"""Utility file for generating PyIEnum support. This is almost a 'template' file. It simplay contains almost full C++ source code for PyIEnum* support, and the Python code simply substitutes the appropriate interface name. This module is notmally not used directly - the @makegw@ module automatically calls this. """ # # INTERNAL FUNCTIONS # # def is_interface_enum(enumtype): return not (enumtype[0].isupper() and enumtype[2].isupper()) def _write_enumifc_cpp(f, interface): enumtype = interface.name[5:] if is_interface_enum(enumtype): # Assume an interface. enum_interface = "I" + enumtype[:-1] converter = "PyObject *ob = PyCom_PyObjectFromIUnknown(rgVar[i], IID_{enum_interface}, FALSE);".format( **locals() ) arraydeclare = ( "{enum_interface} **rgVar = new {enum_interface} *[celt];".format( **locals() ) ) else: # Enum of a simple structure converter = "PyObject *ob = PyCom_PyObjectFrom{enumtype}(&rgVar[i]);".format( **locals() ) arraydeclare = "{enumtype} *rgVar = new {enumtype}[celt];".format(**locals()) f.write( """ // --------------------------------------------------- // // Interface Implementation PyIEnum{enumtype}::PyIEnum{enumtype}(IUnknown *pdisp): PyIUnknown(pdisp) {{ ob_type = &type; }} PyIEnum{enumtype}::~PyIEnum{enumtype}() {{ }} /* static */ IEnum{enumtype} *PyIEnum{enumtype}::GetI(PyObject *self) {{ return (IEnum{enumtype} *)PyIUnknown::GetI(self); }} // @pymethod object|PyIEnum{enumtype}|Next|Retrieves a specified number of items in the enumeration sequence. PyObject *PyIEnum{enumtype}::Next(PyObject *self, PyObject *args) {{ long celt = 1; // @pyparm int|num|1|Number of items to retrieve. if ( !PyArg_ParseTuple(args, "|l:Next", &celt) ) return NULL; IEnum{enumtype} *pIE{enumtype} = GetI(self); if ( pIE{enumtype} == NULL ) return NULL; {arraydeclare} if ( rgVar == NULL ) {{ PyErr_SetString(PyExc_MemoryError, "allocating result {enumtype}s"); return NULL; }} int i; /* for ( i = celt; i--; ) // *** possibly init each structure element??? */ ULONG celtFetched = 0; PY_INTERFACE_PRECALL; HRESULT hr = pIE{enumtype}->Next(celt, rgVar, &celtFetched); PY_INTERFACE_POSTCALL; if ( HRESULT_CODE(hr) != ERROR_NO_MORE_ITEMS && FAILED(hr) ) {{ delete [] rgVar; return PyCom_BuildPyException(hr,pIE{enumtype}, IID_IE{enumtype}); }} PyObject *result = PyTuple_New(celtFetched); if ( result != NULL ) {{ for ( i = celtFetched; i--; ) {{ {converter} if ( ob == NULL ) {{ Py_DECREF(result); result = NULL; break; }} PyTuple_SET_ITEM(result, i, ob); }} }} /* for ( i = celtFetched; i--; ) // *** possibly cleanup each structure element??? */ delete [] rgVar; return result; }} // @pymethod |PyIEnum{enumtype}|Skip|Skips over the next specified elementes. PyObject *PyIEnum{enumtype}::Skip(PyObject *self, PyObject *args) {{ long celt; if ( !PyArg_ParseTuple(args, "l:Skip", &celt) ) return NULL; IEnum{enumtype} *pIE{enumtype} = GetI(self); if ( pIE{enumtype} == NULL ) return NULL; PY_INTERFACE_PRECALL; HRESULT hr = pIE{enumtype}->Skip(celt); PY_INTERFACE_POSTCALL; if ( FAILED(hr) ) return PyCom_BuildPyException(hr, pIE{enumtype}, IID_IE{enumtype}); Py_INCREF(Py_None); return Py_None; }} // @pymethod |PyIEnum{enumtype}|Reset|Resets the enumeration sequence to the beginning. PyObject *PyIEnum{enumtype}::Reset(PyObject *self, PyObject *args) {{ if ( !PyArg_ParseTuple(args, ":Reset") ) return NULL; IEnum{enumtype} *pIE{enumtype} = GetI(self); if ( pIE{enumtype} == NULL ) return NULL; PY_INTERFACE_PRECALL; HRESULT hr = pIE{enumtype}->Reset(); PY_INTERFACE_POSTCALL; if ( FAILED(hr) ) return PyCom_BuildPyException(hr, pIE{enumtype}, IID_IE{enumtype}); Py_INCREF(Py_None); return Py_None; }} // @pymethod |PyIEnum{enumtype}|Clone|Creates another enumerator that contains the same enumeration state as the current one PyObject *PyIEnum{enumtype}::Clone(PyObject *self, PyObject *args) {{ if ( !PyArg_ParseTuple(args, ":Clone") ) return NULL; IEnum{enumtype} *pIE{enumtype} = GetI(self); if ( pIE{enumtype} == NULL ) return NULL; IEnum{enumtype} *pClone; PY_INTERFACE_PRECALL; HRESULT hr = pIE{enumtype}->Clone(&pClone); PY_INTERFACE_POSTCALL; if ( FAILED(hr) ) return PyCom_BuildPyException(hr, pIE{enumtype}, IID_IE{enumtype}); return PyCom_PyObjectFromIUnknown(pClone, IID_IEnum{enumtype}, FALSE); }} // @object PyIEnum{enumtype}|A Python interface to IEnum{enumtype} static struct PyMethodDef PyIEnum{enumtype}_methods[] = {{ {{ "Next", PyIEnum{enumtype}::Next, 1 }}, // @pymeth Next|Retrieves a specified number of items in the enumeration sequence. {{ "Skip", PyIEnum{enumtype}::Skip, 1 }}, // @pymeth Skip|Skips over the next specified elementes. {{ "Reset", PyIEnum{enumtype}::Reset, 1 }}, // @pymeth Reset|Resets the enumeration sequence to the beginning. {{ "Clone", PyIEnum{enumtype}::Clone, 1 }}, // @pymeth Clone|Creates another enumerator that contains the same enumeration state as the current one. {{ NULL }} }}; PyComEnumTypeObject PyIEnum{enumtype}::type("PyIEnum{enumtype}", &PyIUnknown::type, sizeof(PyIEnum{enumtype}), PyIEnum{enumtype}_methods, GET_PYCOM_CTOR(PyIEnum{enumtype})); """.format(**locals()) ) def _write_enumgw_cpp(f, interface): enumtype = interface.name[5:] if is_interface_enum(enumtype): # Assume an interface. enum_interface = "I" + enumtype[:-1] converter = "if ( !PyCom_InterfaceFromPyObject(ob, IID_{enum_interface}, (void **)&rgVar[i], FALSE) )".format( **locals() ) argdeclare = "{enum_interface} __RPC_FAR * __RPC_FAR *rgVar".format(**locals()) else: argdeclare = "{enumtype} __RPC_FAR *rgVar".format(**locals()) converter = "if ( !PyCom_PyObjectAs{enumtype}(ob, &rgVar[i]) )".format( **locals() ) f.write( """ // --------------------------------------------------- // // Gateway Implementation // Std delegation STDMETHODIMP_(ULONG) PyGEnum{enumtype}::AddRef(void) {{return PyGatewayBase::AddRef();}} STDMETHODIMP_(ULONG) PyGEnum{enumtype}::Release(void) {{return PyGatewayBase::Release();}} STDMETHODIMP PyGEnum{enumtype}::QueryInterface(REFIID iid, void ** obj) {{return PyGatewayBase::QueryInterface(iid, obj);}} STDMETHODIMP PyGEnum{enumtype}::GetTypeInfoCount(UINT FAR* pctInfo) {{return PyGatewayBase::GetTypeInfoCount(pctInfo);}} STDMETHODIMP PyGEnum{enumtype}::GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo FAR* FAR* pptInfo) {{return PyGatewayBase::GetTypeInfo(itinfo, lcid, pptInfo);}} STDMETHODIMP PyGEnum{enumtype}::GetIDsOfNames(REFIID refiid, OLECHAR FAR* FAR* rgszNames, UINT cNames, LCID lcid, DISPID FAR* rgdispid) {{return PyGatewayBase::GetIDsOfNames( refiid, rgszNames, cNames, lcid, rgdispid);}} STDMETHODIMP PyGEnum{enumtype}::Invoke(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR* params, VARIANT FAR* pVarResult, EXCEPINFO FAR* pexcepinfo, UINT FAR* puArgErr) {{return PyGatewayBase::Invoke( dispid, riid, lcid, wFlags, params, pVarResult, pexcepinfo, puArgErr);}} STDMETHODIMP PyGEnum{enumtype}::Next( /* [in] */ ULONG celt, /* [length_is][size_is][out] */ {argdeclare}, /* [out] */ ULONG __RPC_FAR *pCeltFetched) {{ PY_GATEWAY_METHOD; PyObject *result; HRESULT hr = InvokeViaPolicy("Next", &result, "i", celt); if ( FAILED(hr) ) return hr; if ( !PySequence_Check(result) ) goto error; int len; len = PyObject_Length(result); if ( len == -1 ) goto error; if ( len > (int)celt) len = celt; if ( pCeltFetched ) *pCeltFetched = len; int i; for ( i = 0; i < len; ++i ) {{ PyObject *ob = PySequence_GetItem(result, i); if ( ob == NULL ) goto error; {converter} {{ Py_DECREF(result); return PyCom_SetCOMErrorFromPyException(IID_IEnum{enumtype}); }} }} Py_DECREF(result); return len < (int)celt ? S_FALSE : S_OK; error: PyErr_Clear(); // just in case Py_DECREF(result); return PyCom_HandleIEnumNoSequence(IID_IEnum{enumtype}); }} STDMETHODIMP PyGEnum{enumtype}::Skip( /* [in] */ ULONG celt) {{ PY_GATEWAY_METHOD; return InvokeViaPolicy("Skip", NULL, "i", celt); }} STDMETHODIMP PyGEnum{enumtype}::Reset(void) {{ PY_GATEWAY_METHOD; return InvokeViaPolicy("Reset"); }} STDMETHODIMP PyGEnum{enumtype}::Clone( /* [out] */ IEnum{enumtype} __RPC_FAR *__RPC_FAR *ppEnum) {{ PY_GATEWAY_METHOD; PyObject * result; HRESULT hr = InvokeViaPolicy("Clone", &result); if ( FAILED(hr) ) return hr; /* ** Make sure we have the right kind of object: we should have some kind ** of IUnknown subclass wrapped into a PyIUnknown instance. */ if ( !PyIBase::is_object(result, &PyIUnknown::type) ) {{ /* the wrong kind of object was returned to us */ Py_DECREF(result); return PyCom_SetCOMErrorFromSimple(E_FAIL, IID_IEnum{enumtype}); }} /* ** Get the IUnknown out of the thing. note that the Python ob maintains ** a reference, so we don't have to explicitly AddRef() here. */ IUnknown *punk = ((PyIUnknown *)result)->m_obj; if ( !punk ) {{ /* damn. the object was released. */ Py_DECREF(result); return PyCom_SetCOMErrorFromSimple(E_FAIL, IID_IEnum{enumtype}); }} /* ** Get the interface we want. note it is returned with a refcount. ** This QI is actually going to instantiate a PyGEnum{enumtype}. */ hr = punk->QueryInterface(IID_IEnum{enumtype}, (LPVOID *)ppEnum); /* done with the result; this DECREF is also for */ Py_DECREF(result); return PyCom_CheckIEnumNextResult(hr, IID_IEnum{enumtype}); }} """.format(**locals()) )