PythonCOMServer.h 8.8 KB

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