163 lines
6.4 KiB
C
163 lines
6.4 KiB
C
|
#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__ */
|