makegwenum.py 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. """Utility file for generating PyIEnum support.
  2. This is almost a 'template' file. It simplay contains almost full
  3. C++ source code for PyIEnum* support, and the Python code simply
  4. substitutes the appropriate interface name.
  5. This module is notmally not used directly - the @makegw@ module
  6. automatically calls this.
  7. """
  8. #
  9. # INTERNAL FUNCTIONS
  10. #
  11. #
  12. import string
  13. def is_interface_enum(enumtype):
  14. return not (enumtype[0] in string.uppercase and enumtype[2] in string.uppercase)
  15. def _write_enumifc_cpp(f, interface):
  16. enumtype = interface.name[5:]
  17. if is_interface_enum(enumtype):
  18. # Assume an interface.
  19. enum_interface = "I" + enumtype[:-1]
  20. converter = "PyObject *ob = PyCom_PyObjectFromIUnknown(rgVar[i], IID_%(enum_interface)s, FALSE);" % locals()
  21. arraydeclare = "%(enum_interface)s **rgVar = new %(enum_interface)s *[celt];" % locals()
  22. else:
  23. # Enum of a simple structure
  24. converter = "PyObject *ob = PyCom_PyObjectFrom%(enumtype)s(&rgVar[i]);" % locals()
  25. arraydeclare = "%(enumtype)s *rgVar = new %(enumtype)s[celt];" % locals()
  26. f.write(\
  27. '''
  28. // ---------------------------------------------------
  29. //
  30. // Interface Implementation
  31. PyIEnum%(enumtype)s::PyIEnum%(enumtype)s(IUnknown *pdisp):
  32. PyIUnknown(pdisp)
  33. {
  34. ob_type = &type;
  35. }
  36. PyIEnum%(enumtype)s::~PyIEnum%(enumtype)s()
  37. {
  38. }
  39. /* static */ IEnum%(enumtype)s *PyIEnum%(enumtype)s::GetI(PyObject *self)
  40. {
  41. return (IEnum%(enumtype)s *)PyIUnknown::GetI(self);
  42. }
  43. // @pymethod object|PyIEnum%(enumtype)s|Next|Retrieves a specified number of items in the enumeration sequence.
  44. PyObject *PyIEnum%(enumtype)s::Next(PyObject *self, PyObject *args)
  45. {
  46. long celt = 1;
  47. // @pyparm int|num|1|Number of items to retrieve.
  48. if ( !PyArg_ParseTuple(args, "|l:Next", &celt) )
  49. return NULL;
  50. IEnum%(enumtype)s *pIE%(enumtype)s = GetI(self);
  51. if ( pIE%(enumtype)s == NULL )
  52. return NULL;
  53. %(arraydeclare)s
  54. if ( rgVar == NULL ) {
  55. PyErr_SetString(PyExc_MemoryError, "allocating result %(enumtype)ss");
  56. return NULL;
  57. }
  58. int i;
  59. /* for ( i = celt; i--; )
  60. // *** possibly init each structure element???
  61. */
  62. ULONG celtFetched = 0;
  63. PY_INTERFACE_PRECALL;
  64. HRESULT hr = pIE%(enumtype)s->Next(celt, rgVar, &celtFetched);
  65. PY_INTERFACE_POSTCALL;
  66. if ( HRESULT_CODE(hr) != ERROR_NO_MORE_ITEMS && FAILED(hr) )
  67. {
  68. delete [] rgVar;
  69. return PyCom_BuildPyException(hr,pIE%(enumtype)s, IID_IE%(enumtype)s);
  70. }
  71. PyObject *result = PyTuple_New(celtFetched);
  72. if ( result != NULL )
  73. {
  74. for ( i = celtFetched; i--; )
  75. {
  76. %(converter)s
  77. if ( ob == NULL )
  78. {
  79. Py_DECREF(result);
  80. result = NULL;
  81. break;
  82. }
  83. PyTuple_SET_ITEM(result, i, ob);
  84. }
  85. }
  86. /* for ( i = celtFetched; i--; )
  87. // *** possibly cleanup each structure element???
  88. */
  89. delete [] rgVar;
  90. return result;
  91. }
  92. // @pymethod |PyIEnum%(enumtype)s|Skip|Skips over the next specified elementes.
  93. PyObject *PyIEnum%(enumtype)s::Skip(PyObject *self, PyObject *args)
  94. {
  95. long celt;
  96. if ( !PyArg_ParseTuple(args, "l:Skip", &celt) )
  97. return NULL;
  98. IEnum%(enumtype)s *pIE%(enumtype)s = GetI(self);
  99. if ( pIE%(enumtype)s == NULL )
  100. return NULL;
  101. PY_INTERFACE_PRECALL;
  102. HRESULT hr = pIE%(enumtype)s->Skip(celt);
  103. PY_INTERFACE_POSTCALL;
  104. if ( FAILED(hr) )
  105. return PyCom_BuildPyException(hr, pIE%(enumtype)s, IID_IE%(enumtype)s);
  106. Py_INCREF(Py_None);
  107. return Py_None;
  108. }
  109. // @pymethod |PyIEnum%(enumtype)s|Reset|Resets the enumeration sequence to the beginning.
  110. PyObject *PyIEnum%(enumtype)s::Reset(PyObject *self, PyObject *args)
  111. {
  112. if ( !PyArg_ParseTuple(args, ":Reset") )
  113. return NULL;
  114. IEnum%(enumtype)s *pIE%(enumtype)s = GetI(self);
  115. if ( pIE%(enumtype)s == NULL )
  116. return NULL;
  117. PY_INTERFACE_PRECALL;
  118. HRESULT hr = pIE%(enumtype)s->Reset();
  119. PY_INTERFACE_POSTCALL;
  120. if ( FAILED(hr) )
  121. return PyCom_BuildPyException(hr, pIE%(enumtype)s, IID_IE%(enumtype)s);
  122. Py_INCREF(Py_None);
  123. return Py_None;
  124. }
  125. // @pymethod <o PyIEnum%(enumtype)s>|PyIEnum%(enumtype)s|Clone|Creates another enumerator that contains the same enumeration state as the current one
  126. PyObject *PyIEnum%(enumtype)s::Clone(PyObject *self, PyObject *args)
  127. {
  128. if ( !PyArg_ParseTuple(args, ":Clone") )
  129. return NULL;
  130. IEnum%(enumtype)s *pIE%(enumtype)s = GetI(self);
  131. if ( pIE%(enumtype)s == NULL )
  132. return NULL;
  133. IEnum%(enumtype)s *pClone;
  134. PY_INTERFACE_PRECALL;
  135. HRESULT hr = pIE%(enumtype)s->Clone(&pClone);
  136. PY_INTERFACE_POSTCALL;
  137. if ( FAILED(hr) )
  138. return PyCom_BuildPyException(hr, pIE%(enumtype)s, IID_IE%(enumtype)s);
  139. return PyCom_PyObjectFromIUnknown(pClone, IID_IEnum%(enumtype)s, FALSE);
  140. }
  141. // @object PyIEnum%(enumtype)s|A Python interface to IEnum%(enumtype)s
  142. static struct PyMethodDef PyIEnum%(enumtype)s_methods[] =
  143. {
  144. { "Next", PyIEnum%(enumtype)s::Next, 1 }, // @pymeth Next|Retrieves a specified number of items in the enumeration sequence.
  145. { "Skip", PyIEnum%(enumtype)s::Skip, 1 }, // @pymeth Skip|Skips over the next specified elementes.
  146. { "Reset", PyIEnum%(enumtype)s::Reset, 1 }, // @pymeth Reset|Resets the enumeration sequence to the beginning.
  147. { "Clone", PyIEnum%(enumtype)s::Clone, 1 }, // @pymeth Clone|Creates another enumerator that contains the same enumeration state as the current one.
  148. { NULL }
  149. };
  150. PyComEnumTypeObject PyIEnum%(enumtype)s::type("PyIEnum%(enumtype)s",
  151. &PyIUnknown::type,
  152. sizeof(PyIEnum%(enumtype)s),
  153. PyIEnum%(enumtype)s_methods,
  154. GET_PYCOM_CTOR(PyIEnum%(enumtype)s));
  155. ''' % locals() )
  156. def _write_enumgw_cpp(f, interface):
  157. enumtype = interface.name[5:]
  158. if is_interface_enum(enumtype):
  159. # Assume an interface.
  160. enum_interface = "I" + enumtype[:-1]
  161. converter = "if ( !PyCom_InterfaceFromPyObject(ob, IID_%(enum_interface)s, (void **)&rgVar[i], FALSE) )" % locals()
  162. argdeclare="%(enum_interface)s __RPC_FAR * __RPC_FAR *rgVar" % locals()
  163. else:
  164. argdeclare="%(enumtype)s __RPC_FAR *rgVar" % locals()
  165. converter="if ( !PyCom_PyObjectAs%(enumtype)s(ob, &rgVar[i]) )" % locals()
  166. f.write(
  167. '''
  168. // ---------------------------------------------------
  169. //
  170. // Gateway Implementation
  171. // Std delegation
  172. STDMETHODIMP_(ULONG) PyGEnum%(enumtype)s::AddRef(void) {return PyGatewayBase::AddRef();}
  173. STDMETHODIMP_(ULONG) PyGEnum%(enumtype)s::Release(void) {return PyGatewayBase::Release();}
  174. STDMETHODIMP PyGEnum%(enumtype)s::QueryInterface(REFIID iid, void ** obj) {return PyGatewayBase::QueryInterface(iid, obj);}
  175. STDMETHODIMP PyGEnum%(enumtype)s::GetTypeInfoCount(UINT FAR* pctInfo) {return PyGatewayBase::GetTypeInfoCount(pctInfo);}
  176. STDMETHODIMP PyGEnum%(enumtype)s::GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo FAR* FAR* pptInfo) {return PyGatewayBase::GetTypeInfo(itinfo, lcid, pptInfo);}
  177. STDMETHODIMP PyGEnum%(enumtype)s::GetIDsOfNames(REFIID refiid, OLECHAR FAR* FAR* rgszNames, UINT cNames, LCID lcid, DISPID FAR* rgdispid) {return PyGatewayBase::GetIDsOfNames( refiid, rgszNames, cNames, lcid, rgdispid);}
  178. STDMETHODIMP PyGEnum%(enumtype)s::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);}
  179. STDMETHODIMP PyGEnum%(enumtype)s::Next(
  180. /* [in] */ ULONG celt,
  181. /* [length_is][size_is][out] */ %(argdeclare)s,
  182. /* [out] */ ULONG __RPC_FAR *pCeltFetched)
  183. {
  184. PY_GATEWAY_METHOD;
  185. PyObject *result;
  186. HRESULT hr = InvokeViaPolicy("Next", &result, "i", celt);
  187. if ( FAILED(hr) )
  188. return hr;
  189. if ( !PySequence_Check(result) )
  190. goto error;
  191. int len;
  192. len = PyObject_Length(result);
  193. if ( len == -1 )
  194. goto error;
  195. if ( len > (int)celt)
  196. len = celt;
  197. if ( pCeltFetched )
  198. *pCeltFetched = len;
  199. int i;
  200. for ( i = 0; i < len; ++i )
  201. {
  202. PyObject *ob = PySequence_GetItem(result, i);
  203. if ( ob == NULL )
  204. goto error;
  205. %(converter)s
  206. {
  207. Py_DECREF(result);
  208. return PyCom_SetCOMErrorFromPyException(IID_IEnum%(enumtype)s);
  209. }
  210. }
  211. Py_DECREF(result);
  212. return len < (int)celt ? S_FALSE : S_OK;
  213. error:
  214. PyErr_Clear(); // just in case
  215. Py_DECREF(result);
  216. return PyCom_SetCOMErrorFromSimple(E_FAIL, IID_IEnum%(enumtype)s, "Next() did not return a sequence of objects");
  217. }
  218. STDMETHODIMP PyGEnum%(enumtype)s::Skip(
  219. /* [in] */ ULONG celt)
  220. {
  221. PY_GATEWAY_METHOD;
  222. return InvokeViaPolicy("Skip", NULL, "i", celt);
  223. }
  224. STDMETHODIMP PyGEnum%(enumtype)s::Reset(void)
  225. {
  226. PY_GATEWAY_METHOD;
  227. return InvokeViaPolicy("Reset");
  228. }
  229. STDMETHODIMP PyGEnum%(enumtype)s::Clone(
  230. /* [out] */ IEnum%(enumtype)s __RPC_FAR *__RPC_FAR *ppEnum)
  231. {
  232. PY_GATEWAY_METHOD;
  233. PyObject * result;
  234. HRESULT hr = InvokeViaPolicy("Clone", &result);
  235. if ( FAILED(hr) )
  236. return hr;
  237. /*
  238. ** Make sure we have the right kind of object: we should have some kind
  239. ** of IUnknown subclass wrapped into a PyIUnknown instance.
  240. */
  241. if ( !PyIBase::is_object(result, &PyIUnknown::type) )
  242. {
  243. /* the wrong kind of object was returned to us */
  244. Py_DECREF(result);
  245. return PyCom_SetCOMErrorFromSimple(E_FAIL, IID_IEnum%(enumtype)s);
  246. }
  247. /*
  248. ** Get the IUnknown out of the thing. note that the Python ob maintains
  249. ** a reference, so we don't have to explicitly AddRef() here.
  250. */
  251. IUnknown *punk = ((PyIUnknown *)result)->m_obj;
  252. if ( !punk )
  253. {
  254. /* damn. the object was released. */
  255. Py_DECREF(result);
  256. return PyCom_SetCOMErrorFromSimple(E_FAIL, IID_IEnum%(enumtype)s);
  257. }
  258. /*
  259. ** Get the interface we want. note it is returned with a refcount.
  260. ** This QI is actually going to instantiate a PyGEnum%(enumtype)s.
  261. */
  262. hr = punk->QueryInterface(IID_IEnum%(enumtype)s, (LPVOID *)ppEnum);
  263. /* done with the result; this DECREF is also for <punk> */
  264. Py_DECREF(result);
  265. return PyCom_SetCOMErrorFromSimple(hr, IID_IEnum%(enumtype)s, "Python could not convert the result from Next() into the required COM interface");
  266. }
  267. ''' % locals())