Funktionierender Prototyp des Serious Games zur Vermittlung von Wissen zu Software-Engineering-Arbeitsmodellen.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

makegwparse.py 34KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008
  1. """Utilities for makegw - Parse a header file to build an interface
  2. This module contains the core code for parsing a header file describing a
  3. COM interface, and building it into an "Interface" structure.
  4. Each Interface has methods, and each method has arguments.
  5. Each argument knows how to use Py_BuildValue or Py_ParseTuple to
  6. exchange itself with Python.
  7. See the @win32com.makegw@ module for information in building a COM
  8. interface
  9. """
  10. import re
  11. import traceback
  12. class error_not_found(Exception):
  13. def __init__(self, msg="The requested item could not be found"):
  14. super(error_not_found, self).__init__(msg)
  15. class error_not_supported(Exception):
  16. def __init__(self, msg="The required functionality is not supported"):
  17. super(error_not_supported, self).__init__(msg)
  18. VERBOSE = 0
  19. DEBUG = 0
  20. ## NOTE : For interfaces as params to work correctly, you must
  21. ## make sure any PythonCOM extensions which expose the interface are loaded
  22. ## before generating.
  23. class ArgFormatter:
  24. """An instance for a specific type of argument. Knows how to convert itself"""
  25. def __init__(self, arg, builtinIndirection, declaredIndirection=0):
  26. # print 'init:', arg.name, builtinIndirection, declaredIndirection, arg.indirectionLevel
  27. self.arg = arg
  28. self.builtinIndirection = builtinIndirection
  29. self.declaredIndirection = declaredIndirection
  30. self.gatewayMode = 0
  31. def _IndirectPrefix(self, indirectionFrom, indirectionTo):
  32. """Given the indirection level I was declared at (0=Normal, 1=*, 2=**)
  33. return a string prefix so I can pass to a function with the
  34. required indirection (where the default is the indirection of the method's param.
  35. eg, assuming my arg has indirection level of 2, if this function was passed 1
  36. it would return "&", so that a variable declared with indirection of 1
  37. can be prefixed with this to turn it into the indirection level required of 2
  38. """
  39. dif = indirectionFrom - indirectionTo
  40. if dif == 0:
  41. return ""
  42. elif dif == -1:
  43. return "&"
  44. elif dif == 1:
  45. return "*"
  46. else:
  47. return "?? (%d)" % (dif,)
  48. raise error_not_supported("Can't indirect this far - please fix me :-)")
  49. def GetIndirectedArgName(self, indirectFrom, indirectionTo):
  50. # print 'get:',self.arg.name, indirectFrom,self._GetDeclaredIndirection() + self.builtinIndirection, indirectionTo, self.arg.indirectionLevel
  51. if indirectFrom is None:
  52. ### ACK! this does not account for [in][out] variables.
  53. ### when this method is called, we need to know which
  54. indirectFrom = self._GetDeclaredIndirection() + self.builtinIndirection
  55. return self._IndirectPrefix(indirectFrom, indirectionTo) + self.arg.name
  56. def GetBuildValueArg(self):
  57. "Get the argument to be passes to Py_BuildValue"
  58. return self.arg.name
  59. def GetParseTupleArg(self):
  60. "Get the argument to be passed to PyArg_ParseTuple"
  61. if self.gatewayMode:
  62. # use whatever they were declared with
  63. return self.GetIndirectedArgName(None, 1)
  64. # local declarations have just their builtin indirection
  65. return self.GetIndirectedArgName(self.builtinIndirection, 1)
  66. def GetInterfaceCppObjectInfo(self):
  67. """Provide information about the C++ object used.
  68. Simple variables (such as integers) can declare their type (eg an integer)
  69. and use it as the target of both PyArg_ParseTuple and the COM function itself.
  70. More complex types require a PyObject * declared as the target of PyArg_ParseTuple,
  71. then some conversion routine to the C++ object which is actually passed to COM.
  72. This method provides the name, and optionally the type of that C++ variable.
  73. If the type if provided, the caller will likely generate a variable declaration.
  74. The name must always be returned.
  75. Result is a tuple of (variableName, [DeclareType|None|""])
  76. """
  77. # the first return element is the variable to be passed as
  78. # an argument to an interface method. the variable was
  79. # declared with only its builtin indirection level. when
  80. # we pass it, we'll need to pass in whatever amount of
  81. # indirection was applied (plus the builtin amount)
  82. # the second return element is the variable declaration; it
  83. # should simply be builtin indirection
  84. return self.GetIndirectedArgName(
  85. self.builtinIndirection, self.arg.indirectionLevel + self.builtinIndirection
  86. ), "%s %s" % (self.GetUnconstType(), self.arg.name)
  87. def GetInterfaceArgCleanup(self):
  88. "Return cleanup code for C++ args passed to the interface method."
  89. if DEBUG:
  90. return "/* GetInterfaceArgCleanup output goes here: %s */\n" % self.arg.name
  91. else:
  92. return ""
  93. def GetInterfaceArgCleanupGIL(self):
  94. """Return cleanup code for C++ args passed to the interface
  95. method that must be executed with the GIL held"""
  96. if DEBUG:
  97. return (
  98. "/* GetInterfaceArgCleanup (GIL held) output goes here: %s */\n"
  99. % self.arg.name
  100. )
  101. else:
  102. return ""
  103. def GetUnconstType(self):
  104. return self.arg.unc_type
  105. def SetGatewayMode(self):
  106. self.gatewayMode = 1
  107. def _GetDeclaredIndirection(self):
  108. return self.arg.indirectionLevel
  109. print("declared:", self.arg.name, self.gatewayMode)
  110. if self.gatewayMode:
  111. return self.arg.indirectionLevel
  112. else:
  113. return self.declaredIndirection
  114. def DeclareParseArgTupleInputConverter(self):
  115. "Declare the variable used as the PyArg_ParseTuple param for a gateway"
  116. # Only declare it??
  117. # if self.arg.indirectionLevel==0:
  118. # return "\t%s %s;\n" % (self.arg.type, self.arg.name)
  119. # else:
  120. if DEBUG:
  121. return (
  122. "/* Declare ParseArgTupleInputConverter goes here: %s */\n"
  123. % self.arg.name
  124. )
  125. else:
  126. return ""
  127. def GetParsePostCode(self):
  128. "Get a string of C++ code to be executed after (ie, to finalise) the PyArg_ParseTuple conversion"
  129. if DEBUG:
  130. return "/* GetParsePostCode code goes here: %s */\n" % self.arg.name
  131. else:
  132. return ""
  133. def GetBuildForInterfacePreCode(self):
  134. "Get a string of C++ code to be executed before (ie, to initialise) the Py_BuildValue conversion for Interfaces"
  135. if DEBUG:
  136. return "/* GetBuildForInterfacePreCode goes here: %s */\n" % self.arg.name
  137. else:
  138. return ""
  139. def GetBuildForGatewayPreCode(self):
  140. "Get a string of C++ code to be executed before (ie, to initialise) the Py_BuildValue conversion for Gateways"
  141. s = self.GetBuildForInterfacePreCode() # Usually the same
  142. if DEBUG:
  143. if s[:4] == "/* G":
  144. s = "/* GetBuildForGatewayPreCode goes here: %s */\n" % self.arg.name
  145. return s
  146. def GetBuildForInterfacePostCode(self):
  147. "Get a string of C++ code to be executed after (ie, to finalise) the Py_BuildValue conversion for Interfaces"
  148. if DEBUG:
  149. return "/* GetBuildForInterfacePostCode goes here: %s */\n" % self.arg.name
  150. return ""
  151. def GetBuildForGatewayPostCode(self):
  152. "Get a string of C++ code to be executed after (ie, to finalise) the Py_BuildValue conversion for Gateways"
  153. s = self.GetBuildForInterfacePostCode() # Usually the same
  154. if DEBUG:
  155. if s[:4] == "/* G":
  156. s = "/* GetBuildForGatewayPostCode goes here: %s */\n" % self.arg.name
  157. return s
  158. def GetAutoduckString(self):
  159. return "// @pyparm %s|%s||Description for %s" % (
  160. self._GetPythonTypeDesc(),
  161. self.arg.name,
  162. self.arg.name,
  163. )
  164. def _GetPythonTypeDesc(self):
  165. "Returns a string with the description of the type. Used for doco purposes"
  166. return None
  167. def NeedUSES_CONVERSION(self):
  168. "Determines if this arg forces a USES_CONVERSION macro"
  169. return 0
  170. # Special formatter for floats since they're smaller than Python floats.
  171. class ArgFormatterFloat(ArgFormatter):
  172. def GetFormatChar(self):
  173. return "f"
  174. def DeclareParseArgTupleInputConverter(self):
  175. # Declare a double variable
  176. return "\tdouble dbl%s;\n" % self.arg.name
  177. def GetParseTupleArg(self):
  178. return "&dbl" + self.arg.name
  179. def _GetPythonTypeDesc(self):
  180. return "float"
  181. def GetBuildValueArg(self):
  182. return "&dbl" + self.arg.name
  183. def GetBuildForInterfacePreCode(self):
  184. return "\tdbl" + self.arg.name + " = " + self.arg.name + ";\n"
  185. def GetBuildForGatewayPreCode(self):
  186. return (
  187. "\tdbl%s = " % self.arg.name
  188. + self._IndirectPrefix(self._GetDeclaredIndirection(), 0)
  189. + self.arg.name
  190. + ";\n"
  191. )
  192. def GetParsePostCode(self):
  193. s = "\t"
  194. if self.gatewayMode:
  195. s = s + self._IndirectPrefix(self._GetDeclaredIndirection(), 0)
  196. s = s + self.arg.name
  197. s = s + " = (float)dbl%s;\n" % self.arg.name
  198. return s
  199. # Special formatter for Shorts because they're
  200. # a different size than Python ints!
  201. class ArgFormatterShort(ArgFormatter):
  202. def GetFormatChar(self):
  203. return "i"
  204. def DeclareParseArgTupleInputConverter(self):
  205. # Declare a double variable
  206. return "\tINT i%s;\n" % self.arg.name
  207. def GetParseTupleArg(self):
  208. return "&i" + self.arg.name
  209. def _GetPythonTypeDesc(self):
  210. return "int"
  211. def GetBuildValueArg(self):
  212. return "&i" + self.arg.name
  213. def GetBuildForInterfacePreCode(self):
  214. return "\ti" + self.arg.name + " = " + self.arg.name + ";\n"
  215. def GetBuildForGatewayPreCode(self):
  216. return (
  217. "\ti%s = " % self.arg.name
  218. + self._IndirectPrefix(self._GetDeclaredIndirection(), 0)
  219. + self.arg.name
  220. + ";\n"
  221. )
  222. def GetParsePostCode(self):
  223. s = "\t"
  224. if self.gatewayMode:
  225. s = s + self._IndirectPrefix(self._GetDeclaredIndirection(), 0)
  226. s = s + self.arg.name
  227. s = s + " = i%s;\n" % self.arg.name
  228. return s
  229. # for types which are 64bits on AMD64 - eg, HWND
  230. class ArgFormatterLONG_PTR(ArgFormatter):
  231. def GetFormatChar(self):
  232. return "O"
  233. def DeclareParseArgTupleInputConverter(self):
  234. # Declare a PyObject variable
  235. return "\tPyObject *ob%s;\n" % self.arg.name
  236. def GetParseTupleArg(self):
  237. return "&ob" + self.arg.name
  238. def _GetPythonTypeDesc(self):
  239. return "int/long"
  240. def GetBuildValueArg(self):
  241. return "ob" + self.arg.name
  242. def GetBuildForInterfacePostCode(self):
  243. return "\tPy_XDECREF(ob%s);\n" % self.arg.name
  244. def GetParsePostCode(self):
  245. return (
  246. "\tif (bPythonIsHappy && !PyWinLong_AsULONG_PTR(ob%s, (ULONG_PTR *)%s)) bPythonIsHappy = FALSE;\n"
  247. % (self.arg.name, self.GetIndirectedArgName(None, 2))
  248. )
  249. def GetBuildForInterfacePreCode(self):
  250. notdirected = self.GetIndirectedArgName(None, 1)
  251. return "\tob%s = PyWinObject_FromULONG_PTR(%s);\n" % (
  252. self.arg.name,
  253. notdirected,
  254. )
  255. def GetBuildForGatewayPostCode(self):
  256. return "\tPy_XDECREF(ob%s);\n" % self.arg.name
  257. class ArgFormatterPythonCOM(ArgFormatter):
  258. """An arg formatter for types exposed in the PythonCOM module"""
  259. def GetFormatChar(self):
  260. return "O"
  261. # def GetInterfaceCppObjectInfo(self):
  262. # return ArgFormatter.GetInterfaceCppObjectInfo(self)[0], \
  263. # "%s %s%s" % (self.arg.unc_type, "*" * self._GetDeclaredIndirection(), self.arg.name)
  264. def DeclareParseArgTupleInputConverter(self):
  265. # Declare a PyObject variable
  266. return "\tPyObject *ob%s;\n" % self.arg.name
  267. def GetParseTupleArg(self):
  268. return "&ob" + self.arg.name
  269. def _GetPythonTypeDesc(self):
  270. return "<o Py%s>" % self.arg.type
  271. def GetBuildValueArg(self):
  272. return "ob" + self.arg.name
  273. def GetBuildForInterfacePostCode(self):
  274. return "\tPy_XDECREF(ob%s);\n" % self.arg.name
  275. class ArgFormatterBSTR(ArgFormatterPythonCOM):
  276. def _GetPythonTypeDesc(self):
  277. return "<o unicode>"
  278. def GetParsePostCode(self):
  279. return (
  280. "\tif (bPythonIsHappy && !PyWinObject_AsBstr(ob%s, %s)) bPythonIsHappy = FALSE;\n"
  281. % (self.arg.name, self.GetIndirectedArgName(None, 2))
  282. )
  283. def GetBuildForInterfacePreCode(self):
  284. notdirected = self.GetIndirectedArgName(None, 1)
  285. return "\tob%s = MakeBstrToObj(%s);\n" % (self.arg.name, notdirected)
  286. def GetBuildForInterfacePostCode(self):
  287. return "\tSysFreeString(%s);\n" % (
  288. self.arg.name,
  289. ) + ArgFormatterPythonCOM.GetBuildForInterfacePostCode(self)
  290. def GetBuildForGatewayPostCode(self):
  291. return "\tPy_XDECREF(ob%s);\n" % self.arg.name
  292. class ArgFormatterOLECHAR(ArgFormatterPythonCOM):
  293. def _GetPythonTypeDesc(self):
  294. return "<o unicode>"
  295. def GetUnconstType(self):
  296. if self.arg.type[:3] == "LPC":
  297. return self.arg.type[:2] + self.arg.type[3:]
  298. else:
  299. return self.arg.unc_type
  300. def GetParsePostCode(self):
  301. return (
  302. "\tif (bPythonIsHappy && !PyWinObject_AsBstr(ob%s, %s)) bPythonIsHappy = FALSE;\n"
  303. % (self.arg.name, self.GetIndirectedArgName(None, 2))
  304. )
  305. def GetInterfaceArgCleanup(self):
  306. return "\tSysFreeString(%s);\n" % self.GetIndirectedArgName(None, 1)
  307. def GetBuildForInterfacePreCode(self):
  308. # the variable was declared with just its builtin indirection
  309. notdirected = self.GetIndirectedArgName(self.builtinIndirection, 1)
  310. return "\tob%s = MakeOLECHARToObj(%s);\n" % (self.arg.name, notdirected)
  311. def GetBuildForInterfacePostCode(self):
  312. # memory returned into an OLECHAR should be freed
  313. return "\tCoTaskMemFree(%s);\n" % (
  314. self.arg.name,
  315. ) + ArgFormatterPythonCOM.GetBuildForInterfacePostCode(self)
  316. def GetBuildForGatewayPostCode(self):
  317. return "\tPy_XDECREF(ob%s);\n" % self.arg.name
  318. class ArgFormatterTCHAR(ArgFormatterPythonCOM):
  319. def _GetPythonTypeDesc(self):
  320. return "string/<o unicode>"
  321. def GetUnconstType(self):
  322. if self.arg.type[:3] == "LPC":
  323. return self.arg.type[:2] + self.arg.type[3:]
  324. else:
  325. return self.arg.unc_type
  326. def GetParsePostCode(self):
  327. return (
  328. "\tif (bPythonIsHappy && !PyWinObject_AsTCHAR(ob%s, %s)) bPythonIsHappy = FALSE;\n"
  329. % (self.arg.name, self.GetIndirectedArgName(None, 2))
  330. )
  331. def GetInterfaceArgCleanup(self):
  332. return "\tPyWinObject_FreeTCHAR(%s);\n" % self.GetIndirectedArgName(None, 1)
  333. def GetBuildForInterfacePreCode(self):
  334. # the variable was declared with just its builtin indirection
  335. notdirected = self.GetIndirectedArgName(self.builtinIndirection, 1)
  336. return "\tob%s = PyWinObject_FromTCHAR(%s);\n" % (self.arg.name, notdirected)
  337. def GetBuildForInterfacePostCode(self):
  338. return "// ??? - TCHAR post code\n"
  339. def GetBuildForGatewayPostCode(self):
  340. return "\tPy_XDECREF(ob%s);\n" % self.arg.name
  341. class ArgFormatterIID(ArgFormatterPythonCOM):
  342. def _GetPythonTypeDesc(self):
  343. return "<o PyIID>"
  344. def GetParsePostCode(self):
  345. return "\tif (!PyWinObject_AsIID(ob%s, &%s)) bPythonIsHappy = FALSE;\n" % (
  346. self.arg.name,
  347. self.arg.name,
  348. )
  349. def GetBuildForInterfacePreCode(self):
  350. # notdirected = self.GetIndirectedArgName(self.arg.indirectionLevel, 0)
  351. notdirected = self.GetIndirectedArgName(None, 0)
  352. return "\tob%s = PyWinObject_FromIID(%s);\n" % (self.arg.name, notdirected)
  353. def GetInterfaceCppObjectInfo(self):
  354. return self.arg.name, "IID %s" % (self.arg.name)
  355. class ArgFormatterTime(ArgFormatterPythonCOM):
  356. def __init__(self, arg, builtinIndirection, declaredIndirection=0):
  357. # we don't want to declare LPSYSTEMTIME / LPFILETIME objects
  358. if arg.indirectionLevel == 0 and arg.unc_type[:2] == "LP":
  359. arg.unc_type = arg.unc_type[2:]
  360. # reduce the builtin and increment the declaration
  361. arg.indirectionLevel = arg.indirectionLevel + 1
  362. builtinIndirection = 0
  363. ArgFormatterPythonCOM.__init__(
  364. self, arg, builtinIndirection, declaredIndirection
  365. )
  366. def _GetPythonTypeDesc(self):
  367. return "<o PyDateTime>"
  368. def GetParsePostCode(self):
  369. # variable was declared with only the builtinIndirection
  370. ### NOTE: this is an [in] ... so use only builtin
  371. return (
  372. '\tif (!PyTime_Check(ob%s)) {\n\t\tPyErr_SetString(PyExc_TypeError, "The argument must be a PyTime object");\n\t\tbPythonIsHappy = FALSE;\n\t}\n\tif (!((PyTime *)ob%s)->GetTime(%s)) bPythonIsHappy = FALSE;\n'
  373. % (
  374. self.arg.name,
  375. self.arg.name,
  376. self.GetIndirectedArgName(self.builtinIndirection, 1),
  377. )
  378. )
  379. def GetBuildForInterfacePreCode(self):
  380. ### use just the builtinIndirection again...
  381. notdirected = self.GetIndirectedArgName(self.builtinIndirection, 0)
  382. return "\tob%s = new PyTime(%s);\n" % (self.arg.name, notdirected)
  383. def GetBuildForInterfacePostCode(self):
  384. ### hack to determine if we need to free stuff
  385. ret = ""
  386. if self.builtinIndirection + self.arg.indirectionLevel > 1:
  387. # memory returned into an OLECHAR should be freed
  388. ret = "\tCoTaskMemFree(%s);\n" % self.arg.name
  389. return ret + ArgFormatterPythonCOM.GetBuildForInterfacePostCode(self)
  390. class ArgFormatterSTATSTG(ArgFormatterPythonCOM):
  391. def _GetPythonTypeDesc(self):
  392. return "<o STATSTG>"
  393. def GetParsePostCode(self):
  394. return (
  395. "\tif (!PyCom_PyObjectAsSTATSTG(ob%s, %s, 0/*flags*/)) bPythonIsHappy = FALSE;\n"
  396. % (self.arg.name, self.GetIndirectedArgName(None, 1))
  397. )
  398. def GetBuildForInterfacePreCode(self):
  399. notdirected = self.GetIndirectedArgName(None, 1)
  400. return (
  401. "\tob%s = PyCom_PyObjectFromSTATSTG(%s);\n\t// STATSTG doco says our responsibility to free\n\tif ((%s).pwcsName) CoTaskMemFree((%s).pwcsName);\n"
  402. % (
  403. self.arg.name,
  404. self.GetIndirectedArgName(None, 1),
  405. notdirected,
  406. notdirected,
  407. )
  408. )
  409. class ArgFormatterGeneric(ArgFormatterPythonCOM):
  410. def _GetPythonTypeDesc(self):
  411. return "<o %s>" % self.arg.type
  412. def GetParsePostCode(self):
  413. return "\tif (!PyObject_As%s(ob%s, &%s) bPythonIsHappy = FALSE;\n" % (
  414. self.arg.type,
  415. self.arg.name,
  416. self.GetIndirectedArgName(None, 1),
  417. )
  418. def GetInterfaceArgCleanup(self):
  419. return "\tPyObject_Free%s(%s);\n" % (self.arg.type, self.arg.name)
  420. def GetBuildForInterfacePreCode(self):
  421. notdirected = self.GetIndirectedArgName(None, 1)
  422. return "\tob%s = PyObject_From%s(%s);\n" % (
  423. self.arg.name,
  424. self.arg.type,
  425. self.GetIndirectedArgName(None, 1),
  426. )
  427. class ArgFormatterIDLIST(ArgFormatterPythonCOM):
  428. def _GetPythonTypeDesc(self):
  429. return "<o PyIDL>"
  430. def GetParsePostCode(self):
  431. return (
  432. "\tif (bPythonIsHappy && !PyObject_AsPIDL(ob%s, &%s)) bPythonIsHappy = FALSE;\n"
  433. % (self.arg.name, self.GetIndirectedArgName(None, 1))
  434. )
  435. def GetInterfaceArgCleanup(self):
  436. return "\tPyObject_FreePIDL(%s);\n" % (self.arg.name,)
  437. def GetBuildForInterfacePreCode(self):
  438. notdirected = self.GetIndirectedArgName(None, 1)
  439. return "\tob%s = PyObject_FromPIDL(%s);\n" % (
  440. self.arg.name,
  441. self.GetIndirectedArgName(None, 1),
  442. )
  443. class ArgFormatterHANDLE(ArgFormatterPythonCOM):
  444. def _GetPythonTypeDesc(self):
  445. return "<o PyHANDLE>"
  446. def GetParsePostCode(self):
  447. return (
  448. "\tif (!PyWinObject_AsHANDLE(ob%s, &%s, FALSE) bPythonIsHappy = FALSE;\n"
  449. % (self.arg.name, self.GetIndirectedArgName(None, 1))
  450. )
  451. def GetBuildForInterfacePreCode(self):
  452. notdirected = self.GetIndirectedArgName(None, 1)
  453. return "\tob%s = PyWinObject_FromHANDLE(%s);\n" % (
  454. self.arg.name,
  455. self.GetIndirectedArgName(None, 0),
  456. )
  457. class ArgFormatterLARGE_INTEGER(ArgFormatterPythonCOM):
  458. def GetKeyName(self):
  459. return "LARGE_INTEGER"
  460. def _GetPythonTypeDesc(self):
  461. return "<o %s>" % self.GetKeyName()
  462. def GetParsePostCode(self):
  463. return "\tif (!PyWinObject_As%s(ob%s, %s)) bPythonIsHappy = FALSE;\n" % (
  464. self.GetKeyName(),
  465. self.arg.name,
  466. self.GetIndirectedArgName(None, 1),
  467. )
  468. def GetBuildForInterfacePreCode(self):
  469. notdirected = self.GetIndirectedArgName(None, 0)
  470. return "\tob%s = PyWinObject_From%s(%s);\n" % (
  471. self.arg.name,
  472. self.GetKeyName(),
  473. notdirected,
  474. )
  475. class ArgFormatterULARGE_INTEGER(ArgFormatterLARGE_INTEGER):
  476. def GetKeyName(self):
  477. return "ULARGE_INTEGER"
  478. class ArgFormatterInterface(ArgFormatterPythonCOM):
  479. def GetInterfaceCppObjectInfo(self):
  480. return self.GetIndirectedArgName(1, self.arg.indirectionLevel), "%s * %s" % (
  481. self.GetUnconstType(),
  482. self.arg.name,
  483. )
  484. def GetParsePostCode(self):
  485. # This gets called for out params in gateway mode
  486. if self.gatewayMode:
  487. sArg = self.GetIndirectedArgName(None, 2)
  488. else:
  489. # vs. in params for interface mode.
  490. sArg = self.GetIndirectedArgName(1, 2)
  491. return (
  492. "\tif (bPythonIsHappy && !PyCom_InterfaceFromPyInstanceOrObject(ob%s, IID_%s, (void **)%s, TRUE /* bNoneOK */))\n\t\t bPythonIsHappy = FALSE;\n"
  493. % (self.arg.name, self.arg.type, sArg)
  494. )
  495. def GetBuildForInterfacePreCode(self):
  496. return "\tob%s = PyCom_PyObjectFromIUnknown(%s, IID_%s, FALSE);\n" % (
  497. self.arg.name,
  498. self.arg.name,
  499. self.arg.type,
  500. )
  501. def GetBuildForGatewayPreCode(self):
  502. sPrefix = self._IndirectPrefix(self._GetDeclaredIndirection(), 1)
  503. return "\tob%s = PyCom_PyObjectFromIUnknown(%s%s, IID_%s, TRUE);\n" % (
  504. self.arg.name,
  505. sPrefix,
  506. self.arg.name,
  507. self.arg.type,
  508. )
  509. def GetInterfaceArgCleanup(self):
  510. return "\tif (%s) %s->Release();\n" % (self.arg.name, self.arg.name)
  511. class ArgFormatterVARIANT(ArgFormatterPythonCOM):
  512. def GetParsePostCode(self):
  513. return (
  514. "\tif ( !PyCom_VariantFromPyObject(ob%s, %s) )\n\t\tbPythonIsHappy = FALSE;\n"
  515. % (self.arg.name, self.GetIndirectedArgName(None, 1))
  516. )
  517. def GetBuildForGatewayPreCode(self):
  518. notdirected = self.GetIndirectedArgName(None, 1)
  519. return "\tob%s = PyCom_PyObjectFromVariant(%s);\n" % (
  520. self.arg.name,
  521. notdirected,
  522. )
  523. def GetBuildForGatewayPostCode(self):
  524. return "\tPy_XDECREF(ob%s);\n" % self.arg.name
  525. # Key : , Python Type Description, ParseTuple format char
  526. ConvertSimpleTypes = {
  527. "BOOL": ("BOOL", "int", "i"),
  528. "UINT": ("UINT", "int", "i"),
  529. "BYTE": ("BYTE", "int", "i"),
  530. "INT": ("INT", "int", "i"),
  531. "DWORD": ("DWORD", "int", "l"),
  532. "HRESULT": ("HRESULT", "int", "l"),
  533. "ULONG": ("ULONG", "int", "l"),
  534. "LONG": ("LONG", "int", "l"),
  535. "int": ("int", "int", "i"),
  536. "long": ("long", "int", "l"),
  537. "DISPID": ("DISPID", "long", "l"),
  538. "APPBREAKFLAGS": ("int", "int", "i"),
  539. "BREAKRESUMEACTION": ("int", "int", "i"),
  540. "ERRORRESUMEACTION": ("int", "int", "i"),
  541. "BREAKREASON": ("int", "int", "i"),
  542. "BREAKPOINT_STATE": ("int", "int", "i"),
  543. "BREAKRESUME_ACTION": ("int", "int", "i"),
  544. "SOURCE_TEXT_ATTR": ("int", "int", "i"),
  545. "TEXT_DOC_ATTR": ("int", "int", "i"),
  546. "QUERYOPTION": ("int", "int", "i"),
  547. "PARSEACTION": ("int", "int", "i"),
  548. }
  549. class ArgFormatterSimple(ArgFormatter):
  550. """An arg formatter for simple integer etc types"""
  551. def GetFormatChar(self):
  552. return ConvertSimpleTypes[self.arg.type][2]
  553. def _GetPythonTypeDesc(self):
  554. return ConvertSimpleTypes[self.arg.type][1]
  555. AllConverters = {
  556. "const OLECHAR": (ArgFormatterOLECHAR, 0, 1),
  557. "WCHAR": (ArgFormatterOLECHAR, 0, 1),
  558. "OLECHAR": (ArgFormatterOLECHAR, 0, 1),
  559. "LPCOLESTR": (ArgFormatterOLECHAR, 1, 1),
  560. "LPOLESTR": (ArgFormatterOLECHAR, 1, 1),
  561. "LPCWSTR": (ArgFormatterOLECHAR, 1, 1),
  562. "LPWSTR": (ArgFormatterOLECHAR, 1, 1),
  563. "LPCSTR": (ArgFormatterOLECHAR, 1, 1),
  564. "LPTSTR": (ArgFormatterTCHAR, 1, 1),
  565. "LPCTSTR": (ArgFormatterTCHAR, 1, 1),
  566. "HANDLE": (ArgFormatterHANDLE, 0),
  567. "BSTR": (ArgFormatterBSTR, 1, 0),
  568. "const IID": (ArgFormatterIID, 0),
  569. "CLSID": (ArgFormatterIID, 0),
  570. "IID": (ArgFormatterIID, 0),
  571. "GUID": (ArgFormatterIID, 0),
  572. "const GUID": (ArgFormatterIID, 0),
  573. "const IID": (ArgFormatterIID, 0),
  574. "REFCLSID": (ArgFormatterIID, 0),
  575. "REFIID": (ArgFormatterIID, 0),
  576. "REFGUID": (ArgFormatterIID, 0),
  577. "const FILETIME": (ArgFormatterTime, 0),
  578. "const SYSTEMTIME": (ArgFormatterTime, 0),
  579. "const LPSYSTEMTIME": (ArgFormatterTime, 1, 1),
  580. "LPSYSTEMTIME": (ArgFormatterTime, 1, 1),
  581. "FILETIME": (ArgFormatterTime, 0),
  582. "SYSTEMTIME": (ArgFormatterTime, 0),
  583. "STATSTG": (ArgFormatterSTATSTG, 0),
  584. "LARGE_INTEGER": (ArgFormatterLARGE_INTEGER, 0),
  585. "ULARGE_INTEGER": (ArgFormatterULARGE_INTEGER, 0),
  586. "VARIANT": (ArgFormatterVARIANT, 0),
  587. "float": (ArgFormatterFloat, 0),
  588. "single": (ArgFormatterFloat, 0),
  589. "short": (ArgFormatterShort, 0),
  590. "WORD": (ArgFormatterShort, 0),
  591. "VARIANT_BOOL": (ArgFormatterShort, 0),
  592. "HWND": (ArgFormatterLONG_PTR, 1),
  593. "HMENU": (ArgFormatterLONG_PTR, 1),
  594. "HOLEMENU": (ArgFormatterLONG_PTR, 1),
  595. "HICON": (ArgFormatterLONG_PTR, 1),
  596. "HDC": (ArgFormatterLONG_PTR, 1),
  597. "LPARAM": (ArgFormatterLONG_PTR, 1),
  598. "WPARAM": (ArgFormatterLONG_PTR, 1),
  599. "LRESULT": (ArgFormatterLONG_PTR, 1),
  600. "UINT": (ArgFormatterShort, 0),
  601. "SVSIF": (ArgFormatterShort, 0),
  602. "Control": (ArgFormatterInterface, 0, 1),
  603. "DataObject": (ArgFormatterInterface, 0, 1),
  604. "_PropertyBag": (ArgFormatterInterface, 0, 1),
  605. "AsyncProp": (ArgFormatterInterface, 0, 1),
  606. "DataSource": (ArgFormatterInterface, 0, 1),
  607. "DataFormat": (ArgFormatterInterface, 0, 1),
  608. "void **": (ArgFormatterInterface, 2, 2),
  609. "ITEMIDLIST": (ArgFormatterIDLIST, 0, 0),
  610. "LPITEMIDLIST": (ArgFormatterIDLIST, 0, 1),
  611. "LPCITEMIDLIST": (ArgFormatterIDLIST, 0, 1),
  612. "const ITEMIDLIST": (ArgFormatterIDLIST, 0, 1),
  613. }
  614. # Auto-add all the simple types
  615. for key in ConvertSimpleTypes.keys():
  616. AllConverters[key] = ArgFormatterSimple, 0
  617. def make_arg_converter(arg):
  618. try:
  619. clz = AllConverters[arg.type][0]
  620. bin = AllConverters[arg.type][1]
  621. decl = 0
  622. if len(AllConverters[arg.type]) > 2:
  623. decl = AllConverters[arg.type][2]
  624. return clz(arg, bin, decl)
  625. except KeyError:
  626. if arg.type[0] == "I":
  627. return ArgFormatterInterface(arg, 0, 1)
  628. raise error_not_supported(
  629. "The type '%s' (%s) is unknown." % (arg.type, arg.name)
  630. )
  631. #############################################################
  632. #
  633. # The instances that represent the args, methods and interface
  634. class Argument:
  635. """A representation of an argument to a COM method
  636. This class contains information about a specific argument to a method.
  637. In addition, methods exist so that an argument knows how to convert itself
  638. to/from Python arguments.
  639. """
  640. # in,out type name [ ]
  641. # -------------- -------- ------------ ------
  642. regex = re.compile(r"/\* \[([^\]]*.*?)] \*/[ \t](.*[* ]+)(\w+)(\[ *])?[\),]")
  643. def __init__(self, good_interface_names):
  644. self.good_interface_names = good_interface_names
  645. self.inout = self.name = self.type = None
  646. self.const = 0
  647. self.arrayDecl = 0
  648. def BuildFromFile(self, file):
  649. """Parse and build my data from a file
  650. Reads the next line in the file, and matches it as an argument
  651. description. If not a valid argument line, an error_not_found exception
  652. is raised.
  653. """
  654. line = file.readline()
  655. mo = self.regex.search(line)
  656. if not mo:
  657. raise error_not_found
  658. self.name = mo.group(3)
  659. self.inout = mo.group(1).split("][")
  660. typ = mo.group(2).strip()
  661. self.raw_type = typ
  662. self.indirectionLevel = 0
  663. if mo.group(4): # Has "[ ]" decl
  664. self.arrayDecl = 1
  665. try:
  666. pos = typ.rindex("__RPC_FAR")
  667. self.indirectionLevel = self.indirectionLevel + 1
  668. typ = typ[:pos].strip()
  669. except ValueError:
  670. pass
  671. typ = typ.replace("__RPC_FAR", "")
  672. while 1:
  673. try:
  674. pos = typ.rindex("*")
  675. self.indirectionLevel = self.indirectionLevel + 1
  676. typ = typ[:pos].strip()
  677. except ValueError:
  678. break
  679. self.type = typ
  680. if self.type[:6] == "const ":
  681. self.unc_type = self.type[6:]
  682. else:
  683. self.unc_type = self.type
  684. if VERBOSE:
  685. print(
  686. " Arg %s of type %s%s (%s)"
  687. % (self.name, self.type, "*" * self.indirectionLevel, self.inout)
  688. )
  689. def HasAttribute(self, typ):
  690. """Determines if the argument has the specific attribute.
  691. Argument attributes are specified in the header file, such as
  692. "[in][out][retval]" etc. You can pass a specific string (eg "out")
  693. to find if this attribute was specified for the argument
  694. """
  695. return typ in self.inout
  696. def GetRawDeclaration(self):
  697. ret = "%s %s" % (self.raw_type, self.name)
  698. if self.arrayDecl:
  699. ret = ret + "[]"
  700. return ret
  701. class Method:
  702. """A representation of a C++ method on a COM interface
  703. This class contains information about a specific method, as well as
  704. a list of all @Argument@s
  705. """
  706. # options ret type callconv name
  707. # ----------------- -------- -------- --------
  708. regex = re.compile(r"virtual (/\*.*?\*/ )?(.*?) (.*?) (.*?)\(\w?")
  709. def __init__(self, good_interface_names):
  710. self.good_interface_names = good_interface_names
  711. self.name = self.result = self.callconv = None
  712. self.args = []
  713. def BuildFromFile(self, file):
  714. """Parse and build my data from a file
  715. Reads the next line in the file, and matches it as a method
  716. description. If not a valid method line, an error_not_found exception
  717. is raised.
  718. """
  719. line = file.readline()
  720. mo = self.regex.search(line)
  721. if not mo:
  722. raise error_not_found
  723. self.name = mo.group(4)
  724. self.result = mo.group(2)
  725. if self.result != "HRESULT":
  726. if self.result == "DWORD": # DWORD is for old old stuff?
  727. print(
  728. "Warning: Old style interface detected - compilation errors likely!"
  729. )
  730. else:
  731. print(
  732. "Method %s - Only HRESULT return types are supported." % self.name
  733. )
  734. # raise error_not_supported, if VERBOSE:
  735. print(" Method %s %s(" % (self.result, self.name))
  736. while 1:
  737. arg = Argument(self.good_interface_names)
  738. try:
  739. arg.BuildFromFile(file)
  740. self.args.append(arg)
  741. except error_not_found:
  742. break
  743. class Interface:
  744. """A representation of a C++ COM Interface
  745. This class contains information about a specific interface, as well as
  746. a list of all @Method@s
  747. """
  748. # name base
  749. # -------- --------
  750. regex = re.compile("(interface|) ([^ ]*) : public (.*)$")
  751. def __init__(self, mo):
  752. self.methods = []
  753. self.name = mo.group(2)
  754. self.base = mo.group(3)
  755. if VERBOSE:
  756. print("Interface %s : public %s" % (self.name, self.base))
  757. def BuildMethods(self, file):
  758. """Build all sub-methods for this interface"""
  759. # skip the next 2 lines.
  760. file.readline()
  761. file.readline()
  762. while 1:
  763. try:
  764. method = Method([self.name])
  765. method.BuildFromFile(file)
  766. self.methods.append(method)
  767. except error_not_found:
  768. break
  769. def find_interface(interfaceName, file):
  770. """Find and return an interface in a file
  771. Given an interface name and file, search for the specified interface.
  772. Upon return, the interface itself has been built,
  773. but not the methods.
  774. """
  775. interface = None
  776. line = file.readline()
  777. while line:
  778. mo = Interface.regex.search(line)
  779. if mo:
  780. name = mo.group(2)
  781. print(name)
  782. AllConverters[name] = (ArgFormatterInterface, 0, 1)
  783. if name == interfaceName:
  784. interface = Interface(mo)
  785. interface.BuildMethods(file)
  786. line = file.readline()
  787. if interface:
  788. return interface
  789. raise error_not_found
  790. def parse_interface_info(interfaceName, file):
  791. """Find, parse and return an interface in a file
  792. Given an interface name and file, search for the specified interface.
  793. Upon return, the interface itself is fully built,
  794. """
  795. try:
  796. return find_interface(interfaceName, file)
  797. except re.error:
  798. traceback.print_exc()
  799. print("The interface could not be built, as the regular expression failed!")
  800. def test():
  801. f = open("d:\\msdev\\include\\objidl.h")
  802. try:
  803. parse_interface_info("IPersistStream", f)
  804. finally:
  805. f.close()
  806. def test_regex(r, text):
  807. res = r.search(text, 0)
  808. if res == -1:
  809. print("** Not found")
  810. else:
  811. print(
  812. "%d\n%s\n%s\n%s\n%s" % (res, r.group(1), r.group(2), r.group(3), r.group(4))
  813. )