Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes15kdownloads
PythonCOM.h767 linesDownload Raw Back to include
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 
codekingpro/portable-devtools · Team Ai