0001 """Utilities for makegw - Parse a header file to build an interface 0002 0003 This module contains the core code for parsing a header file describing a 0004 COM interface, and building it into an "Interface" structure. 0005 0006 Each Interface has methods, and each method has arguments. 0007 0008 Each argument knows how to use Py_BuildValue or Py_ParseTuple to 0009 exchange itself with Python. 0010 0011 See the @win32com.makegw@ module for information in building a COM 0012 interface 0013 """ 0014 import regex 0015 import traceback 0016 import string 0017 0018 error_not_found = "The requested item could not be found" 0019 error_not_supported = "The required functionality is not supported" 0020 0021 VERBOSE=0 0022 DEBUG=0 0023 0024 ## NOTE : For interfaces as params to work correctly, you must 0025 ## make sure any PythonCOM extensions which expose the interface are loaded 0026 ## before generating. 0027 0028 0029 class ArgFormatter: 0030 """An instance for a specific type of argument. Knows how to convert itself""" 0031 def __init__(self, arg, builtinIndirection, declaredIndirection = 0): 0032 #print 'init:', arg.name, builtinIndirection, declaredIndirection, arg.indirectionLevel 0033 self.arg = arg 0034 self.builtinIndirection = builtinIndirection 0035 self.declaredIndirection = declaredIndirection 0036 self.gatewayMode = 0 0037 def _IndirectPrefix(self, indirectionFrom, indirectionTo): 0038 """Given the indirection level I was declared at (0=Normal, 1=*, 2=**) 0039 return a string prefix so I can pass to a function with the 0040 required indirection (where the default is the indirection of the method's param. 0041 0042 eg, assuming my arg has indirection level of 2, if this function was passed 1 0043 it would return "&", so that a variable declared with indirection of 1 0044 can be prefixed with this to turn it into the indirection level required of 2 0045 """ 0046 dif = indirectionFrom - indirectionTo 0047 if dif==0: 0048 return "" 0049 elif dif==-1: 0050 return "&" 0051 elif dif==1: 0052 return "*" 0053 else: 0054 return "??" 0055 raise error_not_supported, "Can't indirect this far - please fix me :-)" 0056 def GetIndirectedArgName(self, indirectFrom, indirectionTo): 0057 #print 'get:',self.arg.name, indirectFrom,self._GetDeclaredIndirection() + self.builtinIndirection, indirectionTo, self.arg.indirectionLevel 0058 0059 if indirectFrom is None: 0060 ### ACK! this does not account for [in][out] variables. 0061 ### when this method is called, we need to know which 0062 indirectFrom = self._GetDeclaredIndirection() + self.builtinIndirection 0063 0064 return self._IndirectPrefix(indirectFrom, indirectionTo) + self.arg.name 0065 def GetBuildValueArg(self): 0066 "Get the argument to be passes to Py_BuildValue" 0067 return self.arg.name 0068 def GetParseTupleArg(self): 0069 "Get the argument to be passed to PyArg_ParseTuple" 0070 if self.gatewayMode: 0071 # use whatever they were declared with 0072 return self.GetIndirectedArgName(None, 1) 0073 # local declarations have just their builtin indirection 0074 return self.GetIndirectedArgName(self.builtinIndirection, 1) 0075 def GetInterfaceCppObjectInfo(self): 0076 """Provide information about the C++ object used. 0077 0078 Simple variables (such as integers) can declare their type (eg an integer) 0079 and use it as the target of both PyArg_ParseTuple and the COM function itself. 0080 0081 More complex types require a PyObject * declared as the target of PyArg_ParseTuple, 0082 then some conversion routine to the C++ object which is actually passed to COM. 0083 0084 This method provides the name, and optionally the type of that C++ variable. 0085 If the type if provided, the caller will likely generate a variable declaration. 0086 The name must always be returned. 0087 0088 Result is a tuple of (variableName, [DeclareType|None|""]) 0089 """ 0090 0091 # the first return element is the variable to be passed as 0092 # an argument to an interface method. the variable was 0093 # declared with only its builtin indirection level. when 0094 # we pass it, we'll need to pass in whatever amount of 0095 # indirection was applied (plus the builtin amount) 0096 # the second return element is the variable declaration; it 0097 # should simply be builtin indirection 0098 return self.GetIndirectedArgName(self.builtinIndirection, self.arg.indirectionLevel + self.builtinIndirection), \ 0099 "%s %s" % (self.GetUnconstType(), self.arg.name) 0100 0101 def GetInterfaceArgCleanup(self): 0102 "Return cleanup code for C++ args passed to the interface method." 0103 if DEBUG: 0104 return "/* GetInterfaceArgCleanup output goes here: %s */\n" % self.arg.name 0105 else: 0106 return "" 0107 0108 def GetInterfaceArgCleanupGIL(self): 0109 """Return cleanup code for C++ args passed to the interface 0110 method that must be executed with the GIL held""" 0111 if DEBUG: 0112 return "/* GetInterfaceArgCleanup (GIL held) output goes here: %s */\n" % self.arg.name 0113 else: 0114 return "" 0115 0116 def GetUnconstType(self): 0117 return self.arg.unc_type 0118 0119 def SetGatewayMode(self): 0120 self.gatewayMode = 1 0121 def _GetDeclaredIndirection(self): 0122 return self.arg.indirectionLevel 0123 print 'declared:', self.arg.name, self.gatewayMode 0124 if self.gatewayMode: 0125 return self.arg.indirectionLevel 0126 else: 0127 return self.declaredIndirection 0128 def DeclareParseArgTupleInputConverter(self): 0129 "Declare the variable used as the PyArg_ParseTuple param for a gateway" 0130 # Only declare it?? 0131 #if self.arg.indirectionLevel==0: 0132 # return "\t%s %s;\n" % (self.arg.type, self.arg.name) 0133 #else: 0134 if DEBUG: 0135 return "/* Declare ParseArgTupleInputConverter goes here: %s */\n" % self.arg.name 0136 else: 0137 return "" 0138 def GetParsePostCode(self): 0139 "Get a string of C++ code to be executed after (ie, to finalise) the PyArg_ParseTuple conversion" 0140 if DEBUG: 0141 return "/* GetParsePostCode code goes here: %s */\n" % self.arg.name 0142 else: 0143 return "" 0144 def GetBuildForInterfacePreCode(self): 0145 "Get a string of C++ code to be executed before (ie, to initialise) the Py_BuildValue conversion for Interfaces" 0146 if DEBUG: 0147 return "/* GetBuildForInterfacePreCode goes here: %s */\n" % self.arg.name 0148 else: 0149 return "" 0150 def GetBuildForGatewayPreCode(self): 0151 "Get a string of C++ code to be executed before (ie, to initialise) the Py_BuildValue conversion for Gateways" 0152 s = self.GetBuildForInterfacePreCode() # Usually the same 0153 if DEBUG: 0154 if s[:4] == "/* G": 0155 s = "/* GetBuildForGatewayPreCode goes here: %s */\n" % self.arg.name 0156 return s 0157 def GetBuildForInterfacePostCode(self): 0158 "Get a string of C++ code to be executed after (ie, to finalise) the Py_BuildValue conversion for Interfaces" 0159 if DEBUG: 0160 return "/* GetBuildForInterfacePostCode goes here: %s */\n" % self.arg.name 0161 return "" 0162 def GetBuildForGatewayPostCode(self): 0163 "Get a string of C++ code to be executed after (ie, to finalise) the Py_BuildValue conversion for Gateways" 0164 s = self.GetBuildForInterfacePostCode() # Usually the same 0165 if DEBUG: 0166 if s[:4] == "/* G": 0167 s = "/* GetBuildForGatewayPostCode goes here: %s */\n" % self.arg.name 0168 return s 0169 def GetAutoduckString(self): 0170 return '// @pyparm %s|%s||Description for %s' % (self._GetPythonTypeDesc(), self.arg.name, self.arg.name) 0171 def _GetPythonTypeDesc(self): 0172 "Returns a string with the description of the type. Used for doco purposes" 0173 return None 0174 def NeedUSES_CONVERSION(self): 0175 "Determines if this arg forces a USES_CONVERSION macro" 0176 return 0 0177 0178 # Special formatter for floats since they're smaller than Python floats. 0179 class ArgFormatterFloat(ArgFormatter): 0180 def GetFormatChar(self): 0181 return "f" 0182 def DeclareParseArgTupleInputConverter(self): 0183 # Declare a double variable 0184 return "\tdouble dbl%s;\n" % self.arg.name 0185 def GetParseTupleArg(self): 0186 return "&dbl" + self.arg.name 0187 def _GetPythonTypeDesc(self): 0188 return "float" 0189 def GetBuildValueArg(self): 0190 return "&dbl" + self.arg.name 0191 def GetBuildForInterfacePreCode(self): 0192 return "\tdbl" + self.arg.name + " = " + self.arg.name + ";\n" 0193 def GetBuildForGatewayPreCode(self): 0194 return "\tdbl%s = " % self.arg.name + self._IndirectPrefix( \ 0195 self._GetDeclaredIndirection(), 0196 0) + self.arg.name + ";\n" 0197 def GetParsePostCode(self): 0198 s = "\t" 0199 if self.gatewayMode: 0200 s = s + self._IndirectPrefix( 0201 self._GetDeclaredIndirection(), 0202 0) 0203 s = s + self.arg.name 0204 s = s + " = (float)dbl%s;\n" % self.arg.name 0205 return s 0206 0207 # Special formatter for Shorts because they're 0208 # a different size than Python ints! 0209 class ArgFormatterShort(ArgFormatter): 0210 def GetFormatChar(self): 0211 return "i" 0212 def DeclareParseArgTupleInputConverter(self): 0213 # Declare a double variable 0214 return "\tINT i%s;\n" % self.arg.name 0215 def GetParseTupleArg(self): 0216 return "&i" + self.arg.name 0217 def _GetPythonTypeDesc(self): 0218 return "int" 0219 def GetBuildValueArg(self): 0220 return "&i" + self.arg.name 0221 def GetBuildForInterfacePreCode(self): 0222 return "\ti" + self.arg.name + " = " + self.arg.name + ";\n" 0223 def GetBuildForGatewayPreCode(self): 0224 return "\ti%s = " % self.arg.name + self._IndirectPrefix( \ 0225 self._GetDeclaredIndirection(), 0226 0) + self.arg.name + ";\n" 0227 def GetParsePostCode(self): 0228 s = "\t" 0229 if self.gatewayMode: 0230 s = s + self._IndirectPrefix( 0231 self._GetDeclaredIndirection(), 0232 0) 0233 s = s + self.arg.name 0234 s = s + " = i%s;\n" % self.arg.name 0235 return s 0236 0237 class ArgFormatterPythonCOM(ArgFormatter): 0238 """An arg formatter for types exposed in the PythonCOM module""" 0239 def GetFormatChar(self): 0240 return "O" 0241 #def GetInterfaceCppObjectInfo(self): 0242 # return ArgFormatter.GetInterfaceCppObjectInfo(self)[0], \ 0243 # "%s %s%s" % (self.arg.unc_type, "*" * self._GetDeclaredIndirection(), self.arg.name) 0244 def DeclareParseArgTupleInputConverter(self): 0245 # Declare a PyObject variable 0246 return "\tPyObject *ob%s;\n" % self.arg.name 0247 def GetParseTupleArg(self): 0248 return "&ob"+self.arg.name 0249 def _GetPythonTypeDesc(self): 0250 return "<o Py%s>" % self.arg.type 0251 def GetBuildValueArg(self): 0252 return "ob" + self.arg.name 0253 def GetBuildForInterfacePostCode(self): 0254 return "\tPy_XDECREF(ob%s);\n" % self.arg.name 0255 def DeclareParseArgTupleInputConverter(self): 0256 # Declare a PyObject variable 0257 return "\tPyObject *ob%s;\n" % self.arg.name 0258 0259 class ArgFormatterBSTR(ArgFormatterPythonCOM): 0260 def _GetPythonTypeDesc(self): 0261 return "<o unicode>" 0262 def GetParsePostCode(self): 0263 return "\tif (bPythonIsHappy && !PyWinObject_AsBstr(ob%s, %s)) bPythonIsHappy = FALSE;\n" % (self.arg.name, self.GetIndirectedArgName(None, 2)) 0264 def GetBuildForInterfacePreCode(self): 0265 notdirected = self.GetIndirectedArgName(None, 1) 0266 return "\tob%s = MakeBstrToObj(%s);\n" % \ 0267 (self.arg.name, notdirected) 0268 def GetBuildForInterfacePostCode(self): 0269 return "\tSysFreeString(%s);\n" % (self.arg.name,) + \ 0270 ArgFormatterPythonCOM.GetBuildForInterfacePostCode(self) 0271 def GetBuildForGatewayPostCode(self): 0272 return "\tPy_XDECREF(ob%s);\n" % self.arg.name 0273 0274 class ArgFormatterOLECHAR(ArgFormatterPythonCOM): 0275 def _GetPythonTypeDesc(self): 0276 return "<o unicode>" 0277 def GetUnconstType(self): 0278 if self.arg.type[:3]=="LPC": 0279 return self.arg.type[:2] + self.arg.type[3:] 0280 else: 0281 return self.arg.unc_type 0282 def GetParsePostCode(self): 0283 return "\tif (bPythonIsHappy && !PyWinObject_AsBstr(ob%s, %s)) bPythonIsHappy = FALSE;\n" % (self.arg.name, self.GetIndirectedArgName(None, 2)) 0284 def GetInterfaceArgCleanup(self): 0285 return "\tSysFreeString(%s);\n" % self.GetIndirectedArgName(None, 1) 0286 def GetBuildForInterfacePreCode(self): 0287 # the variable was declared with just its builtin indirection 0288 notdirected = self.GetIndirectedArgName(self.builtinIndirection, 1) 0289 return "\tob%s = MakeOLECHARToObj(%s);\n" % \ 0290 (self.arg.name, notdirected) 0291 def GetBuildForInterfacePostCode(self): 0292 # memory returned into an OLECHAR should be freed 0293 return "\tCoTaskMemFree(%s);\n" % (self.arg.name,) + \ 0294 ArgFormatterPythonCOM.GetBuildForInterfacePostCode(self) 0295 def GetBuildForGatewayPostCode(self): 0296 return "\tPy_XDECREF(ob%s);\n" % self.arg.name 0297 0298 class ArgFormatterTCHAR(ArgFormatterPythonCOM): 0299 def _GetPythonTypeDesc(self): 0300 return "string/<o unicode>" 0301 def GetUnconstType(self): 0302 if self.arg.type[:3]=="LPC": 0303 return self.arg.type[:2] + self.arg.type[3:] 0304 else: 0305 return self.arg.unc_type 0306 def GetParsePostCode(self): 0307 return "\tif (bPythonIsHappy && !PyWinObject_AsTCHAR(ob%s, %s)) bPythonIsHappy = FALSE;\n" % (self.arg.name, self.GetIndirectedArgName(None, 2)) 0308 def GetInterfaceArgCleanup(self): 0309 return "\tPyWinObject_FreeTCHAR(%s);\n" % self.GetIndirectedArgName(None, 1) 0310 def GetBuildForInterfacePreCode(self): 0311 # the variable was declared with just its builtin indirection 0312 notdirected = self.GetIndirectedArgName(self.builtinIndirection, 1) 0313 return "\tob%s = PyWinObject_FromTCHAR(%s);\n" % \ 0314 (self.arg.name, notdirected) 0315 def GetBuildForInterfacePostCode(self): 0316 return "// ??? - TCHAR post code\n" 0317 def GetBuildForGatewayPostCode(self): 0318 return "\tPy_XDECREF(ob%s);\n" % self.arg.name 0319 0320 class ArgFormatterIID(ArgFormatterPythonCOM): 0321 def _GetPythonTypeDesc(self): 0322 return "<o PyIID>" 0323 def GetParsePostCode(self): 0324 return "\tif (!PyWinObject_AsIID(ob%s, &%s)) bPythonIsHappy = FALSE;\n" % (self.arg.name, self.arg.name) 0325 def GetBuildForInterfacePreCode(self): 0326 # notdirected = self.GetIndirectedArgName(self.arg.indirectionLevel, 0) 0327 notdirected = self.GetIndirectedArgName(None, 0) 0328 return "\tob%s = PyWinObject_FromIID(%s);\n" % (self.arg.name, notdirected) 0329 def GetInterfaceCppObjectInfo(self): 0330 return self.arg.name, "IID %s" % (self.arg.name) 0331 0332 class ArgFormatterTime(ArgFormatterPythonCOM): 0333 def __init__(self, arg, builtinIndirection, declaredIndirection = 0): 0334 # we don't want to declare LPSYSTEMTIME / LPFILETIME objects 0335 if arg.indirectionLevel == 0 and arg.unc_type[:2] == "LP": 0336 arg.unc_type = arg.unc_type[2:] 0337 # reduce the builtin and increment the declaration 0338 arg.indirectionLevel = arg.indirectionLevel + 1 0339 builtinIndirection = 0 0340 ArgFormatterPythonCOM.__init__(self, arg, builtinIndirection, declaredIndirection) 0341 0342 def _GetPythonTypeDesc(self): 0343 return "<o PyTime>" 0344 def GetParsePostCode(self): 0345 # variable was declared with only the builtinIndirection 0346 ### NOTE: this is an [in] ... so use only builtin 0347 return '\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' % (self.arg.name, self.arg.name, self.GetIndirectedArgName(self.builtinIndirection, 1)) 0348 def GetBuildForInterfacePreCode(self): 0349 ### use just the builtinIndirection again... 0350 notdirected = self.GetIndirectedArgName(self.builtinIndirection,0) 0351 return "\tob%s = new PyTime(%s);\n" % (self.arg.name, notdirected) 0352 def GetBuildForInterfacePostCode(self): 0353 ### hack to determine if we need to free stuff 0354 ret = '' 0355 if self.builtinIndirection + self.arg.indirectionLevel > 1: 0356 # memory returned into an OLECHAR should be freed 0357 ret = "\tCoTaskMemFree(%s);\n" % self.arg.name 0358 return ret + ArgFormatterPythonCOM.GetBuildForInterfacePostCode(self) 0359 0360 class ArgFormatterSTATSTG(ArgFormatterPythonCOM): 0361 def _GetPythonTypeDesc(self): 0362 return "<o STATSTG>" 0363 def GetParsePostCode(self): 0364 return '\tif (!PyCom_PyObjectAsSTATSTG(ob%s, %s, 0/*flags*/)) bPythonIsHappy = FALSE;\n' % (self.arg.name, self.GetIndirectedArgName(None, 1)) 0365 def GetBuildForInterfacePreCode(self): 0366 notdirected = self.GetIndirectedArgName(None, 1) 0367 return "\tob%s = PyCom_PyObjectFromSTATSTG(%s);\n\t// STATSTG doco says our responsibility to free\n\tif ((%s).pwcsName) CoTaskMemFree((%s).pwcsName);\n" % (self.arg.name, self.GetIndirectedArgName(None, 1),notdirected,notdirected) 0368 0369 class ArgFormatterGeneric(ArgFormatterPythonCOM): 0370 def _GetPythonTypeDesc(self): 0371 return "<o %s>" % self.arg.type 0372 def GetParsePostCode(self): 0373 return '\tif (!PyObject_As%s(ob%s, &%s) bPythonIsHappy = FALSE;\n' % (self.arg.type, self.arg.name, self.GetIndirectedArgName(None, 1)) 0374 def GetInterfaceArgCleanup(self): 0375 return '\tPyObject_Free%s(%s);\n' % (self.arg.type, self.arg.name) 0376 def GetBuildForInterfacePreCode(self): 0377 notdirected = self.GetIndirectedArgName(None, 1) 0378 return "\tob%s = PyObject_From%s(%s);\n" % (self.arg.name, self.arg.type, self.GetIndirectedArgName(None, 1)) 0379 0380 class ArgFormatterIDLIST(ArgFormatterPythonCOM): 0381 def _GetPythonTypeDesc(self): 0382 return "<o PyIDL>" 0383 def GetParsePostCode(self): 0384 return '\tif (bPythonIsHappy && !PyObject_AsPIDL(ob%s, &%s)) bPythonIsHappy = FALSE;\n' % (self.arg.name, self.GetIndirectedArgName(None, 1)) 0385 def GetInterfaceArgCleanup(self): 0386 return '\tPyObject_FreePIDL(%s);\n' % (self.arg.name,) 0387 def GetBuildForInterfacePreCode(self): 0388 notdirected = self.GetIndirectedArgName(None, 1) 0389 return "\tob%s = PyObject_FromPIDL(%s);\n" % (self.arg.name, self.GetIndirectedArgName(None, 1)) 0390 0391 class ArgFormatterHANDLE(ArgFormatterPythonCOM): 0392 def _GetPythonTypeDesc(self): 0393 return "<o PyHANDLE>" 0394 def GetParsePostCode(self): 0395 return '\tif (!PyWinObject_AsHANDLE(ob%s, &%s, FALSE) bPythonIsHappy = FALSE;\n' % (self.arg.name, self.GetIndirectedArgName(None, 1)) 0396 def GetBuildForInterfacePreCode(self): 0397 notdirected = self.GetIndirectedArgName(None, 1) 0398 return "\tob%s = PyWinObject_FromHANDLE(%s);\n" % (self.arg.name, self.GetIndirectedArgName(None, 0)) 0399 0400 class ArgFormatterLARGE_INTEGER(ArgFormatterPythonCOM): 0401 def GetKeyName(self): 0402 return "LARGE_INTEGER" 0403 def _GetPythonTypeDesc(self): 0404 return "<o %s>" % self.GetKeyName() 0405 def GetParsePostCode(self): 0406 return '\tif (!PyWinObject_As%s(ob%s, %s)) bPythonIsHappy = FALSE;\n' % (self.GetKeyName(), self.arg.name, self.GetIndirectedArgName(None, 1)) 0407 def GetBuildForInterfacePreCode(self): 0408 notdirected = self.GetIndirectedArgName(None, 0) 0409 return "\tob%s = PyWinObject_From%s(%s);\n" % (self.arg.name, self.GetKeyName(), notdirected) 0410 0411 class ArgFormatterULARGE_INTEGER(ArgFormatterLARGE_INTEGER): 0412 def GetKeyName(self): 0413 return "ULARGE_INTEGER" 0414 0415 class ArgFormatterInterface(ArgFormatterPythonCOM): 0416 def GetInterfaceCppObjectInfo(self): 0417 return self.GetIndirectedArgName(1, self.arg.indirectionLevel), \ 0418 "%s * %s" % (self.GetUnconstType(), self.arg.name) 0419 0420 def GetParsePostCode(self): 0421 # This gets called for out params in gateway mode 0422 if self.gatewayMode: 0423 sArg = self.GetIndirectedArgName(None, 2) 0424 else: 0425 # vs. in params for interface mode. 0426 sArg = self.GetIndirectedArgName(1, 2) 0427 return "\tif (bPythonIsHappy && !PyCom_InterfaceFromPyInstanceOrObject(ob%s, IID_%s, (void **)%s, TRUE /* bNoneOK */))\n\t\t bPythonIsHappy = FALSE;\n" % (self.arg.name, self.arg.type, sArg) 0428 0429 def GetBuildForInterfacePreCode(self): 0430 return "\tob%s = PyCom_PyObjectFromIUnknown(%s, IID_%s, FALSE);\n" % (self.arg.name, self.arg.name, self.arg.type) 0431 0432 def GetBuildForGatewayPreCode(self): 0433 sPrefix = self._IndirectPrefix(self._GetDeclaredIndirection(), 1) 0434 return "\tob%s = PyCom_PyObjectFromIUnknown(%s%s, IID_%s, TRUE);\n" % (self.arg.name, sPrefix, self.arg.name, self.arg.type) 0435 0436 def GetInterfaceArgCleanup(self): 0437 return "\tif (%s) %s->Release();\n" % (self.arg.name, self.arg.name) 0438 0439 class ArgFormatterVARIANT(ArgFormatterPythonCOM): 0440 def GetParsePostCode(self): 0441 return "\tif ( !PyCom_VariantFromPyObject(ob%s, %s) )\n\t\tbPythonIsHappy = FALSE;\n" % (self.arg.name, self.GetIndirectedArgName(None, 1)) 0442 0443 def GetBuildForGatewayPreCode(self): 0444 notdirected = self.GetIndirectedArgName(None, 1) 0445 return "\tob%s = PyCom_PyObjectFromVariant(%s);\n" % (self.arg.name, notdirected) 0446 def GetBuildForGatewayPostCode(self): 0447 return "\tPy_XDECREF(ob%s);\n" % self.arg.name 0448 0449 # Key : , Python Type Description, ParseTuple format char 0450 ConvertSimpleTypes = {"BOOL":("BOOL", "int", "i"), 0451 "UINT":("UINT", "int", "i"), 0452 "BYTE": ("BYTE", "int", "i"), 0453 "INT": ("INT", "int", "i"), 0454 "DWORD": ("DWORD", "int", "l"), 0455 "HRESULT":("HRESULT", "int", "l"), 0456 "ULONG": ("ULONG", "int", "l"), 0457 "LONG": ("LONG", "int", "l"), 0458 "int": ("int", "int", "i"), 0459 "long": ("long", "int", "l"), 0460 "HWND": ("HWND", "HWND", "l"), 0461 "HDC": ("HDC", "HDC", "l"), 0462 "LPARAM" : ("LPARAM", "long", "l"), 0463 "LRESULT" : ("LRESULT", "long", "l"), 0464 "WPARAM" : ("LPARAM", "int", "i"), 0465 "DISPID": ("DISPID", "long", "l"), 0466 "APPBREAKFLAGS": ("int", "int", "i"), 0467 "BREAKRESUMEACTION": ("int", "int", "i"), 0468 "ERRORRESUMEACTION": ("int", "int", "i"), 0469 "BREAKREASON": ("int", "int", "i"), 0470 "BREAKPOINT_STATE": ("int", "int", "i"), 0471 "BREAKRESUME_ACTION": ("int", "int", "i"), 0472 "SOURCE_TEXT_ATTR": ("int", "int", "i"), 0473 "TEXT_DOC_ATTR": ("int", "int", "i"), 0474 "QUERYOPTION": ("int", "int", "i"), 0475 "PARSEACTION": ("int", "int", "i"), 0476 } 0477 0478 class ArgFormatterSimple(ArgFormatter): 0479 """An arg formatter for simple integer etc types""" 0480 def GetFormatChar(self): 0481 return ConvertSimpleTypes[self.arg.type][2] 0482 def _GetPythonTypeDesc(self): 0483 return ConvertSimpleTypes[self.arg.type][1] 0484 0485 AllConverters = {"const OLECHAR": (ArgFormatterOLECHAR, 0, 1), 0486 "WCHAR": (ArgFormatterOLECHAR, 0, 1), 0487 "OLECHAR": (ArgFormatterOLECHAR, 0, 1), 0488 "LPCOLESTR": (ArgFormatterOLECHAR, 1, 1), 0489 "LPOLESTR": (ArgFormatterOLECHAR, 1, 1), 0490 "LPCWSTR": (ArgFormatterOLECHAR, 1, 1), 0491 "LPWSTR": (ArgFormatterOLECHAR, 1, 1), 0492 "LPCSTR": (ArgFormatterOLECHAR, 1, 1), 0493 "LPTSTR": (ArgFormatterTCHAR, 1, 1), 0494 "LPCTSTR": (ArgFormatterTCHAR, 1, 1), 0495 "HANDLE": (ArgFormatterHANDLE, 0), 0496 "BSTR": (ArgFormatterBSTR, 1, 0), 0497 "const IID": (ArgFormatterIID, 0), 0498 "CLSID": (ArgFormatterIID, 0), 0499 "IID": (ArgFormatterIID, 0), 0500 "GUID": (ArgFormatterIID, 0), 0501 "const GUID": (ArgFormatterIID, 0), 0502 "const IID": (ArgFormatterIID, 0), 0503 "REFCLSID": (ArgFormatterIID, 0), 0504 "REFIID": (ArgFormatterIID, 0), 0505 "REFGUID": (ArgFormatterIID, 0), 0506 "const FILETIME": (ArgFormatterTime, 0), 0507 "const SYSTEMTIME":(ArgFormatterTime, 0), 0508 "const LPSYSTEMTIME":(ArgFormatterTime, 1, 1), 0509 "LPSYSTEMTIME": (ArgFormatterTime, 1, 1), 0510 "FILETIME": (ArgFormatterTime, 0), 0511 "SYSTEMTIME": (ArgFormatterTime, 0), 0512 "STATSTG": (ArgFormatterSTATSTG, 0), 0513 "LARGE_INTEGER": (ArgFormatterLARGE_INTEGER, 0), 0514 "ULARGE_INTEGER": (ArgFormatterULARGE_INTEGER, 0), 0515 "VARIANT": (ArgFormatterVARIANT, 0), 0516 "float": (ArgFormatterFloat, 0), 0517 "single": (ArgFormatterFloat, 0), 0518 "short": (ArgFormatterShort, 0), 0519 "WORD": (ArgFormatterShort, 0), 0520 "VARIANT_BOOL": (ArgFormatterShort, 0), 0521 "HWND": (ArgFormatterShort, 0), 0522 "HMENU": (ArgFormatterShort, 0), 0523 "HOLEMENU": (ArgFormatterShort, 0), 0524 "HICON": (ArgFormatterShort, 0), 0525 "UINT": (ArgFormatterShort, 0), 0526 "SVSIF": (ArgFormatterShort, 0), 0527 "Control": (ArgFormatterInterface, 0, 1), 0528 "DataObject": (ArgFormatterInterface, 0, 1), 0529 "_PropertyBag": (ArgFormatterInterface, 0, 1), 0530 "AsyncProp": (ArgFormatterInterface, 0, 1), 0531 "DataSource": (ArgFormatterInterface, 0, 1), 0532 "DataFormat": (ArgFormatterInterface, 0, 1), 0533 "void **": (ArgFormatterInterface, 2, 2), 0534 "ITEMIDLIST": (ArgFormatterIDLIST, 0, 0), 0535 "LPITEMIDLIST": (ArgFormatterIDLIST, 0, 1), 0536 "LPCITEMIDLIST": (ArgFormatterIDLIST, 0, 1), 0537 "const ITEMIDLIST": (ArgFormatterIDLIST, 0, 1), 0538 } 0539 0540 # Auto-add all the simple types 0541 for key in ConvertSimpleTypes.keys(): 0542 AllConverters[key] = ArgFormatterSimple, 0 0543 0544 def make_arg_converter(arg): 0545 try: 0546 clz = AllConverters[arg.type][0] 0547 bin = AllConverters[arg.type][1] 0548 decl = 0 0549 if len(AllConverters[arg.type])>2: 0550 decl = AllConverters[arg.type][2] 0551 return clz(arg,bin, decl) 0552 except KeyError: 0553 if arg.type[0]=="I": 0554 return ArgFormatterInterface(arg, 0, 1) 0555 0556 raise error_not_supported, "The type '%s' (%s) is unknown." % (arg.type, arg.name) 0557 0558 0559 ############################################################# 0560 # 0561 # The instances that represent the args, methods and interface 0562 class Argument: 0563 """A representation of an argument to a COM method 0564 0565 This class contains information about a specific argument to a method. 0566 In addition, methods exist so that an argument knows how to convert itself 0567 to/from Python arguments. 0568 """ 0569 # in,out type name [ ] 0570 # -------------- -------- ------------ ------ 0571 regex = regex.compile('/\\* \\[\\([^\\]]*.*\\)] \\*/[ \t]\\(.*[\\* ]\\)\\([a-zA-Z0-9]+\\)\\(\\[ *]\\)?[),]') 0572 def __init__(self, good_interface_names): 0573 self.good_interface_names = good_interface_names 0574 self.inout = self.name = self.type = None 0575 self.const = 0 0576 self.arrayDecl = 0 0577 def BuildFromFile(self, file): 0578 """Parse and build my data from a file 0579 0580 Reads the next line in the file, and matches it as an argument 0581 description. If not a valid argument line, an error_not_found exception 0582 is raised. 0583 """ 0584 line = file.readline() 0585 if self.regex.search(line)<0: 0586 raise error_not_found 0587 self.name = self.regex.group(3) 0588 self.inout = string.split(self.regex.group(1),'][') 0589 typ = string.strip(self.regex.group(2)) 0590 self.raw_type = typ 0591 self.indirectionLevel = 0 0592 if self.regex.group(4): # Has "[ ]" decl 0593 self.arrayDecl = 1 0594 try: 0595 pos = string.rindex(typ, "__RPC_FAR") 0596 self.indirectionLevel = self.indirectionLevel + 1 0597 typ = string.strip(typ[:pos]) 0598 except ValueError: 0599 pass 0600 0601 while 1: 0602 try: 0603 pos = string.rindex(typ, "__RPC_FAR *") 0604 self.indirectionLevel = self.indirectionLevel + 1 0605 typ = string.strip(typ[:pos]) 0606 except ValueError: 0607 break 0608 self.type = typ 0609 if self.type[:6]=="const ": 0610 self.unc_type = self.type[6:] 0611 else: 0612 self.unc_type = self.type 0613 0614 if VERBOSE: 0615 print " Arg %s of type %s%s (%s)" % (self.name, self.type, "*" * self.indirectionLevel, self.inout) 0616 0617 def HasAttribute(self, typ): 0618 """Determines if the argument has the specific attribute. 0619 0620 Argument attributes are specified in the header file, such as 0621 "[in][out][retval]" etc. You can pass a specific string (eg "out") 0622 to find if this attribute was specified for the argument 0623 """ 0624 return typ in self.inout 0625 0626 def GetRawDeclaration(self): 0627 ret = "%s %s" % (self.raw_type, self.name) 0628 if self.arrayDecl: 0629 ret = ret + "[]" 0630 return ret 0631 0632 class Method: 0633 """A representation of a C++ method on a COM interface 0634 0635 This class contains information about a specific method, as well as 0636 a list of all @Argument@s 0637 """ 0638 # options ret type callconv name 0639 # ----------------- -------- -------- -------- 0640 regex = regex.compile('virtual \\(/\\*.*\\*/ \\)?\\(.*\\) \\(.*\\) \\(.*\\)(\w?') 0641 def __init__(self, good_interface_names ): 0642 self.good_interface_names = good_interface_names 0643 self.name = self.result = self.callconv = None 0644 self.args = [] 0645 def BuildFromFile(self, file): 0646 """Parse and build my data from a file 0647 0648 Reads the next line in the file, and matches it as a method 0649 description. If not a valid method line, an error_not_found exception 0650 is raised. 0651 """ 0652 str = file.readline() 0653 if self.regex.search(str, 0) == -1: 0654 raise error_not_found 0655 self.name = self.regex.group(4) 0656 self.result = self.regex.group(2) 0657 if self.result != "HRESULT": 0658 if self.result=="DWORD": # DWORD is for old old stuff? 0659 print "Warning: Old style interface detected - compilation errors likely!" 0660 else: 0661 print "Method %s - Only HRESULT return types are supported." % self.name 0662 # raise error_not_supported, if VERBOSE: 0663 print " Method %s %s(" % (self.result, self.name) 0664 while 1: 0665 arg = Argument(self.good_interface_names) 0666 try: 0667 arg.BuildFromFile(file) 0668 self.args.append(arg) 0669 except error_not_found: 0670 break 0671 0672 class Interface: 0673 """A representation of a C++ COM Interface 0674 0675 This class contains information about a specific interface, as well as 0676 a list of all @Method@s 0677 """ 0678 # name base 0679 # -------- -------- 0680 regex = regex.compile("\\(interface\\|\\) \\([^ ]*\\) : public \\(.*\\)$") 0681 def __init__(self): 0682 self.methods = [] 0683 self.name = self.regex.group(2) 0684 self.base = self.regex.group(3) 0685 if VERBOSE: 0686 print "Interface %s : public %s" % (self.name, self.base) 0687 0688 def BuildMethods(self, file): 0689 """Build all sub-methods for this interface""" 0690 # skip the next 2 lines. 0691 file.readline();file.readline(); 0692 while 1: 0693 try: 0694 method = Method([self.name]) 0695 method.BuildFromFile(file) 0696 self.methods.append(method) 0697 except error_not_found: 0698 break 0699 0700 def find_interface(interfaceName, file): 0701 """Find and return an interface in a file 0702 0703 Given an interface name and file, search for the specified interface. 0704 0705 Upon return, the interface itself has been built, 0706 but not the methods. 0707 """ 0708 0709 line = file.readline() 0710 while line: 0711 if Interface.regex.search(line, 0) >=0: 0712 name = Interface.regex.group(2) 0713 print name 0714 if name==interfaceName: 0715 return Interface() 0716 line = file.readline() 0717 raise error_not_found 0718 0719 0720 def parse_interface_info(interfaceName, file): 0721 """Find, parse and return an interface in a file 0722 0723 Given an interface name and file, search for the specified interface. 0724 0725 Upon return, the interface itself is fully built, 0726 """ 0727 try: 0728 interface = find_interface(interfaceName, file) 0729 interface.BuildMethods(file) 0730 return interface 0731 except regex.error: 0732 traceback.print_exc() 0733 print "The interface could not be built, as the regular expression failed!" 0734 def test(): 0735 f=open("d:\\msdev\\include\\objidl.h") 0736 try: 0737 parse_interface_info("IPersistStream", f) 0738 finally: 0739 f.close() 0740 0741 def test_regex(r,text): 0742 res=r.search(text,0) 0743 if res==-1: 0744 print "** Not found" 0745 else: 0746 print "%d\n%s\n%s\n%s\n%s" % (res, r.group(1), r.group(2), r.group(3), r.group(4)) 0747 0748
Generated by PyXR 0.9.4