codekingpro/portable-devtools
115k
1/* PythonCOM.h2 3 Main header for Python COM support.4 5 This file is involved mainly with client side COM support for6 Python.7 8 Most COM work put together by Greg Stein and Mark Hammond, with a9 few others starting to come out of the closet.10 11 12 --------------------------------------------------------------------13 Thread State Rules14 ------------------15 These rules apply to PythonCOM in general, and not just to16 the client side.17 18 The rules are quite simple, but it is critical they be followed.19 In general, errors here will be picked up quite quickly, as Python20 will raise a Fatal Error. However, the Release() issue in particular21 may keep a number of problems well hidden.22 23 Interfaces:24 -----------25 Before making ANY call out to COM, you MUST release the Python lock.26 This is true to ANY call whatsoever, including the COM call in question,27 but also any calls to "->Release();"28 29 This is normally achieved with the calls30 PY_INTERFACE_PRECALL and PY_INTERFACE_POSTCALL, which release31 and acquire the Python lock.32 33 Gateways:34 ---------35 Before doing anything related to Python, gateways MUST acquire the36 Python lock, and must release it before returning.37 38 This is normally achieved with PY_GATEWAY_METHOD at the top of a39 gateway method. This macro resolves to a class, which automatically does40 the right thing.41 42 Release:43 --------44 As mentioned above for Interfaces, EVERY call to Release() must be done45 with the Python lock released. This is expanded here.46 47 This is very important, but an error may not be noticed. The problem will48 only be seen when the Release() is on a Python object and the Release() is the49 final one for the object. In this case, the Python object will attempt to50 acquire the Python lock before destroying itself, and Python will raise a51 fatal error.52 53 In many many cases, you will not notice this error, but someday, someone will54 implement the other side in Python, and suddenly FatalErrors will start55 appearing. Make sure you get this right.56 57 Eg, this code is correct:58 PY_INTERFACE_PRECALL;59 pSomeObj->SomeFunction(pSomeOtherObject);60 pSomeOtherObject->Release();61 PY_INTERFACE_POSTCALL;62 63 However, this code is WRONG, but will RARELY FAIL.64 PY_INTERFACE_PRECALL;65 pSomeObj->SomeFunction(pSomeOtherObject);66 PY_INTERFACE_POSTCALL;67 pSomeOtherObject->Release();68--------------------------------------------------------------------69*/70#ifndef __PYTHONCOM_H__71#define __PYTHONCOM_H__72 73// #define _DEBUG_LIFETIMES // Trace COM object lifetimes.74 75#ifdef FREEZE_PYTHONCOM76/* The pythoncom module is being included in a frozen .EXE/.DLL */77#define PYCOM_EXPORT78#else79#ifdef BUILD_PYTHONCOM80/* We are building pythoncomxx.dll */81#define PYCOM_EXPORT __declspec(dllexport)82#else83/* This module uses pythoncomxx.dll */84#define PYCOM_EXPORT __declspec(dllimport)85#ifndef _DEBUG86#pragma comment(lib, "pythoncom.lib")87#else88#pragma comment(lib, "pythoncom_d.lib")89#endif90#endif91#endif92 93#ifdef MS_WINCE94// List of interfaces not supported by CE.95#define NO_PYCOM_IDISPATCHEX96#define NO_PYCOM_IPROVIDECLASSINFO97#define NO_PYCOM_IENUMGUID98#define NO_PYCOM_IENUMCATEGORYINFO99#define NO_PYCOM_ICATINFORMATION100#define NO_PYCOM_ICATREGISTER101#define NO_PYCOM_ISERVICEPROVIDER102#define NO_PYCOM_IPROPERTYSTORAGE103#define NO_PYCOM_IPROPERTYSETSTORAGE104#define NO_PYCOM_ENUMSTATPROPSTG105 106#include "ocidl.h"107#include "oleauto.h"108 109#endif // MS_WINCE110 111#ifdef __MINGW32__112// Special Mingw32 considerations.113#define NO_PYCOM_ENUMSTATPROPSTG114#define __try try115#define __except catch116#include <olectl.h>117 118#endif // __MINGW32__119 120#include <PyWinTypes.h> // Standard Win32 Types121 122#ifndef NO_PYCOM_IDISPATCHEX123#include <dispex.h> // New header for IDispatchEx interface.124#endif // NO_PYCOM_IDISPATCHEX125 126#if defined(MAINWIN)127// Mainwin seems to have 1/2 the VT_RECORD infrastructure in place128#if !defined(VT_RECORD)129#define VT_RECORD 36130#define V_RECORDINFO(X) ((X)->brecVal.pRecInfo)131#define V_RECORD(X) ((X)->brecVal.pvRecord)132#else133#pragma message( \134 "MAINWIN appears to have grown correct VT_RECORD " \135 "support. Please update PythonCOM.h accordingly")136#endif // VT_RECORD137#endif // MAINWIN138 139class PyIUnknown;140// To make life interesting/complicated, I use C++ classes for141// all Python objects. The main advantage is that I can derive142// a PyIDispatch object from a PyIUnknown, etc. This provides a143// clean C++ interface, and "automatically" provides all base144// Python methods to "derived" Python types.145//146// Main disadvantage is that any extension DLLs will need to include147// these headers, and link with this .lib148//149// Base class for (most of) the type objects.150 151class PYCOM_EXPORT PyComTypeObject : public PyTypeObject {152 public:153 PyComTypeObject(const char *name, PyComTypeObject *pBaseType, Py_ssize_t typeSize, struct PyMethodDef *methodList,154 PyIUnknown *(*thector)(IUnknown *));155 ~PyComTypeObject();156 157 // is the given object an interface type object? (e.g. PyIUnknown)158 static BOOL is_interface_type(PyObject *ob);159 160 public:161 PyIUnknown *(*ctor)(IUnknown *);162};163 164// A type used for interfaces that can automatically provide enumerators165// (ie, they themselves aren't enumerable, but do have a suitable default166// method that returns a PyIEnum object167class PYCOM_EXPORT PyComEnumProviderTypeObject : public PyComTypeObject {168 public:169 PyComEnumProviderTypeObject(const char *name, PyComTypeObject *pBaseType, Py_ssize_t typeSize,170 struct PyMethodDef *methodList, PyIUnknown *(*thector)(IUnknown *),171 const char *enum_method_name);172 static PyObject *iter(PyObject *self);173 const char *enum_method_name;174};175 176// A type used for PyIEnum interfaces177class PYCOM_EXPORT PyComEnumTypeObject : public PyComTypeObject {178 public:179 static PyObject *iter(PyObject *self);180 static PyObject *iternext(PyObject *self);181 PyComEnumTypeObject(const char *name, PyComTypeObject *pBaseType, Py_ssize_t typeSize, struct PyMethodDef *methodList,182 PyIUnknown *(*thector)(IUnknown *));183};184 185// Very very base class - not COM specific - Should exist in the186// Python core somewhere, IMO.187class PYCOM_EXPORT PyIBase : public PyObject {188 public:189 // virtuals for Python support190 virtual PyObject *getattr(char *name);191 virtual int setattr(char *name, PyObject *v);192 virtual PyObject *repr();193 virtual int compare(PyObject *other)194 {195 if (this == other)196 return 0;197 if (this < other)198 return -1;199 return 1;200 }201 // These iter are a little special, in that returning NULL means202 // use the implementation in the type203 virtual PyObject *iter() { return NULL; }204 virtual PyObject *iternext() { return NULL; }205 206 protected:207 PyIBase();208 virtual ~PyIBase();209 210 public:211 static BOOL is_object(PyObject *, PyComTypeObject *which);212 BOOL is_object(PyComTypeObject *which);213 static void dealloc(PyObject *ob);214 static PyObject *repr(PyObject *ob);215 static PyObject *getattro(PyObject *self, PyObject *name);216 static int setattro(PyObject *op, PyObject *obname, PyObject *v);217 static int cmp(PyObject *ob1, PyObject *ob2);218 static PyObject *richcmp(PyObject *ob1, PyObject *ob2, int op);219};220 221/* Special Type objects */222extern PYCOM_EXPORT PyTypeObject PyOleEmptyType; // equivalent to VT_EMPTY223extern PYCOM_EXPORT PyTypeObject PyOleMissingType; // special Python handling.224extern PYCOM_EXPORT PyTypeObject PyOleArgNotFoundType; // special VT_ERROR value225extern PYCOM_EXPORT PyTypeObject PyOleNothingType; // special VT_ERROR value226 227// ALL of these set an appropriate Python error on bad return.228 229// Given a Python object that is a registered COM type, return a given230// interface pointer on its underlying object, with a new reference added.231PYCOM_EXPORT BOOL PyCom_InterfaceFromPyObject(PyObject *ob, REFIID iid, LPVOID *ppv, BOOL bNoneOK = TRUE);232 233// As above, but allows instance with "_oleobj_" attribute.234PYCOM_EXPORT BOOL PyCom_InterfaceFromPyInstanceOrObject(PyObject *ob, REFIID iid, LPVOID *ppv, BOOL bNoneOK = TRUE);235 236// Release an arbitary COM pointer.237// NOTE: the PRECALL/POSTCALL stuff is probably not strictly necessary238// since the PyGILSTATE stuff has been in place (and even then, it only239// mattered when it was the last Release() on a Python implemented object)240#define PYCOM_RELEASE(pUnk) \241 { \242 if (pUnk) { \243 PY_INTERFACE_PRECALL; \244 (pUnk)->Release(); \245 PY_INTERFACE_POSTCALL; \246 } \247 }248 249// Given an IUnknown and an Interface ID, create and return an object250// of the appropriate type. eg IID_Unknown->PyIUnknown,251// IID_IDispatch->PyIDispatch, etc.252// Uses a map that external extension DLLs can populate with their IID/type.253// Under the principal of least surprise, this will return Py_None is punk is NULL.254// Otherwise, a valid PyI*, but with NULL m_obj (and therefore totally useless)255// object would be created.256// BOOL bAddRef indicates if a COM reference count should be added to the IUnknown.257// This depends purely on the context in which it is called. If the IUnknown is obtained258// from a function that creates a new ref (eg, CoCreateInstance()) then you should use259// FALSE. If you receive the pointer as (eg) a param to a gateway function, then260// you normally need to pass TRUE, as this is truly a new reference.261// *** ALWAYS take the time to get this right. ***262PYCOM_EXPORT PyObject *PyCom_PyObjectFromIUnknown(IUnknown *punk, REFIID riid, BOOL bAddRef = FALSE);263 264// VARIANT <-> PyObject conversion utilities.265PYCOM_EXPORT BOOL PyCom_VariantFromPyObject(PyObject *obj, VARIANT *var);266PYCOM_EXPORT PyObject *PyCom_PyObjectFromVariant(const VARIANT *var);267 268// PROPVARIANT269PYCOM_EXPORT PyObject *PyObject_FromPROPVARIANT(PROPVARIANT *pVar);270PYCOM_EXPORT PyObject *PyObject_FromPROPVARIANTs(PROPVARIANT *pVars, ULONG cVars);271PYCOM_EXPORT BOOL PyObject_AsPROPVARIANT(PyObject *ob, PROPVARIANT *pVar);272 273// Other conversion helpers...274PYCOM_EXPORT PyObject *PyCom_PyObjectFromSTATSTG(STATSTG *pStat);275PYCOM_EXPORT BOOL PyCom_PyObjectAsSTATSTG(PyObject *ob, STATSTG *pStat, DWORD flags = 0);276PYCOM_EXPORT BOOL PyCom_SAFEARRAYFromPyObject(PyObject *obj, SAFEARRAY **ppSA, VARENUM vt = VT_VARIANT);277PYCOM_EXPORT PyObject *PyCom_PyObjectFromSAFEARRAY(SAFEARRAY *psa, VARENUM vt = VT_VARIANT);278#ifndef NO_PYCOM_STGOPTIONS279PYCOM_EXPORT BOOL PyCom_PyObjectAsSTGOPTIONS(PyObject *obstgoptions, STGOPTIONS **ppstgoptions, TmpWCHAR *tmpw_shelve);280#endif281PYCOM_EXPORT PyObject *PyCom_PyObjectFromSTATPROPSETSTG(STATPROPSETSTG *pStat);282PYCOM_EXPORT BOOL PyCom_PyObjectAsSTATPROPSETSTG(PyObject *, STATPROPSETSTG *);283 284// Currency support.285PYCOM_EXPORT PyObject *PyObject_FromCurrency(CURRENCY &cy);286PYCOM_EXPORT BOOL PyObject_AsCurrency(PyObject *ob, CURRENCY *pcy);287 288// OLEMENUGROUPWIDTHS are used by axcontrol, shell, etc289PYCOM_EXPORT BOOL PyObject_AsOLEMENUGROUPWIDTHS(PyObject *oblpMenuWidths, OLEMENUGROUPWIDTHS *pWidths);290PYCOM_EXPORT PyObject *PyObject_FromOLEMENUGROUPWIDTHS(const OLEMENUGROUPWIDTHS *pWidths);291 292/* Functions for Initializing COM, and also letting the core know about it!293 */294PYCOM_EXPORT HRESULT PyCom_CoInitializeEx(LPVOID reserved, DWORD dwInit);295PYCOM_EXPORT HRESULT PyCom_CoInitialize(LPVOID reserved);296PYCOM_EXPORT void PyCom_CoUninitialize();297 298///////////////////////////////////////////////////////////////////299// Error related functions300 301// Client related functions - generally called by interfaces before302// they return NULL back to Python to indicate the error.303// All these functions return NULL so interfaces can generally304// just "return PyCom_BuildPyException(hr, punk, IID_IWhatever)"305 306// Uses the HRESULT, and IErrorInfo interfaces if available to307// create and set a pythoncom.com_error.308PYCOM_EXPORT PyObject *PyCom_BuildPyException(HRESULT hr, IUnknown *pUnk = NULL, REFIID iid = IID_NULL);309 310// Uses the HRESULT and an EXCEPINFO structure to create and311// set a pythoncom.com_error.312PYCOM_EXPORT PyObject *PyCom_BuildPyExceptionFromEXCEPINFO(HRESULT hr, EXCEPINFO *pexcepInfo, UINT nArgErr = (UINT)-1);313 314// Sets a pythoncom.internal_error - no one should ever see these!315PYCOM_EXPORT PyObject *PyCom_BuildInternalPyException(char *msg);316 317// Log an error to a Python logger object if one can be found, or318// to stderr if no log available.319// If logProvider is not NULL, we will call a "_GetLogger_()" method on it.320// If logProvider is NULL, we attempt to fetch "win32com.logger".321// If they do not exist, return None, or raise an error fetching them322// (or even writing to them once fetched), the message still goes to stderr.323// NOTE: By default, win32com does *not* provide a logger, so default is that324// all errors are written to stdout.325// This will *not* write a record if a COM Server error is current.326PYCOM_EXPORT void PyCom_LoggerNonServerException(PyObject *logProvider, const WCHAR *fmt, ...);327 328// Write an error record, including exception. This will write an error329// record even if a COM server error is current.330PYCOM_EXPORT void PyCom_LoggerException(PyObject *logProvider, const WCHAR *fmt, ...);331 332// Write a warning record - in general this does *not* mean a call failed, but333// still is something in the programmers control that they should change.334// XXX - if an exception is pending when this is called, the traceback will335// also be written. This is undesirable and will be changed should this336// start being a problem.337PYCOM_EXPORT void PyCom_LoggerWarning(PyObject *logProvider, const WCHAR *fmt, ...);338 339// Server related error functions340// These are supplied so that any Python errors we detect can be341// converted into COM error information. The HRESULT returned should342// be returned by the COM function, and these functions also set the343// IErrorInfo interfaces, so the caller can extract more detailed344// information about the Python exception.345 346// Set a COM exception, logging the exception if not an explicitly raised 'server' exception347PYCOM_EXPORT HRESULT PyCom_SetAndLogCOMErrorFromPyException(const char *methodName, REFIID riid /* = IID_NULL */);348PYCOM_EXPORT HRESULT PyCom_SetAndLogCOMErrorFromPyExceptionEx(PyObject *provider, const char *methodName,349 REFIID riid /* = IID_NULL */);350 351// Used in gateways to SetErrorInfo() with a simple HRESULT, then return it.352// The description is generally only useful for debugging purposes,353// and if you are debugging via a server that supports IErrorInfo (like Python :-)354// NOTE: this function is usuable from outside the Python context355PYCOM_EXPORT HRESULT PyCom_SetCOMErrorFromSimple(HRESULT hr, REFIID riid = IID_NULL, const WCHAR *description = NULL);356 357// Used in gateways to check if an IEnum*'s Next() or Clone() method worked.358PYCOM_EXPORT HRESULT PyCom_CheckIEnumNextResult(HRESULT hr, REFIID riid);359 360// Used in gateways when an enumerator expected a sequence but didn't get it.361PYCOM_EXPORT HRESULT PyCom_HandleIEnumNoSequence(REFIID riid);362 363// Used in gateways to SetErrorInfo() the current Python exception, and364// (assuming not a server error explicitly raised) also logs an error365// to stdout/win32com.logger.366// NOTE: this function assumes GIL held367PYCOM_EXPORT HRESULT PyCom_SetCOMErrorFromPyException(REFIID riid = IID_NULL);368 369// A couple of EXCEPINFO helpers - could be private to IDispatch370// if it wasnt for the AXScript support (and ITypeInfo if we get around to that :-)371// These functions do not set any error states to either Python or372// COM - they simply convert to/from PyObjects and EXCEPINFOs373 374// Use the current Python exception to fill an EXCEPINFO structure.375PYCOM_EXPORT void PyCom_ExcepInfoFromPyException(EXCEPINFO *pExcepInfo);376 377// Fill in an EXCEPINFO structure from a Python instance or tuple object.378// (ie, similar to the above, except the Python exception object is specified,379// rather than using the "current"380PYCOM_EXPORT BOOL PyCom_ExcepInfoFromPyObject(PyObject *obExcepInfo, EXCEPINFO *pexcepInfo, HRESULT *phresult = NULL);381 382// Create a Python object holding the exception information. The exception383// information is *not* freed by this function. Python exceptions are384// raised and NULL is returned if an error occurs.385PYCOM_EXPORT PyObject *PyCom_PyObjectFromExcepInfo(const EXCEPINFO *pexcepInfo);386 387///////////////////////////////////////////////////////////////////388//389// External C++ helpers - these helpers are for other DLLs which390// may need similar functionality, but dont want to duplicate all391 392// This helper is for an application that has an IDispatch, and COM arguments393// and wants to call a Python function. It is assumed the caller can map the IDispatch394// to a Python object, so the Python handler is passed.395// Args:396// handler : A Python callable object.397// dispparms : the COM arguments.398// pVarResult : The variant for the return value of the Python call.399// pexcepinfo : Exception info the helper may fill out.400// puArgErr : Argument error the helper may fill out on exception401// addnArgs : Any additional arguments to the Python function. May be NULL.402// If addnArgs is NULL, then it is assumed the Python call should be native -403// ie, the COM args are packed as normal Python args to the call.404// If addnArgs is NOT NULL, it is assumed the Python function itself is405// a helper. This Python function will be called with 2 arguments - both406// tuples - first one is the COM args, second is the addn args.407PYCOM_EXPORT BOOL PyCom_MakeOlePythonCall(PyObject *handler, DISPPARAMS FAR *params, VARIANT FAR *pVarResult,408 EXCEPINFO FAR *pexcepinfo, UINT FAR *puArgErr, PyObject *addnlArgs);409 410/////////////////////////////////////////////////////////////////////////////411// Various special purpose singletons412class PYCOM_EXPORT PyOleEmpty : public PyObject {413 public:414 PyOleEmpty();415};416 417class PYCOM_EXPORT PyOleMissing : public PyObject {418 public:419 PyOleMissing();420};421 422class PYCOM_EXPORT PyOleArgNotFound : public PyObject {423 public:424 PyOleArgNotFound();425};426 427class PYCOM_EXPORT PyOleNothing : public PyObject {428 public:429 PyOleNothing();430};431 432// We need to dynamically create C++ Python objects433// These helpers allow each type object to create it.434#define MAKE_PYCOM_CTOR(classname) \435 static PyIUnknown *PyObConstruct(IUnknown *pInitObj) { return new classname(pInitObj); }436#define MAKE_PYCOM_CTOR_ERRORINFO(classname, iid) \437 static PyIUnknown *PyObConstruct(IUnknown *pInitObj) { return new classname(pInitObj); } \438 static PyObject *SetPythonCOMError(PyObject *self, HRESULT hr) \439 { \440 return PyCom_BuildPyException(hr, GetI(self), iid); \441 }442#define GET_PYCOM_CTOR(classname) classname::PyObConstruct443 444// Macros that interfaces should use. PY_INTERFACE_METHOD at the top of the method445// The other 2 wrap directly around the underlying method call.446#define PY_INTERFACE_METHOD447// Identical to Py_BEGIN_ALLOW_THREADS except no { !!!448#define PY_INTERFACE_PRECALL PyThreadState *_save = PyEval_SaveThread();449#define PY_INTERFACE_POSTCALL PyEval_RestoreThread(_save);450 451/////////////////////////////////////////////////////////////////////////////452// class PyIUnknown453class PYCOM_EXPORT PyIUnknown : public PyIBase {454 public:455 MAKE_PYCOM_CTOR(PyIUnknown);456 virtual PyObject *repr();457 virtual int compare(PyObject *other);458 459 static IUnknown *GetI(PyObject *self);460 IUnknown *m_obj;461 static char *szErrMsgObjectReleased;462 static void SafeRelease(PyIUnknown *ob);463 static PyComTypeObject type;464 465 // The Python methods466 static PyObject *QueryInterface(PyObject *self, PyObject *args);467 static PyObject *SafeRelease(PyObject *self, PyObject *args);468 469 protected:470 PyIUnknown(IUnknown *punk);471 ~PyIUnknown();472};473 474/////////////////////////////////////////////////////////////////////////////475// class PyIDispatch476 477class PYCOM_EXPORT PyIDispatch : public PyIUnknown {478 public:479 MAKE_PYCOM_CTOR(PyIDispatch);480 static IDispatch *GetI(PyObject *self);481 static PyComTypeObject type;482 483 // The Python methods484 static PyObject *Invoke(PyObject *self, PyObject *args);485 static PyObject *InvokeTypes(PyObject *self, PyObject *args);486 static PyObject *GetIDsOfNames(PyObject *self, PyObject *args);487 static PyObject *GetTypeInfo(PyObject *self, PyObject *args);488 static PyObject *GetTypeInfoCount(PyObject *self, PyObject *args);489 490 protected:491 PyIDispatch(IUnknown *pdisp);492 ~PyIDispatch();493};494 495#ifndef NO_PYCOM_IDISPATCHEX496/////////////////////////////////////////////////////////////////////////////497// class PyIDispatchEx498 499class PYCOM_EXPORT PyIDispatchEx : public PyIDispatch {500 public:501 MAKE_PYCOM_CTOR_ERRORINFO(PyIDispatchEx, IID_IDispatchEx);502 static IDispatchEx *GetI(PyObject *self);503 static PyComTypeObject type;504 505 // The Python methods506 static PyObject *GetDispID(PyObject *self, PyObject *args);507 static PyObject *InvokeEx(PyObject *self, PyObject *args);508 static PyObject *DeleteMemberByName(PyObject *self, PyObject *args);509 static PyObject *DeleteMemberByDispID(PyObject *self, PyObject *args);510 static PyObject *GetMemberProperties(PyObject *self, PyObject *args);511 static PyObject *GetMemberName(PyObject *self, PyObject *args);512 static PyObject *GetNextDispID(PyObject *self, PyObject *args);513 514 protected:515 PyIDispatchEx(IUnknown *pdisp);516 ~PyIDispatchEx();517};518#endif // NO_PYCOM_IDISPATCHEX519 520/////////////////////////////////////////////////////////////////////////////521// class PyIClassFactory522 523class PYCOM_EXPORT PyIClassFactory : public PyIUnknown {524 public:525 MAKE_PYCOM_CTOR(PyIClassFactory);526 static IClassFactory *GetI(PyObject *self);527 static PyComTypeObject type;528 529 // The Python methods530 static PyObject *CreateInstance(PyObject *self, PyObject *args);531 static PyObject *LockServer(PyObject *self, PyObject *args);532 533 protected:534 PyIClassFactory(IUnknown *pdisp);535 ~PyIClassFactory();536};537 538#ifndef NO_PYCOM_IPROVIDECLASSINFO539 540/////////////////////////////////////////////////////////////////////////////541// class PyIProvideTypeInfo542 543class PYCOM_EXPORT PyIProvideClassInfo : public PyIUnknown {544 public:545 MAKE_PYCOM_CTOR(PyIProvideClassInfo);546 static IProvideClassInfo *GetI(PyObject *self);547 static PyComTypeObject type;548 549 // The Python methods550 static PyObject *GetClassInfo(PyObject *self, PyObject *args);551 552 protected:553 PyIProvideClassInfo(IUnknown *pdisp);554 ~PyIProvideClassInfo();555};556 557class PYCOM_EXPORT PyIProvideClassInfo2 : public PyIProvideClassInfo {558 public:559 MAKE_PYCOM_CTOR(PyIProvideClassInfo2);560 static IProvideClassInfo2 *GetI(PyObject *self);561 static PyComTypeObject type;562 563 // The Python methods564 static PyObject *GetGUID(PyObject *self, PyObject *args);565 566 protected:567 PyIProvideClassInfo2(IUnknown *pdisp);568 ~PyIProvideClassInfo2();569};570#endif // NO_PYCOM_IPROVIDECLASSINFO571 572/////////////////////////////////////////////////////////////////////////////573// class PyITypeInfo574class PYCOM_EXPORT PyITypeInfo : public PyIUnknown {575 public:576 MAKE_PYCOM_CTOR(PyITypeInfo);577 static PyComTypeObject type;578 static ITypeInfo *GetI(PyObject *self);579 580 PyObject *GetContainingTypeLib();581 PyObject *GetDocumentation(MEMBERID);582 PyObject *GetRefTypeInfo(HREFTYPE href);583 PyObject *GetRefTypeOfImplType(int index);584 PyObject *GetFuncDesc(int pos);585 PyObject *GetIDsOfNames(OLECHAR FAR *FAR *, int);586 PyObject *GetNames(MEMBERID);587 PyObject *GetTypeAttr();588 PyObject *GetVarDesc(int pos);589 PyObject *GetImplTypeFlags(int index);590 PyObject *GetTypeComp();591 592 protected:593 PyITypeInfo(IUnknown *);594 ~PyITypeInfo();595};596 597/////////////////////////////////////////////////////////////////////////////598// class PyITypeComp599class PYCOM_EXPORT PyITypeComp : public PyIUnknown {600 public:601 MAKE_PYCOM_CTOR(PyITypeComp);602 static PyComTypeObject type;603 static ITypeComp *GetI(PyObject *self);604 605 PyObject *Bind(OLECHAR *szName, unsigned short wflags);606 PyObject *BindType(OLECHAR *szName);607 608 protected:609 PyITypeComp(IUnknown *);610 ~PyITypeComp();611};612 613/////////////////////////////////////////////////////////////////////////////614// class CPyTypeLib615 616class PYCOM_EXPORT PyITypeLib : public PyIUnknown {617 public:618 MAKE_PYCOM_CTOR(PyITypeLib);619 static PyComTypeObject type;620 static ITypeLib *GetI(PyObject *self);621 622 PyObject *GetLibAttr();623 PyObject *GetDocumentation(int pos);624 PyObject *GetTypeInfo(int pos);625 PyObject *GetTypeInfoCount();626 PyObject *GetTypeInfoOfGuid(REFGUID guid);627 PyObject *GetTypeInfoType(int pos);628 PyObject *GetTypeComp();629 630 protected:631 PyITypeLib(IUnknown *);632 ~PyITypeLib();633};634 635/////////////////////////////////////////////////////////////////////////////636// class PyIConnectionPoint637 638class PYCOM_EXPORT PyIConnectionPoint : public PyIUnknown {639 public:640 MAKE_PYCOM_CTOR_ERRORINFO(PyIConnectionPoint, IID_IConnectionPoint);641 static PyComTypeObject type;642 static IConnectionPoint *GetI(PyObject *self);643 644 static PyObject *GetConnectionInterface(PyObject *self, PyObject *args);645 static PyObject *GetConnectionPointContainer(PyObject *self, PyObject *args);646 static PyObject *Advise(PyObject *self, PyObject *args);647 static PyObject *Unadvise(PyObject *self, PyObject *args);648 static PyObject *EnumConnections(PyObject *self, PyObject *args);649 650 protected:651 PyIConnectionPoint(IUnknown *);652 ~PyIConnectionPoint();653};654 655class PYCOM_EXPORT PyIConnectionPointContainer : public PyIUnknown {656 public:657 MAKE_PYCOM_CTOR_ERRORINFO(PyIConnectionPointContainer, IID_IConnectionPointContainer);658 static PyComTypeObject type;659 static IConnectionPointContainer *GetI(PyObject *self);660 661 static PyObject *EnumConnectionPoints(PyObject *self, PyObject *args);662 static PyObject *FindConnectionPoint(PyObject *self, PyObject *args);663 664 protected:665 PyIConnectionPointContainer(IUnknown *);666 ~PyIConnectionPointContainer();667};668 669/////////////////////////////////////////////////////////////////////////////670// class PythonOleArgHelper671//672// A PythonOleArgHelper is used primarily to help out Python helpers673// which need to convert from a Python object when the specific OLE674// type is known - eg, when a TypeInfo is available.675//676// The type of conversion determines who owns what buffers etc. I wish BYREF didnt exist :-)677typedef enum {678 // We dont know what sort of conversion it is yet.679 POAH_CONVERT_UNKNOWN,680 // A PyObject is given, we convert to a VARIANT, make the COM call, then BYREFs back to a PyObject681 // ie, this is typically a "normal" COM call, where Python initiates the call682 POAH_CONVERT_FROM_PYOBJECT,683 // A VARIANT is given, we convert to a PyObject, make the Python call, then BYREFs back to a VARIANT.684 // ie, this is typically handling a COM event, where COM itself initiates the call.685 POAH_CONVERT_FROM_VARIANT,686} POAH_CONVERT_DIRECTION;687 688class PYCOM_EXPORT PythonOleArgHelper {689 public:690 PythonOleArgHelper();691 ~PythonOleArgHelper();692 BOOL ParseTypeInformation(PyObject *reqdObjectTuple);693 694 // Using this call with reqdObject != NULL will check the existing695 // VT_ of the variant. If not VT_EMPTY, then the result will be coerced to696 // that type. This contrasts with PyCom_PyObjectToVariant which just697 // uses the Python type to determine the variant type.698 BOOL MakeObjToVariant(PyObject *obj, VARIANT *var, PyObject *reqdObjectTuple = NULL);699 PyObject *MakeVariantToObj(VARIANT *var);700 701 VARTYPE m_reqdType;702 BOOL m_bParsedTypeInfo;703 BOOL m_bIsOut;704 POAH_CONVERT_DIRECTION m_convertDirection;705 PyObject *m_pyVariant; // if non-null, a win32com.client.VARIANT706 union {707 void *m_pValueHolder;708 short m_sBuf;709 long m_lBuf;710 LONGLONG m_llBuf;711 VARIANT_BOOL m_boolBuf;712 double m_dBuf;713 float m_fBuf;714 IDispatch *m_dispBuf;715 IUnknown *m_unkBuf;716 SAFEARRAY *m_arrayBuf;717 VARIANT *m_varBuf;718 DATE m_dateBuf;719 CY m_cyBuf;720 };721};722 723/////////////////////////////////////////////////////////////////////////////724// global functions and variables725PYCOM_EXPORT BOOL MakePythonArgumentTuples(PyObject **pArgs, PythonOleArgHelper **ppHelpers, PyObject **pNamedArgs,726 PythonOleArgHelper **ppNamedHelpers, DISPPARAMS FAR *params);727 728// Convert a Python object to a BSTR - allow embedded NULLs, None, etc.729PYCOM_EXPORT BOOL PyCom_BstrFromPyObject(PyObject *stringObject, BSTR *pResult, BOOL bNoneOK = FALSE);730 731// MakeBstrToObj - convert a BSTR into a Python string.732//733// ONLY USE THIS FOR TRUE BSTR's - Use the fn below for OLECHAR *'s.734// NOTE - does not use standard macros, so NULLs get through!735PYCOM_EXPORT PyObject *MakeBstrToObj(const BSTR bstr);736 737// Size info is available (eg, a fn returns a string and also fills in a size variable)738PYCOM_EXPORT PyObject *MakeOLECHARToObj(const OLECHAR *str, int numChars);739 740// No size info avail.741PYCOM_EXPORT PyObject *MakeOLECHARToObj(const OLECHAR *str);742 743PYCOM_EXPORT void PyCom_LogF(const WCHAR *fmt, ...);744 745// Generic conversion from python sequence to VT_VECTOR array746// Resulting array must be freed with CoTaskMemFree747template <typename arraytype>748BOOL SeqToVector(PyObject *ob, arraytype **pA, ULONG *pcount, BOOL (*converter)(PyObject *, arraytype *))749{750 TmpPyObject seq = PyWinSequence_Tuple(ob, pcount);751 if (seq == NULL)752 return FALSE;753 *pA = (arraytype *)CoTaskMemAlloc(*pcount * sizeof(arraytype));754 if (*pA == NULL) {755 PyErr_NoMemory();756 return FALSE;757 }758 for (ULONG i = 0; i < *pcount; i++) {759 PyObject *item = PyTuple_GET_ITEM((PyObject *)seq, i);760 if (!(*converter)(item, &(*pA)[i]))761 return FALSE;762 }763 return TRUE;764}765 766#endif // __PYTHONCOM_H__767 