PythonCOMServer.h
1 #ifndef __PYTHONCOMSERVER_H__ 2 #define __PYTHONCOMSERVER_H__ 3 4 // PythonCOMServer.h :Server side COM support 5 6 #include <Python.h> 7 8 #define DLLAcquireGlobalLock PyWin_AcquireGlobalLock 9 #define DLLReleaseGlobalLock PyWin_ReleaseGlobalLock 10 11 void PYCOM_EXPORT PyCom_DLLAddRef(void); 12 void PYCOM_EXPORT PyCom_DLLReleaseRef(void); 13 14 // Use this macro at the start of all gateway methods. 15 #define PY_GATEWAY_METHOD CEnterLeavePython _celp 16 17 class PyGatewayBase; 18 // Gateway constructors. 19 // Each gateway must be able to be created from a "gateway constructor". This 20 // is simply a function that takes a Python instance as as argument, and returns 21 // a gateway object of the correct type. The MAKE_PYGATEWAY_CTOR is a helper that 22 // will embed such a constructor in the class - however, this is not necessary - 23 // _any_ function of the correct signature can be used. 24 25 typedef HRESULT (*pfnPyGatewayConstructor)(PyObject *PythonInstance, PyGatewayBase *, void **ppResult, REFIID iid); 26 HRESULT PyCom_MakeRegisteredGatewayObject(REFIID iid, PyObject *instance, PyGatewayBase *base, void **ppv); 27 28 // A version of the above which support classes being derived from 29 // other than IUnknown 30 #define PYGATEWAY_MAKE_SUPPORT2(classname, IInterface, theIID, gatewaybaseclass) \ 31 public: \ 32 static HRESULT classname::PyGatewayConstruct(PyObject *pPyInstance, PyGatewayBase *unkBase, void **ppResult, \ 33 REFIID iid) \ 34 { \ 35 if (ppResult == NULL) \ 36 return E_INVALIDARG; \ 37 classname *newob = new classname(pPyInstance); \ 38 newob->m_pBaseObject = unkBase; \ 39 if (unkBase) \ 40 unkBase->AddRef(); \ 41 *ppResult = newob->ThisAsIID(iid); \ 42 return *ppResult ? S_OK : E_OUTOFMEMORY; \ 43 } \ 44 \ 45 protected: \ 46 virtual IID GetIID(void) { return theIID; } \ 47 virtual void *ThisAsIID(IID iid) \ 48 { \ 49 if (this == NULL) \ 50 return NULL; \ 51 if (iid == theIID) \ 52 return (IInterface *)this; \ 53 else \ 54 return gatewaybaseclass::ThisAsIID(iid); \ 55 } \ 56 STDMETHOD_(ULONG, AddRef)(void) { return gatewaybaseclass::AddRef(); } \ 57 STDMETHOD_(ULONG, Release)(void) { return gatewaybaseclass::Release(); } \ 58 STDMETHOD(QueryInterface)(REFIID iid, void **obj) { return gatewaybaseclass::QueryInterface(iid, obj); }; 59 60 // This is the "old" version to use, or use it if you derive 61 // directly from PyGatewayBase 62 #define PYGATEWAY_MAKE_SUPPORT(classname, IInterface, theIID) \ 63 PYGATEWAY_MAKE_SUPPORT2(classname, IInterface, theIID, PyGatewayBase) 64 65 #define GET_PYGATEWAY_CTOR(classname) classname::PyGatewayConstruct 66 67 #ifdef _MSC_VER 68 // Disable an OK warning... 69 #pragma warning(disable : 4275) 70 // warning C4275: non dll-interface struct 'IDispatch' used as base for dll-interface class 'PyGatewayBase' 71 #endif // _MSC_VER 72 73 // Helper interface for fetching a Python object from a gateway 74 75 extern const GUID IID_IInternalUnwrapPythonObject; 76 77 interface IInternalUnwrapPythonObject : public IUnknown 78 { 79 public: 80 STDMETHOD(Unwrap)(PyObject * *ppPyObject) = 0; 81 }; 82 83 ///////////////////////////////////////////////////////////////////////////// 84 // PyGatewayBase 85 // 86 // Base class for all gateways. 87 // 88 class PYCOM_EXPORT PyGatewayBase : 89 #ifndef NO_PYCOM_IDISPATCHEX 90 public IDispatchEx, // IDispatch comes along for the ride! 91 #else 92 public IDispatch, // No IDispatchEx - must explicitely use IDispatch 93 #endif 94 public ISupportErrorInfo, 95 public IInternalUnwrapPythonObject { 96 protected: 97 PyGatewayBase(PyObject *instance); 98 virtual ~PyGatewayBase(); 99 100 // Invoke the Python method (via the policy object) 101 STDMETHOD(InvokeViaPolicy)(const char *szMethodName, PyObject **ppResult = NULL, const char *szFormat = NULL, ...); 102 103 public: 104 // IUnknown 105 STDMETHOD_(ULONG, AddRef)(void); 106 STDMETHOD_(ULONG, Release)(void); 107 STDMETHOD(QueryInterface)(REFIID iid, void **obj); 108 109 // IDispatch 110 STDMETHOD(GetTypeInfoCount)(UINT FAR *pctInfo); 111 STDMETHOD(GetTypeInfo)(UINT itinfo, LCID lcid, ITypeInfo FAR *FAR *pptInfo); 112 STDMETHOD(GetIDsOfNames)(REFIID refiid, OLECHAR FAR *FAR *rgszNames, UINT cNames, LCID lcid, DISPID FAR *rgdispid); 113 STDMETHOD(Invoke) 114 (DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *params, VARIANT FAR *pVarResult, 115 EXCEPINFO FAR *pexcepinfo, UINT FAR *puArgErr); 116 117 // IDispatchEx 118 #ifndef NO_PYCOM_IDISPATCHEX 119 STDMETHOD(GetDispID)(BSTR bstrName, DWORD grfdex, DISPID *pid); 120 STDMETHOD(InvokeEx) 121 (DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller); 122 STDMETHOD(DeleteMemberByName)(BSTR bstr, DWORD grfdex); 123 STDMETHOD(DeleteMemberByDispID)(DISPID id); 124 STDMETHOD(GetMemberProperties)(DISPID id, DWORD grfdexFetch, DWORD *pgrfdex); 125 STDMETHOD(GetMemberName)(DISPID id, BSTR *pbstrName); 126 STDMETHOD(GetNextDispID)(DWORD grfdex, DISPID id, DISPID *pid); 127 STDMETHOD(GetNameSpaceParent)(IUnknown **ppunk); 128 #endif // NO_PYCOM_IDISPATCHEX 129 // ISupportErrorInfo 130 STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid); 131 132 // IInternalUnwrapPythonObject 133 STDMETHOD(Unwrap)(PyObject **ppPyObject); 134 135 // Basically just PYGATEWAY_MAKE_SUPPORT(PyGatewayBase, IDispatch, IID_IDispatch); 136 // but with special handling as its the base class. 137 static HRESULT PyGatewayBase::PyGatewayConstruct(PyObject *pPyInstance, PyGatewayBase *gatewayBase, void **ppResult, 138 REFIID iid) 139 { 140 if (ppResult == NULL) 141 return E_INVALIDARG; 142 PyGatewayBase *obNew = new PyGatewayBase(pPyInstance); 143 obNew->m_pBaseObject = gatewayBase; 144 if (gatewayBase) 145 gatewayBase->AddRef(); 146 *ppResult = (IDispatch *)obNew; 147 return *ppResult ? S_OK : E_OUTOFMEMORY; 148 } 149 // Currently this is used only for ISupportErrorInfo, 150 // so hopefully this will never be called in this base class. 151 // (however, this is not a rule, so we wont assert or anything!) 152 virtual IID GetIID(void) { return IID_IUnknown; } 153 virtual void *ThisAsIID(IID iid); 154 // End of PYGATEWAY_MAKE_SUPPORT 155 PyObject *m_pPyObject; 156 PyGatewayBase *m_pBaseObject; 157 158 private: 159 LONG m_cRef; 160 }; 161 162 #ifdef _MSC_VER 163 #pragma warning(default : 4275) 164 #endif // _MSC_VER 165 166 // B/W compat hack for gateways. 167 #define PyCom_HandlePythonFailureToCOM() \ 168 PyCom_SetAndLogCOMErrorFromPyExceptionEx(this->m_pPyObject, "<unknown>", GetIID()) 169 170 // F/W compat hack for gateways! Must be careful about updating 171 // PyGatewayBase vtable, so a slightly older pythoncomXX.dll will work 172 // with slightly later extensions. So use a #define. 173 #define MAKE_PYCOM_GATEWAY_FAILURE_CODE(method_name) \ 174 PyCom_SetAndLogCOMErrorFromPyExceptionEx(this->m_pPyObject, method_name, GetIID()) 175 176 #endif /* __PYTHONCOMSERVER_H__ */