PythonCOMServer.h
6.25 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
#ifndef __PYTHONCOMSERVER_H__
#define __PYTHONCOMSERVER_H__
// PythonCOMServer.h :Server side COM support
#include <Python.h>
#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, "<unknown>", 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__ */