#ifndef __PYTHONCOMSERVER_H__ #define __PYTHONCOMSERVER_H__ // PythonCOMServer.h :Server side COM support #include #define DLLAcquireGlobalLock PyWin_AcquireGlobalLock #define DLLReleaseGlobalLock PyWin_ReleaseGlobalLock void PYCOM_EXPORT PyCom_DLLAddRef(void); void PYCOM_EXPORT PyCom_DLLReleaseRef(void); // Use this macro at the start of all gateway methods. #define PY_GATEWAY_METHOD CEnterLeavePython _celp class PyGatewayBase; // Gateway constructors. // Each gateway must be able to be created from a "gateway constructor". This // is simply a function that takes a Python instance as as argument, and returns // a gateway object of the correct type. The MAKE_PYGATEWAY_CTOR is a helper that // will embed such a constructor in the class - however, this is not necessary - // _any_ function of the correct signature can be used. typedef HRESULT (* pfnPyGatewayConstructor)(PyObject *PythonInstance, PyGatewayBase *, void **ppResult, REFIID iid); HRESULT PyCom_MakeRegisteredGatewayObject(REFIID iid, PyObject *instance, PyGatewayBase *base, void **ppv); // A version of the above which support classes being derived from // other than IUnknown #define PYGATEWAY_MAKE_SUPPORT2(classname, IInterface, theIID, gatewaybaseclass) \ public: \ static HRESULT classname::PyGatewayConstruct(PyObject *pPyInstance, PyGatewayBase *unkBase, void **ppResult, REFIID iid) { \ if (ppResult==NULL) return E_INVALIDARG; \ classname *newob = new classname(pPyInstance); \ newob->m_pBaseObject = unkBase; \ if (unkBase) unkBase->AddRef(); \ *ppResult = newob->ThisAsIID(iid); \ return *ppResult ? S_OK : E_OUTOFMEMORY; } \ protected: \ virtual IID GetIID(void) { return theIID; } \ virtual void *ThisAsIID(IID iid) {if (this==NULL) return NULL;if (iid==theIID) return (IInterface *)this; else return gatewaybaseclass::ThisAsIID(iid);} \ STDMETHOD_(ULONG,AddRef)(void) {return gatewaybaseclass::AddRef();} \ STDMETHOD_(ULONG,Release)(void) {return gatewaybaseclass::Release();} \ STDMETHOD(QueryInterface)(REFIID iid, void ** obj) {return gatewaybaseclass::QueryInterface(iid, obj);}; // This is the "old" version to use, or use it if you derive // directly from PyGatewayBase #define PYGATEWAY_MAKE_SUPPORT(classname, IInterface, theIID) \ PYGATEWAY_MAKE_SUPPORT2(classname, IInterface, theIID, PyGatewayBase) #define GET_PYGATEWAY_CTOR(classname) classname::PyGatewayConstruct #ifdef _MSC_VER // Disable an OK warning... #pragma warning( disable : 4275 ) // warning C4275: non dll-interface struct 'IDispatch' used as base for dll-interface class 'PyGatewayBase' #endif // _MSC_VER // Helper interface for fetching a Python object from a gateway extern const GUID IID_IInternalUnwrapPythonObject; interface IInternalUnwrapPythonObject : public IUnknown { public: STDMETHOD(Unwrap)( PyObject **ppPyObject ) = 0; }; ///////////////////////////////////////////////////////////////////////////// // PyGatewayBase // // Base class for all gateways. // class PYCOM_EXPORT PyGatewayBase : #ifndef NO_PYCOM_IDISPATCHEX public IDispatchEx, // IDispatch comes along for the ride! #else public IDispatch, // No IDispatchEx - must explicitely use IDispatch #endif public ISupportErrorInfo, public IInternalUnwrapPythonObject { protected: PyGatewayBase(PyObject *instance); virtual ~PyGatewayBase(); // Invoke the Python method (via the policy object) STDMETHOD(InvokeViaPolicy)( const char *szMethodName, PyObject **ppResult = NULL, const char *szFormat = NULL, ...); public: // IUnknown STDMETHOD_(ULONG,AddRef)(void); STDMETHOD_(ULONG,Release)(void); STDMETHOD(QueryInterface)(REFIID iid, void ** obj); // IDispatch STDMETHOD(GetTypeInfoCount)(UINT FAR* pctInfo); STDMETHOD(GetTypeInfo)(UINT itinfo, LCID lcid, ITypeInfo FAR* FAR* pptInfo); STDMETHOD(GetIDsOfNames)(REFIID refiid, OLECHAR FAR* FAR* rgszNames, UINT cNames, LCID lcid, DISPID FAR* rgdispid); STDMETHOD(Invoke)(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR* params, VARIANT FAR* pVarResult, EXCEPINFO FAR* pexcepinfo, UINT FAR* puArgErr); // IDispatchEx #ifndef NO_PYCOM_IDISPATCHEX STDMETHOD(GetDispID)(BSTR bstrName, DWORD grfdex, DISPID *pid); STDMETHOD(InvokeEx)(DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller); STDMETHOD(DeleteMemberByName)(BSTR bstr, DWORD grfdex); STDMETHOD(DeleteMemberByDispID)(DISPID id); STDMETHOD(GetMemberProperties)(DISPID id, DWORD grfdexFetch, DWORD *pgrfdex); STDMETHOD(GetMemberName)(DISPID id, BSTR *pbstrName); STDMETHOD(GetNextDispID)(DWORD grfdex, DISPID id, DISPID *pid); STDMETHOD(GetNameSpaceParent)(IUnknown **ppunk); #endif // NO_PYCOM_IDISPATCHEX // ISupportErrorInfo STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid); // IInternalUnwrapPythonObject STDMETHOD(Unwrap)(PyObject **ppPyObject); // Basically just PYGATEWAY_MAKE_SUPPORT(PyGatewayBase, IDispatch, IID_IDispatch); // but with special handling as its the base class. static HRESULT PyGatewayBase::PyGatewayConstruct(PyObject *pPyInstance, PyGatewayBase *gatewayBase, void **ppResult, REFIID iid) { if (ppResult==NULL) return E_INVALIDARG; PyGatewayBase *obNew = new PyGatewayBase(pPyInstance); obNew->m_pBaseObject = gatewayBase; if (gatewayBase) gatewayBase->AddRef(); *ppResult = (IDispatch *)obNew; return *ppResult ? S_OK : E_OUTOFMEMORY; } // Currently this is used only for ISupportErrorInfo, // so hopefully this will never be called in this base class. // (however, this is not a rule, so we wont assert or anything!) virtual IID GetIID(void) { return IID_IUnknown; } virtual void *ThisAsIID(IID iid); // End of PYGATEWAY_MAKE_SUPPORT PyObject * m_pPyObject; PyGatewayBase *m_pBaseObject; private: LONG m_cRef; }; #ifdef _MSC_VER #pragma warning(default : 4275 ) #endif // _MSC_VER // B/W compat hack for gateways. #define PyCom_HandlePythonFailureToCOM() \ PyCom_SetAndLogCOMErrorFromPyExceptionEx(this->m_pPyObject, "", GetIID()) // F/W compat hack for gateways! Must be careful about updating // PyGatewayBase vtable, so a slightly older pythoncomXX.dll will work // with slightly later extensions. So use a #define. #define MAKE_PYCOM_GATEWAY_FAILURE_CODE(method_name) \ PyCom_SetAndLogCOMErrorFromPyExceptionEx(this->m_pPyObject, method_name, GetIID()) #endif /* __PYTHONCOMSERVER_H__ */