PyVARDESC::PyVARDESC(const VARDESC *pVD) { ob_type = &PyVARDESC::Type; _Py_NewReference(this); memid = pVD->memid; wVarFlags = pVD->wVarFlags; varkind = pVD->varkind; if (varkind == VAR_PERINSTANCE) value = PyInt_FromLong(pVD->oInst); else if (varkind == VAR_CONST) { VARIANT varValue; // Cast the variant type here to the correct value for this constant // so that the correct Python type will be created below. // The problem seems to exist for unsigned types (the variant has // a signed type, but the typelib has an unsigned one). However, // doing this unconditionally has side-effects, as the typelib // has VT_LPWSTR for the type of strings - and VariantChangeType // returns a VT_EMPTY variant in that case. // So we only perform this conversion for types known to be a problem: switch (pVD->elemdescVar.tdesc.vt) { case VT_UI1: case VT_UI2: case VT_UI4: case VT_UI8: case VT_UINT: case VT_UINT_PTR: VariantInit(&varValue); VariantChangeType(&varValue, pVD->lpvarValue, 0, pVD->elemdescVar.tdesc.vt); value = PyCom_PyObjectFromVariant(&varValue); VariantClear(&varValue); break; default: value = PyCom_PyObjectFromVariant(pVD->lpvarValue); break; } } else if (varkind == VAR_DISPATCH) { // all caller needs is memid, which is already setup. value = Py_None; Py_INCREF(Py_None); } else { PyCom_LoggerWarning(NULL, "PyVARDESC ctor has unknown varkind (%d) - returning None", varkind); value = Py_None; Py_INCREF(Py_None); } elemdescVar = PyObject_FromELEMDESC(&pVD->elemdescVar); }
// @pymethod object|PyIADs|Get|Description of Get. // @rdesc The result is a Python object converted from a COM variant. It // may be an array, or any types supported by COM variant. PyObject *PyIADs::Get(PyObject *self, PyObject *args) { IADs *pIAD = GetI(self); if ( pIAD == NULL ) return NULL; VARIANT val; VariantInit(&val); // @pyparm <o PyUnicode>|prop||The name of the property to fetch PyObject *obbstrName; BSTR bstrName; if ( !PyArg_ParseTuple(args, "O:Get", &obbstrName) ) return NULL; BOOL bPythonIsHappy = TRUE; if (bPythonIsHappy && !PyWinObject_AsBstr(obbstrName, &bstrName)) bPythonIsHappy = FALSE; if (!bPythonIsHappy) return NULL; HRESULT hr; PY_INTERFACE_PRECALL; hr = pIAD->Get( bstrName, &val ); SysFreeString(bstrName); PY_INTERFACE_POSTCALL; if ( FAILED(hr) ) return PyCom_BuildPyException(hr, pIAD, IID_IADs ); PyObject *ret = PyCom_PyObjectFromVariant(&val); { PY_INTERFACE_PRECALL; VariantClear(&val); PY_INTERFACE_POSTCALL; } return ret; }
// DS_SELECTION_LIST helpers PyObject *PyStringAsDS_SELECTION_LIST(PyObject *self, PyObject *args) { char *sz; unsigned int cb; if (!PyArg_ParseTuple(args, "s#:PyStringAsDS_SELECTION_LIST", &sz, &cb)) return NULL; if (cb < sizeof(DS_SELECTION_LIST)) return PyErr_Format(PyExc_ValueError, "String must be at least %d bytes (got %d)", sizeof(DS_SELECTION_LIST), cb); DS_SELECTION_LIST *pSL = (DS_SELECTION_LIST *)sz; PyObject *ret = PyList_New(pSL->cItems); if (!ret) return NULL; for (unsigned int i=0;i<pSL->cItems;i++) { // get attrs for this item DS_SELECTION *pItem = pSL->aDsSelection+i; PyObject *obAttr; if (pItem->pvarFetchedAttributes) { obAttr = PyList_New(pSL->cFetchedAttributes); if (!obAttr) { Py_DECREF(ret); return NULL; } for (unsigned int ia=0;ia<pSL->cFetchedAttributes;ia++) PyList_SET_ITEM(obAttr, ia, PyCom_PyObjectFromVariant(pItem->pvarFetchedAttributes+ia)); } else { obAttr = Py_None; Py_INCREF(Py_None); } PyObject *sub = Py_BuildValue("NNNNNl", PyWinObject_FromWCHAR(pItem->pwzName), PyWinObject_FromWCHAR(pItem->pwzADsPath), PyWinObject_FromWCHAR(pItem->pwzClass), PyWinObject_FromWCHAR(pItem->pwzUPN), obAttr, pItem->flScopeType); if (!sub) { Py_DECREF(ret); return NULL; } PyList_SET_ITEM(ret, i, sub); } return ret; }
// @object ELEMDESC|An ELEMDESC is respresented as a tuple of PyObject *PyObject_FromELEMDESC(const ELEMDESC *ed) { // @tupleitem 0|<o TYPEDESC>|typeDesc|The type description. // @tupleitem 1|int|idlFlags| // @tupleitem 2|object|default|If PARAMFLAG_FHASDEFAULT are set, then this is the default value. PyObject *defaultValue = NULL; if (ed->idldesc.wIDLFlags & PARAMFLAG_FHASDEFAULT && ed->paramdesc.pparamdescex) defaultValue = PyCom_PyObjectFromVariant(&ed->paramdesc.pparamdescex->varDefaultValue); if (defaultValue==NULL) { defaultValue = Py_None; Py_INCREF(Py_None); } PyObject *td = PyObject_FromTYPEDESC(&ed->tdesc); PyObject *ret = Py_BuildValue("(OiO)", td, ed->paramdesc.wParamFlags, defaultValue); Py_DECREF(td); Py_DECREF(defaultValue); return ret; }
// @pymethod |PyIOleCommandTarget|Exec|Description of Exec. PyObject *PyIOleCommandTarget::Exec(PyObject *self, PyObject *args) { PyObject *ret; int cmdid, cmdopt; PyObject *obVar; PyObject *obGUID; VARIANT varIn, varOut; IOleCommandTarget *pIOCT = GetI(self); if ( pIOCT == NULL ) return NULL; if (!PyArg_ParseTuple(args, "OiiO", &obGUID, &cmdid, &cmdopt, &obVar)) return NULL; GUID guid; GUID *pguid; if (obGUID == Py_None) { pguid = NULL; } else { if (!PyWinObject_AsIID(obGUID, &guid)) return FALSE; pguid = &guid; } VariantInit(&varIn); VariantInit(&varOut); if (!PyCom_VariantFromPyObject(obVar, &varIn)) return NULL; HRESULT hr; PY_INTERFACE_PRECALL; hr = pIOCT->Exec( pguid, cmdid, cmdopt, &varIn, &varOut); PY_INTERFACE_POSTCALL; VariantClear(&varIn); if ( FAILED(hr) ) { PyCom_BuildPyException(hr, pIOCT, IID_IOleCommandTarget ); ret = NULL; } else { ret = PyCom_PyObjectFromVariant(&varOut); } VariantClear(&varOut); return ret; }
// @pymethod object|PyIPropertyBag|Read|Called by the control to read a property from the storage provided by the container. PyObject *PyIPropertyBag::Read(PyObject *self, PyObject *args) { int varType = VT_EMPTY; PyObject *obLog = NULL; PyObject *obName; // @pyparm str|propName||Name of the property to read. // @pyparm int|propType||The type of the object to read. Must be a VT_* Variant Type constant. // @pyparm <o PyIErrorLog>|errorLog|None|The caller's <o PyIErrorLog> object in which the property bag stores any errors that occur during reads. Can be None in which case the caller is not interested in errors. if ( !PyArg_ParseTuple(args, "O|iO:Read", &obName, &varType, &obLog) ) return NULL; IPropertyBag *pIPB = GetI(self); if ( pIPB == NULL ) return NULL; TmpWCHAR Name; if (!PyWinObject_AsWCHAR(obName, &Name)) return NULL; IErrorLog *pIEL = NULL; if ( obLog != NULL && obLog != Py_None && !PyCom_InterfaceFromPyObject(obLog, IID_IErrorLog, (LPVOID*)&pIEL, FALSE) ) return NULL; VARIANT var; VariantInit(&var); V_VT(&var) = varType; // ### do we need to set anything more? PY_INTERFACE_PRECALL; HRESULT hr = pIPB->Read(Name, &var, pIEL); if ( pIEL != NULL ) pIEL->Release(); PY_INTERFACE_POSTCALL; if ( FAILED(hr) ) return PyCom_BuildPyException(hr, pIPB, IID_IPropertyBag); PyObject *result = PyCom_PyObjectFromVariant(&var); VariantClear(&var); // @comm The result is a Python object, mapped from a COM VARIANT of type as specified in the propType parameter. return result; }
STDMETHODIMP PyGPropertyBag::Write( /* [in] */ LPCOLESTR pszPropName, /* [in] */ VARIANT __RPC_FAR *pVar) { if ( pszPropName == NULL || pVar == NULL ) return E_POINTER; PY_GATEWAY_METHOD; PyObject *value = PyCom_PyObjectFromVariant(pVar); if ( !value ) return PyCom_SetCOMErrorFromPyException(GetIID()); PyObject *obName = PyWinObject_FromWCHAR(pszPropName); HRESULT hr = InvokeViaPolicy("Write", NULL, "OO", obName, value); Py_DECREF(value); Py_XDECREF(obName); return hr; }
STDMETHODIMP PyGOleCommandTarget::Exec( /* [unique][in] */ const GUID * pguidCmdGroup, /* [in] */ DWORD nCmdID, /* [in] */ DWORD nCmdexecopt, /* [unique][in] */ VARIANT * pvaIn, /* [unique][out][in] */ VARIANT * pvaOut) { PY_GATEWAY_METHOD; PyObject *obGUID; if (pguidCmdGroup == NULL) { obGUID = Py_None; Py_INCREF(obGUID); } else { obGUID = PyWinObject_FromIID(*pguidCmdGroup); } PyObject *obpvaIn = PyCom_PyObjectFromVariant(pvaIn); PyObject *result; HRESULT hr=InvokeViaPolicy("Exec", &result, "NllN", obGUID, nCmdID, nCmdexecopt, obpvaIn); if (FAILED(hr)) return hr; hr = pvaOut ? PyCom_VariantFromPyObject(result, pvaOut) : S_OK; Py_DECREF(result); return hr; }
PyObject * dataconv_ReadFromInTuple(PyObject *self, PyObject *args) { PyObject *obArgTypes; PyObject *obArgType; PyObject *obPtr; BYTE *pb; BYTE *pbArg; Py_ssize_t cArgs, i; PyObject *obArgs = NULL; PyObject *obArg; VARTYPE vtArgType; UINT cb; VARIANT var; BOOL bIsByRef; if (!PyArg_ParseTuple(args, "OO:ReadFromInTuple", &obArgTypes, &obPtr)) return NULL; pbArg = (BYTE *)PyLong_AsVoidPtr(obPtr); assert(pbArg); if (!pbArg) return NULL; pb = pbArg; if (!PyTuple_Check(obArgTypes)) { PyErr_SetString(PyExc_TypeError, "OLE type description - expecting a tuple"); return NULL; } cArgs = PyTuple_Size(obArgTypes); obArgs = PyTuple_New(cArgs); if (!obArgs) return NULL; for(i = 0 ; i < cArgs; i++) { // (<type tuple>, argPtr offset, arg size) if (PyTuple_Size(PyTuple_GET_ITEM(obArgTypes, i)) != 3) { PyErr_SetString(PyExc_TypeError, "OLE type description - expecting an arg desc tuple of size 3"); goto Error; } obArgType = PyTuple_GET_ITEM(PyTuple_GET_ITEM(obArgTypes, i), 0); // Position pb to point to the current argument. pb = pbArg + PyInt_AS_LONG(PyTuple_GET_ITEM(PyTuple_GET_ITEM(obArgTypes, i), 1)); vtArgType = (VARTYPE)PyInt_AS_LONG(obArgType); #ifdef _M_IX86 bIsByRef = vtArgType & VT_BYREF; #elif _M_X64 // params > 64bits always passed by address - and the only // arg we support > 64 bits is a VARIANT structure. bIsByRef = (vtArgType==VT_VARIANT) || (vtArgType & VT_BYREF); #else #error Unknown platform #endif VARTYPE vtConversionType = vtArgType & VT_TYPEMASK; if (vtArgType & VT_ARRAY) { SAFEARRAY FAR *psa = *((SAFEARRAY **)pb); if (psa==NULL) { // A NULL array Py_INCREF(Py_None); obArg = Py_None; } else { if (vtArgType & VT_BYREF) // one more level of indirection psa = *((SAFEARRAY FAR **)psa); if (psa==NULL) { // A NULL array Py_INCREF(Py_None); obArg = Py_None; } else obArg = PyCom_PyObjectFromSAFEARRAY(psa, (VARENUM)vtConversionType); } } else { switch (vtConversionType) { // If they can fit in a VARIANT, cheat and make that code do all of the work... case VT_I2: case VT_I4: case VT_R4: case VT_R8: case VT_CY: case VT_DATE: case VT_BSTR: case VT_ERROR: case VT_BOOL: case VT_I1: case VT_UI1: case VT_UI2: case VT_UI4: case VT_INT: case VT_UINT: case VT_UNKNOWN: case VT_DISPATCH: case VT_HRESULT: VariantInit(&var); if (vtConversionType == VT_HRESULT || vtConversionType == VT_INT) { // Preserve VT_BYREF or VT_ARRAY vtArgType = VT_I4 | (vtArgType & VT_TYPEMASK); } if (vtArgType == VT_UINT) { // Preserve VT_BYREF or VT_ARRAY vtArgType = VT_UI4 | (vtArgType & VT_TYPEMASK); } V_VT(&var) = vtArgType; // Copy the data into the variant... if (!SizeOfVT(V_VT(&var), (int *)&cb, NULL)) goto Error; memcpy(&V_I4(&var), pb, cb); // Convert it into a PyObject: obArg = PyCom_PyObjectFromVariant(&var); break; case VT_VARIANT: // A _real_ variant. if (bIsByRef) obArg = PyCom_PyObjectFromVariant(*(VARIANT**)pb); else obArg = PyCom_PyObjectFromVariant((VARIANT*)pb); break; case VT_LPSTR: obArg = PyString_FromString(*(CHAR **)pb); break; case VT_LPWSTR: obArg = PyWinObject_FromOLECHAR(*(OLECHAR **)pb); break; // Special cases: case VT_UI8: if (bIsByRef) { obArg = PyWinObject_FromULARGE_INTEGER(*(ULARGE_INTEGER *)pb); } else { obArg = PyWinObject_FromULARGE_INTEGER(**(ULARGE_INTEGER **)pb); } break; case VT_I8: if (bIsByRef) { obArg = PyWinObject_FromLARGE_INTEGER(*(LARGE_INTEGER *)pb); } else { obArg = PyWinObject_FromLARGE_INTEGER(**(LARGE_INTEGER **)pb); } break; // Pointers to unhandled arguments: // neither of these will be VT_BYREF'd. case VT_RECORD: case VT_PTR: obArg = PyLong_FromVoidPtr((void *)pb); break; // None of these should ever happen: case VT_USERDEFINED: // Should have been coerced into VT_PTR. case VT_CARRAY: default: obArg = NULL; PyErr_SetString(PyExc_TypeError, "Unknown/bad type description type!"); // barf here, we don't wtf they were thinking... break; } // switch } // if ARRAY if (obArg == NULL) { goto Error; } PyTuple_SET_ITEM(obArgs, i, obArg); } return obArgs; Error: Py_XDECREF(obArgs); return NULL; }
PyObject *PyRecord::getattro(PyObject *self, PyObject *obname) { PyObject *res; PyRecord *pyrec = (PyRecord *)self; char *name=PYWIN_ATTR_CONVERT(obname); if (name==NULL) return NULL; if (strcmp(name, "__members__")==0) { ULONG cnames = 0; HRESULT hr = pyrec->pri->GetFieldNames(&cnames, NULL); if (FAILED(hr)) return PyCom_BuildPyException(hr, pyrec->pri, IID_IRecordInfo); BSTR *strs = (BSTR *)malloc(sizeof(BSTR) * cnames); if (strs==NULL) return PyErr_NoMemory(); hr = pyrec->pri->GetFieldNames(&cnames, strs); if (FAILED(hr)) { free(strs); return PyCom_BuildPyException(hr, pyrec->pri, IID_IRecordInfo); } res = PyList_New(cnames); for (ULONG i=0;i<cnames && res != NULL;i++) { PyObject *item = PyWinCoreString_FromString(strs[i]); SysFreeString(strs[i]); if (item==NULL) { Py_DECREF(res); res = NULL; } else PyList_SET_ITEM(res, i, item); // ref count swallowed. } free(strs); return res; } res = PyObject_GenericGetAttr(self, obname); if (res != NULL) return res; PyErr_Clear(); WCHAR *wname; if (!PyWinObject_AsWCHAR(obname, &wname)) return NULL; VARIANT vret; VariantInit(&vret); void *sub_data = NULL; PY_INTERFACE_PRECALL; HRESULT hr = pyrec->pri->GetFieldNoCopy(pyrec->pdata, wname, &vret, &sub_data); PyWinObject_FreeWCHAR(wname); PY_INTERFACE_POSTCALL; if (FAILED(hr)) { if (hr == TYPE_E_FIELDNOTFOUND){ // This is slightly suspect - throwing a unicode // object for an AttributeError in py2k - but this // is the value we asked COM for, so it makes sense... // (and PyErr_Format doesn't handle unicode in py2x) PyErr_SetObject(PyExc_AttributeError, obname); return NULL; } return PyCom_BuildPyException(hr, pyrec->pri, IID_IRecordInfo); } // Short-circuit sub-structs and arrays here, so we dont allocate a new chunk // of memory and copy it - we need sub-structs to persist. if (V_VT(&vret)==(VT_BYREF | VT_RECORD)) return new PyRecord(V_RECORDINFO(&vret), V_RECORD(&vret), pyrec->owner); else if (V_VT(&vret)==(VT_BYREF | VT_ARRAY | VT_RECORD)) { SAFEARRAY *psa = *V_ARRAYREF(&vret); int d = SafeArrayGetDim(psa); if (sub_data==NULL) return PyErr_Format(PyExc_RuntimeError, "Did not get a buffer for the array!"); if (SafeArrayGetDim(psa) != 1) return PyErr_Format(PyExc_TypeError, "Only support single dimensional arrays of records"); IRecordInfo *sub = NULL; long ubound, lbound, nelems; int i; BYTE *this_data; PyObject *ret_tuple = NULL; ULONG element_size = 0; hr = SafeArrayGetUBound(psa, 1, &ubound); if (FAILED(hr)) goto array_end; hr = SafeArrayGetLBound(psa, 1, &lbound); if (FAILED(hr)) goto array_end; hr = SafeArrayGetRecordInfo(psa, &sub); if (FAILED(hr)) goto array_end; hr = sub->GetSize(&element_size); if (FAILED(hr)) goto array_end; nelems = ubound-lbound; ret_tuple = PyTuple_New(nelems); if (ret_tuple==NULL) goto array_end; this_data = (BYTE *)sub_data; for (i=0;i<nelems;i++) { PyTuple_SET_ITEM(ret_tuple, i, new PyRecord(sub, this_data, pyrec->owner)); this_data += element_size; } array_end: if (sub) sub->Release(); if (FAILED(hr)) return PyCom_BuildPyException(hr, pyrec->pri, IID_IRecordInfo); return ret_tuple; } // This default conversion we use is a little slow (but it will do!) // For arrays, the pparray->pvData member is *not* set, since the actual data // pointer from the record is returned in sub_data, so set it here. if (V_ISARRAY(&vret) && V_ISBYREF(&vret)) (*V_ARRAYREF(&vret))->pvData = sub_data; PyObject *ret = PyCom_PyObjectFromVariant(&vret); // VariantClear(&vret); return ret; }
// @pymethod object|PyIDispatchEx|InvokeEx|Provides access to properties and methods exposed by a <o PyIDispatchEx> object. PyObject *PyIDispatchEx::InvokeEx(PyObject *self, PyObject *args) { long dispid; long lcid; int flags; PyObject *invokeArgs; PyObject *types = Py_None; PyObject *obReturnDesc = Py_None; PyObject *obCaller = Py_None; if (!PyArg_ParseTuple(args, "lliO|OOO:InvokeEx", &dispid, // @pyparm int|dispid|| &lcid, // @pyparm int|lcid|| &flags, // @pyparm int|flags|| &invokeArgs, // @pyparm [object, ...]|args||The arguments. &types, // @pyparm [object, ...]|types|None|A tuple of type description object, or None if type descriptions are not available. &obReturnDesc, // @pyparm object\|int|returnDesc|1|If types==None, should be a BOOL indicating if the result is needed. If types is a tuple, then should a be type description. &obCaller)) // @pyparm <o PyIServiceProvider>|serviceProvider|None|A service provider object supplied by the caller which allows the object to obtain services from the caller. Can be None. return NULL; if (!PyTuple_Check(invokeArgs)) { PyErr_SetString(PyExc_TypeError, "The arguments must be a tuple."); return NULL; } // TODO - We do not yet support the Type Description here // (Im not even sure if we need it!) if (types != Py_None || obReturnDesc != Py_None) { PyErr_SetString(PyExc_TypeError, "Type descriptions are not yet supported."); return NULL; } // TODO - Add support for PyIServiceProvider if (obCaller != Py_None) { PyErr_SetString(PyExc_TypeError, "If you really need IServiceProvider support, you are going to have to add it!."); return NULL; } BOOL bResultWanted = TRUE; IDispatchEx *pMyDispatch = GetI(self); if ( pMyDispatch==NULL ) return NULL; DISPPARAMS dispparams; PythonOleArgHelper *helpers; if (!PyCom_MakeUntypedDISPPARAMS(invokeArgs, PyObject_Length(invokeArgs), flags, &dispparams, &helpers )) return NULL; VARIANT varResult; VARIANT *pVarResultUse; if ( bResultWanted ) { VariantInit(&varResult); pVarResultUse = &varResult; } else pVarResultUse = NULL; // initialize EXCEPINFO struct EXCEPINFO excepInfo; memset(&excepInfo, 0, sizeof excepInfo); PY_INTERFACE_PRECALL; HRESULT hr = pMyDispatch->InvokeEx((DISPID)dispid, (LCID)lcid, (WORD)flags, &dispparams, pVarResultUse, &excepInfo, NULL); PY_INTERFACE_POSTCALL; if (!PyCom_FinishUntypedDISPPARAMS(&dispparams, helpers) || HandledDispatchFailure(hr, &excepInfo, (UINT)-1, dispparams.cArgs) ) { if ( pVarResultUse ) VariantClear(pVarResultUse); return NULL; } PyObject *result; if (pVarResultUse) { result = PyCom_PyObjectFromVariant(pVarResultUse); VariantClear(pVarResultUse); } else { result = Py_None; Py_INCREF(result); } return result; }
// @pymethod object|PyIDispatch|Invoke|Invokes a DISPID, using the passed arguments. PyObject * PyIDispatch::Invoke(PyObject *self, PyObject *args) { /* Invoke(dispid, lcid, wflags, bResultWanted, arg1, arg2...) */ // should be no need to clear this error - but for the next few release // I will keep it in place for release builds, and assert in debug #ifdef _DEBUG assert(!PyErr_Occurred()); #else PyErr_Clear(); #endif int argc = PyObject_Length(args); if ( argc == -1 ) return NULL; if ( argc < 4 ) return PyErr_Format(PyExc_TypeError, "not enough arguments (at least 4 needed)"); // @pyparm int|dispid||The dispid to use. Typically this value will come from <om PyIDispatch.GetIDsOfNames> or from a type library. DISPID dispid = PyInt_AsLong(PyTuple_GET_ITEM(args, 0)); // @pyparm int|lcid||The locale id to use. LCID lcid = PyInt_AsLong(PyTuple_GET_ITEM(args, 1)); // @pyparm int|flags||The flags for the call. The following flags can be used. // @flagh Flag|Description // @flag DISPATCH_METHOD|The member is invoked as a method. If a property has the same name, both this and the DISPATCH_PROPERTYGET flag may be set. // @flag DISPATCH_PROPERTYGET|The member is retrieved as a property or data member. // @flag DISPATCH_PROPERTYPUT|The member is changed as a property or data member. // @flag DISPATCH_PROPERTYPUTREF|The member is changed by a reference assignment, rather than a value assignment. This flag is valid only when the property accepts a reference to an object. UINT wFlags = PyInt_AsLong(PyTuple_GET_ITEM(args, 2)); // @pyparm int|bResultWanted||Indicates if the result of the call should be requested. // @pyparm object, ...|params, ...||The parameters to pass. BOOL bResultWanted = (BOOL)PyInt_AsLong(PyTuple_GET_ITEM(args, 3)); if ( PyErr_Occurred() ) return NULL; IDispatch *pMyDispatch = GetI(self); if ( pMyDispatch==NULL ) return NULL; DISPPARAMS dispparams; PythonOleArgHelper *helpers; if (!PyCom_MakeUntypedDISPPARAMS(args, argc-4, wFlags, &dispparams, &helpers )) return NULL; VARIANT varResult; VARIANT *pVarResultUse; if ( bResultWanted ) { VariantInit(&varResult); pVarResultUse = &varResult; } else pVarResultUse = NULL; // initialize EXCEPINFO struct EXCEPINFO excepInfo; memset(&excepInfo, 0, sizeof excepInfo); UINT nArgErr = (UINT)-1; // initialize to invalid arg PY_INTERFACE_PRECALL; HRESULT hr = pMyDispatch->Invoke(dispid, IID_NULL, lcid, wFlags, &dispparams, pVarResultUse, &excepInfo, &nArgErr); PY_INTERFACE_POSTCALL; if (!PyCom_FinishUntypedDISPPARAMS(&dispparams, helpers) || HandledDispatchFailure(hr, &excepInfo, nArgErr, dispparams.cArgs) ) { if ( pVarResultUse ) VariantClear(pVarResultUse); return NULL; } // @rdesc If the bResultWanted parameter is False, then the result will be None. // Otherwise, the result is determined by the COM object itself (and may still be None) PyObject *result; if (pVarResultUse) { result = PyCom_PyObjectFromVariant(pVarResultUse); VariantClear(pVarResultUse); } else { result = Py_None; Py_INCREF(result); } return result; }