123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783 |
- """Utilities for makegw - Parse a header file to build an interface
- This module contains the core code for parsing a header file describing a
- COM interface, and building it into an "Interface" structure.
- Each Interface has methods, and each method has arguments.
- Each argument knows how to use Py_BuildValue or Py_ParseTuple to
- exchange itself with Python.
-
- See the @win32com.makegw@ module for information in building a COM
- interface
- """
- import re
- import traceback
- class error_not_found(Exception):
- def __init__(self, msg="The requested item could not be found"):
- super(error_not_found, self).__init__(msg)
- class error_not_supported(Exception):
- def __init__(self, msg="The required functionality is not supported"):
- super(error_not_supported, self).__init__(msg)
- VERBOSE=0
- DEBUG=0
- ## NOTE : For interfaces as params to work correctly, you must
- ## make sure any PythonCOM extensions which expose the interface are loaded
- ## before generating.
- class ArgFormatter:
- """An instance for a specific type of argument. Knows how to convert itself"""
- def __init__(self, arg, builtinIndirection, declaredIndirection = 0):
- #print 'init:', arg.name, builtinIndirection, declaredIndirection, arg.indirectionLevel
- self.arg = arg
- self.builtinIndirection = builtinIndirection
- self.declaredIndirection = declaredIndirection
- self.gatewayMode = 0
- def _IndirectPrefix(self, indirectionFrom, indirectionTo):
- """Given the indirection level I was declared at (0=Normal, 1=*, 2=**)
- return a string prefix so I can pass to a function with the
- required indirection (where the default is the indirection of the method's param.
-
- eg, assuming my arg has indirection level of 2, if this function was passed 1
- it would return "&", so that a variable declared with indirection of 1
- can be prefixed with this to turn it into the indirection level required of 2
- """
- dif = indirectionFrom - indirectionTo
- if dif==0:
- return ""
- elif dif==-1:
- return "&"
- elif dif==1:
- return "*"
- else:
- return "?? (%d)" % (dif,)
- raise error_not_supported("Can't indirect this far - please fix me :-)")
- def GetIndirectedArgName(self, indirectFrom, indirectionTo):
- #print 'get:',self.arg.name, indirectFrom,self._GetDeclaredIndirection() + self.builtinIndirection, indirectionTo, self.arg.indirectionLevel
- if indirectFrom is None:
- ### ACK! this does not account for [in][out] variables.
- ### when this method is called, we need to know which
- indirectFrom = self._GetDeclaredIndirection() + self.builtinIndirection
- return self._IndirectPrefix(indirectFrom, indirectionTo) + self.arg.name
- def GetBuildValueArg(self):
- "Get the argument to be passes to Py_BuildValue"
- return self.arg.name
- def GetParseTupleArg(self):
- "Get the argument to be passed to PyArg_ParseTuple"
- if self.gatewayMode:
- # use whatever they were declared with
- return self.GetIndirectedArgName(None, 1)
- # local declarations have just their builtin indirection
- return self.GetIndirectedArgName(self.builtinIndirection, 1)
- def GetInterfaceCppObjectInfo(self):
- """Provide information about the C++ object used.
-
- Simple variables (such as integers) can declare their type (eg an integer)
- and use it as the target of both PyArg_ParseTuple and the COM function itself.
-
- More complex types require a PyObject * declared as the target of PyArg_ParseTuple,
- then some conversion routine to the C++ object which is actually passed to COM.
-
- This method provides the name, and optionally the type of that C++ variable.
- If the type if provided, the caller will likely generate a variable declaration.
- The name must always be returned.
-
- Result is a tuple of (variableName, [DeclareType|None|""])
- """
- # the first return element is the variable to be passed as
- # an argument to an interface method. the variable was
- # declared with only its builtin indirection level. when
- # we pass it, we'll need to pass in whatever amount of
- # indirection was applied (plus the builtin amount)
- # the second return element is the variable declaration; it
- # should simply be builtin indirection
- return self.GetIndirectedArgName(self.builtinIndirection, self.arg.indirectionLevel + self.builtinIndirection), \
- "%s %s" % (self.GetUnconstType(), self.arg.name)
- def GetInterfaceArgCleanup(self):
- "Return cleanup code for C++ args passed to the interface method."
- if DEBUG:
- return "/* GetInterfaceArgCleanup output goes here: %s */\n" % self.arg.name
- else:
- return ""
- def GetInterfaceArgCleanupGIL(self):
- """Return cleanup code for C++ args passed to the interface
- method that must be executed with the GIL held"""
- if DEBUG:
- return "/* GetInterfaceArgCleanup (GIL held) output goes here: %s */\n" % self.arg.name
- else:
- return ""
- def GetUnconstType(self):
- return self.arg.unc_type
-
- def SetGatewayMode(self):
- self.gatewayMode = 1
- def _GetDeclaredIndirection(self):
- return self.arg.indirectionLevel
- print('declared:', self.arg.name, self.gatewayMode)
- if self.gatewayMode:
- return self.arg.indirectionLevel
- else:
- return self.declaredIndirection
- def DeclareParseArgTupleInputConverter(self):
- "Declare the variable used as the PyArg_ParseTuple param for a gateway"
- # Only declare it??
- #if self.arg.indirectionLevel==0:
- # return "\t%s %s;\n" % (self.arg.type, self.arg.name)
- #else:
- if DEBUG:
- return "/* Declare ParseArgTupleInputConverter goes here: %s */\n" % self.arg.name
- else:
- return ""
- def GetParsePostCode(self):
- "Get a string of C++ code to be executed after (ie, to finalise) the PyArg_ParseTuple conversion"
- if DEBUG:
- return "/* GetParsePostCode code goes here: %s */\n" % self.arg.name
- else:
- return ""
- def GetBuildForInterfacePreCode(self):
- "Get a string of C++ code to be executed before (ie, to initialise) the Py_BuildValue conversion for Interfaces"
- if DEBUG:
- return "/* GetBuildForInterfacePreCode goes here: %s */\n" % self.arg.name
- else:
- return ""
- def GetBuildForGatewayPreCode(self):
- "Get a string of C++ code to be executed before (ie, to initialise) the Py_BuildValue conversion for Gateways"
- s = self.GetBuildForInterfacePreCode() # Usually the same
- if DEBUG:
- if s[:4] == "/* G":
- s = "/* GetBuildForGatewayPreCode goes here: %s */\n" % self.arg.name
- return s
- def GetBuildForInterfacePostCode(self):
- "Get a string of C++ code to be executed after (ie, to finalise) the Py_BuildValue conversion for Interfaces"
- if DEBUG:
- return "/* GetBuildForInterfacePostCode goes here: %s */\n" % self.arg.name
- return ""
- def GetBuildForGatewayPostCode(self):
- "Get a string of C++ code to be executed after (ie, to finalise) the Py_BuildValue conversion for Gateways"
- s = self.GetBuildForInterfacePostCode() # Usually the same
- if DEBUG:
- if s[:4] == "/* G":
- s = "/* GetBuildForGatewayPostCode goes here: %s */\n" % self.arg.name
- return s
- def GetAutoduckString(self):
- return '// @pyparm %s|%s||Description for %s' % (self._GetPythonTypeDesc(), self.arg.name, self.arg.name)
- def _GetPythonTypeDesc(self):
- "Returns a string with the description of the type. Used for doco purposes"
- return None
- def NeedUSES_CONVERSION(self):
- "Determines if this arg forces a USES_CONVERSION macro"
- return 0
- # Special formatter for floats since they're smaller than Python floats.
- class ArgFormatterFloat(ArgFormatter):
- def GetFormatChar(self):
- return "f"
- def DeclareParseArgTupleInputConverter(self):
- # Declare a double variable
- return "\tdouble dbl%s;\n" % self.arg.name
- def GetParseTupleArg(self):
- return "&dbl" + self.arg.name
- def _GetPythonTypeDesc(self):
- return "float"
- def GetBuildValueArg(self):
- return "&dbl" + self.arg.name
- def GetBuildForInterfacePreCode(self):
- return "\tdbl" + self.arg.name + " = " + self.arg.name + ";\n"
- def GetBuildForGatewayPreCode(self):
- return "\tdbl%s = " % self.arg.name + self._IndirectPrefix( \
- self._GetDeclaredIndirection(),
- 0) + self.arg.name + ";\n"
- def GetParsePostCode(self):
- s = "\t"
- if self.gatewayMode:
- s = s + self._IndirectPrefix(
- self._GetDeclaredIndirection(),
- 0)
- s = s + self.arg.name
- s = s + " = (float)dbl%s;\n" % self.arg.name
- return s
- # Special formatter for Shorts because they're
- # a different size than Python ints!
- class ArgFormatterShort(ArgFormatter):
- def GetFormatChar(self):
- return "i"
- def DeclareParseArgTupleInputConverter(self):
- # Declare a double variable
- return "\tINT i%s;\n" % self.arg.name
- def GetParseTupleArg(self):
- return "&i" + self.arg.name
- def _GetPythonTypeDesc(self):
- return "int"
- def GetBuildValueArg(self):
- return "&i" + self.arg.name
- def GetBuildForInterfacePreCode(self):
- return "\ti" + self.arg.name + " = " + self.arg.name + ";\n"
- def GetBuildForGatewayPreCode(self):
- return "\ti%s = " % self.arg.name + self._IndirectPrefix( \
- self._GetDeclaredIndirection(),
- 0) + self.arg.name + ";\n"
- def GetParsePostCode(self):
- s = "\t"
- if self.gatewayMode:
- s = s + self._IndirectPrefix(
- self._GetDeclaredIndirection(),
- 0)
- s = s + self.arg.name
- s = s + " = i%s;\n" % self.arg.name
- return s
- # for types which are 64bits on AMD64 - eg, HWND
- class ArgFormatterLONG_PTR(ArgFormatter):
- def GetFormatChar(self):
- return "O"
- def DeclareParseArgTupleInputConverter(self):
- # Declare a PyObject variable
- return "\tPyObject *ob%s;\n" % self.arg.name
- def GetParseTupleArg(self):
- return "&ob"+self.arg.name
- def _GetPythonTypeDesc(self):
- return "int/long"
- def GetBuildValueArg(self):
- return "ob" + self.arg.name
- def GetBuildForInterfacePostCode(self):
- return "\tPy_XDECREF(ob%s);\n" % self.arg.name
- def DeclareParseArgTupleInputConverter(self):
- # Declare a PyObject variable
- return "\tPyObject *ob%s;\n" % self.arg.name
- def GetParsePostCode(self):
- return "\tif (bPythonIsHappy && !PyWinLong_AsULONG_PTR(ob%s, (ULONG_PTR *)%s)) bPythonIsHappy = FALSE;\n" % (self.arg.name, self.GetIndirectedArgName(None, 2))
- def GetBuildForInterfacePreCode(self):
- notdirected = self.GetIndirectedArgName(None, 1)
- return "\tob%s = PyWinObject_FromULONG_PTR(%s);\n" % \
- (self.arg.name, notdirected)
- def GetBuildForGatewayPostCode(self):
- return "\tPy_XDECREF(ob%s);\n" % self.arg.name
- class ArgFormatterPythonCOM(ArgFormatter):
- """An arg formatter for types exposed in the PythonCOM module"""
- def GetFormatChar(self):
- return "O"
- #def GetInterfaceCppObjectInfo(self):
- # return ArgFormatter.GetInterfaceCppObjectInfo(self)[0], \
- # "%s %s%s" % (self.arg.unc_type, "*" * self._GetDeclaredIndirection(), self.arg.name)
- def DeclareParseArgTupleInputConverter(self):
- # Declare a PyObject variable
- return "\tPyObject *ob%s;\n" % self.arg.name
- def GetParseTupleArg(self):
- return "&ob"+self.arg.name
- def _GetPythonTypeDesc(self):
- return "<o Py%s>" % self.arg.type
- def GetBuildValueArg(self):
- return "ob" + self.arg.name
- def GetBuildForInterfacePostCode(self):
- return "\tPy_XDECREF(ob%s);\n" % self.arg.name
- def DeclareParseArgTupleInputConverter(self):
- # Declare a PyObject variable
- return "\tPyObject *ob%s;\n" % self.arg.name
- class ArgFormatterBSTR(ArgFormatterPythonCOM):
- def _GetPythonTypeDesc(self):
- return "<o unicode>"
- def GetParsePostCode(self):
- return "\tif (bPythonIsHappy && !PyWinObject_AsBstr(ob%s, %s)) bPythonIsHappy = FALSE;\n" % (self.arg.name, self.GetIndirectedArgName(None, 2))
- def GetBuildForInterfacePreCode(self):
- notdirected = self.GetIndirectedArgName(None, 1)
- return "\tob%s = MakeBstrToObj(%s);\n" % \
- (self.arg.name, notdirected)
- def GetBuildForInterfacePostCode(self):
- return "\tSysFreeString(%s);\n" % (self.arg.name,) + \
- ArgFormatterPythonCOM.GetBuildForInterfacePostCode(self)
- def GetBuildForGatewayPostCode(self):
- return "\tPy_XDECREF(ob%s);\n" % self.arg.name
- class ArgFormatterOLECHAR(ArgFormatterPythonCOM):
- def _GetPythonTypeDesc(self):
- return "<o unicode>"
- def GetUnconstType(self):
- if self.arg.type[:3]=="LPC":
- return self.arg.type[:2] + self.arg.type[3:]
- else:
- return self.arg.unc_type
- def GetParsePostCode(self):
- return "\tif (bPythonIsHappy && !PyWinObject_AsBstr(ob%s, %s)) bPythonIsHappy = FALSE;\n" % (self.arg.name, self.GetIndirectedArgName(None, 2))
- def GetInterfaceArgCleanup(self):
- return "\tSysFreeString(%s);\n" % self.GetIndirectedArgName(None, 1)
- def GetBuildForInterfacePreCode(self):
- # the variable was declared with just its builtin indirection
- notdirected = self.GetIndirectedArgName(self.builtinIndirection, 1)
- return "\tob%s = MakeOLECHARToObj(%s);\n" % \
- (self.arg.name, notdirected)
- def GetBuildForInterfacePostCode(self):
- # memory returned into an OLECHAR should be freed
- return "\tCoTaskMemFree(%s);\n" % (self.arg.name,) + \
- ArgFormatterPythonCOM.GetBuildForInterfacePostCode(self)
- def GetBuildForGatewayPostCode(self):
- return "\tPy_XDECREF(ob%s);\n" % self.arg.name
- class ArgFormatterTCHAR(ArgFormatterPythonCOM):
- def _GetPythonTypeDesc(self):
- return "string/<o unicode>"
- def GetUnconstType(self):
- if self.arg.type[:3]=="LPC":
- return self.arg.type[:2] + self.arg.type[3:]
- else:
- return self.arg.unc_type
- def GetParsePostCode(self):
- return "\tif (bPythonIsHappy && !PyWinObject_AsTCHAR(ob%s, %s)) bPythonIsHappy = FALSE;\n" % (self.arg.name, self.GetIndirectedArgName(None, 2))
- def GetInterfaceArgCleanup(self):
- return "\tPyWinObject_FreeTCHAR(%s);\n" % self.GetIndirectedArgName(None, 1)
- def GetBuildForInterfacePreCode(self):
- # the variable was declared with just its builtin indirection
- notdirected = self.GetIndirectedArgName(self.builtinIndirection, 1)
- return "\tob%s = PyWinObject_FromTCHAR(%s);\n" % \
- (self.arg.name, notdirected)
- def GetBuildForInterfacePostCode(self):
- return "// ??? - TCHAR post code\n"
- def GetBuildForGatewayPostCode(self):
- return "\tPy_XDECREF(ob%s);\n" % self.arg.name
- class ArgFormatterIID(ArgFormatterPythonCOM):
- def _GetPythonTypeDesc(self):
- return "<o PyIID>"
- def GetParsePostCode(self):
- return "\tif (!PyWinObject_AsIID(ob%s, &%s)) bPythonIsHappy = FALSE;\n" % (self.arg.name, self.arg.name)
- def GetBuildForInterfacePreCode(self):
- # notdirected = self.GetIndirectedArgName(self.arg.indirectionLevel, 0)
- notdirected = self.GetIndirectedArgName(None, 0)
- return "\tob%s = PyWinObject_FromIID(%s);\n" % (self.arg.name, notdirected)
- def GetInterfaceCppObjectInfo(self):
- return self.arg.name, "IID %s" % (self.arg.name)
- class ArgFormatterTime(ArgFormatterPythonCOM):
- def __init__(self, arg, builtinIndirection, declaredIndirection = 0):
- # we don't want to declare LPSYSTEMTIME / LPFILETIME objects
- if arg.indirectionLevel == 0 and arg.unc_type[:2] == "LP":
- arg.unc_type = arg.unc_type[2:]
- # reduce the builtin and increment the declaration
- arg.indirectionLevel = arg.indirectionLevel + 1
- builtinIndirection = 0
- ArgFormatterPythonCOM.__init__(self, arg, builtinIndirection, declaredIndirection)
- def _GetPythonTypeDesc(self):
- return "<o PyDateTime>"
- def GetParsePostCode(self):
- # variable was declared with only the builtinIndirection
- ### NOTE: this is an [in] ... so use only builtin
- 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))
- def GetBuildForInterfacePreCode(self):
- ### use just the builtinIndirection again...
- notdirected = self.GetIndirectedArgName(self.builtinIndirection,0)
- return "\tob%s = new PyTime(%s);\n" % (self.arg.name, notdirected)
- def GetBuildForInterfacePostCode(self):
- ### hack to determine if we need to free stuff
- ret = ''
- if self.builtinIndirection + self.arg.indirectionLevel > 1:
- # memory returned into an OLECHAR should be freed
- ret = "\tCoTaskMemFree(%s);\n" % self.arg.name
- return ret + ArgFormatterPythonCOM.GetBuildForInterfacePostCode(self)
- class ArgFormatterSTATSTG(ArgFormatterPythonCOM):
- def _GetPythonTypeDesc(self):
- return "<o STATSTG>"
- def GetParsePostCode(self):
- return '\tif (!PyCom_PyObjectAsSTATSTG(ob%s, %s, 0/*flags*/)) bPythonIsHappy = FALSE;\n' % (self.arg.name, self.GetIndirectedArgName(None, 1))
- def GetBuildForInterfacePreCode(self):
- notdirected = self.GetIndirectedArgName(None, 1)
- 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)
- class ArgFormatterGeneric(ArgFormatterPythonCOM):
- def _GetPythonTypeDesc(self):
- return "<o %s>" % self.arg.type
- def GetParsePostCode(self):
- return '\tif (!PyObject_As%s(ob%s, &%s) bPythonIsHappy = FALSE;\n' % (self.arg.type, self.arg.name, self.GetIndirectedArgName(None, 1))
- def GetInterfaceArgCleanup(self):
- return '\tPyObject_Free%s(%s);\n' % (self.arg.type, self.arg.name)
- def GetBuildForInterfacePreCode(self):
- notdirected = self.GetIndirectedArgName(None, 1)
- return "\tob%s = PyObject_From%s(%s);\n" % (self.arg.name, self.arg.type, self.GetIndirectedArgName(None, 1))
- class ArgFormatterIDLIST(ArgFormatterPythonCOM):
- def _GetPythonTypeDesc(self):
- return "<o PyIDL>"
- def GetParsePostCode(self):
- return '\tif (bPythonIsHappy && !PyObject_AsPIDL(ob%s, &%s)) bPythonIsHappy = FALSE;\n' % (self.arg.name, self.GetIndirectedArgName(None, 1))
- def GetInterfaceArgCleanup(self):
- return '\tPyObject_FreePIDL(%s);\n' % (self.arg.name,)
- def GetBuildForInterfacePreCode(self):
- notdirected = self.GetIndirectedArgName(None, 1)
- return "\tob%s = PyObject_FromPIDL(%s);\n" % (self.arg.name, self.GetIndirectedArgName(None, 1))
- class ArgFormatterHANDLE(ArgFormatterPythonCOM):
- def _GetPythonTypeDesc(self):
- return "<o PyHANDLE>"
- def GetParsePostCode(self):
- return '\tif (!PyWinObject_AsHANDLE(ob%s, &%s, FALSE) bPythonIsHappy = FALSE;\n' % (self.arg.name, self.GetIndirectedArgName(None, 1))
- def GetBuildForInterfacePreCode(self):
- notdirected = self.GetIndirectedArgName(None, 1)
- return "\tob%s = PyWinObject_FromHANDLE(%s);\n" % (self.arg.name, self.GetIndirectedArgName(None, 0))
- class ArgFormatterLARGE_INTEGER(ArgFormatterPythonCOM):
- def GetKeyName(self):
- return "LARGE_INTEGER"
- def _GetPythonTypeDesc(self):
- return "<o %s>" % self.GetKeyName()
- def GetParsePostCode(self):
- return '\tif (!PyWinObject_As%s(ob%s, %s)) bPythonIsHappy = FALSE;\n' % (self.GetKeyName(), self.arg.name, self.GetIndirectedArgName(None, 1))
- def GetBuildForInterfacePreCode(self):
- notdirected = self.GetIndirectedArgName(None, 0)
- return "\tob%s = PyWinObject_From%s(%s);\n" % (self.arg.name, self.GetKeyName(), notdirected)
- class ArgFormatterULARGE_INTEGER(ArgFormatterLARGE_INTEGER):
- def GetKeyName(self):
- return "ULARGE_INTEGER"
- class ArgFormatterInterface(ArgFormatterPythonCOM):
- def GetInterfaceCppObjectInfo(self):
- return self.GetIndirectedArgName(1, self.arg.indirectionLevel), \
- "%s * %s" % (self.GetUnconstType(), self.arg.name)
- def GetParsePostCode(self):
- # This gets called for out params in gateway mode
- if self.gatewayMode:
- sArg = self.GetIndirectedArgName(None, 2)
- else:
- # vs. in params for interface mode.
- sArg = self.GetIndirectedArgName(1, 2)
- 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)
-
- def GetBuildForInterfacePreCode(self):
- return "\tob%s = PyCom_PyObjectFromIUnknown(%s, IID_%s, FALSE);\n" % (self.arg.name, self.arg.name, self.arg.type)
-
- def GetBuildForGatewayPreCode(self):
- sPrefix = self._IndirectPrefix(self._GetDeclaredIndirection(), 1)
- return "\tob%s = PyCom_PyObjectFromIUnknown(%s%s, IID_%s, TRUE);\n" % (self.arg.name, sPrefix, self.arg.name, self.arg.type)
- def GetInterfaceArgCleanup(self):
- return "\tif (%s) %s->Release();\n" % (self.arg.name, self.arg.name)
- class ArgFormatterVARIANT(ArgFormatterPythonCOM):
- def GetParsePostCode(self):
- return "\tif ( !PyCom_VariantFromPyObject(ob%s, %s) )\n\t\tbPythonIsHappy = FALSE;\n" % (self.arg.name, self.GetIndirectedArgName(None, 1))
- def GetBuildForGatewayPreCode(self):
- notdirected = self.GetIndirectedArgName(None, 1)
- return "\tob%s = PyCom_PyObjectFromVariant(%s);\n" % (self.arg.name, notdirected)
- def GetBuildForGatewayPostCode(self):
- return "\tPy_XDECREF(ob%s);\n" % self.arg.name
- # Key : , Python Type Description, ParseTuple format char
- ConvertSimpleTypes = {"BOOL":("BOOL", "int", "i"),
- "UINT":("UINT", "int", "i"),
- "BYTE": ("BYTE", "int", "i"),
- "INT": ("INT", "int", "i"),
- "DWORD": ("DWORD", "int", "l"),
- "HRESULT":("HRESULT", "int", "l"),
- "ULONG": ("ULONG", "int", "l"),
- "LONG": ("LONG", "int", "l"),
- "int": ("int", "int", "i"),
- "long": ("long", "int", "l"),
- "DISPID": ("DISPID", "long", "l"),
- "APPBREAKFLAGS": ("int", "int", "i"),
- "BREAKRESUMEACTION": ("int", "int", "i"),
- "ERRORRESUMEACTION": ("int", "int", "i"),
- "BREAKREASON": ("int", "int", "i"),
- "BREAKPOINT_STATE": ("int", "int", "i"),
- "BREAKRESUME_ACTION": ("int", "int", "i"),
- "SOURCE_TEXT_ATTR": ("int", "int", "i"),
- "TEXT_DOC_ATTR": ("int", "int", "i"),
- "QUERYOPTION": ("int", "int", "i"),
- "PARSEACTION": ("int", "int", "i"),
- }
- class ArgFormatterSimple(ArgFormatter):
- """An arg formatter for simple integer etc types"""
- def GetFormatChar(self):
- return ConvertSimpleTypes[self.arg.type][2]
- def _GetPythonTypeDesc(self):
- return ConvertSimpleTypes[self.arg.type][1]
- AllConverters = {"const OLECHAR": (ArgFormatterOLECHAR, 0, 1),
- "WCHAR": (ArgFormatterOLECHAR, 0, 1),
- "OLECHAR": (ArgFormatterOLECHAR, 0, 1),
- "LPCOLESTR": (ArgFormatterOLECHAR, 1, 1),
- "LPOLESTR": (ArgFormatterOLECHAR, 1, 1),
- "LPCWSTR": (ArgFormatterOLECHAR, 1, 1),
- "LPWSTR": (ArgFormatterOLECHAR, 1, 1),
- "LPCSTR": (ArgFormatterOLECHAR, 1, 1),
- "LPTSTR": (ArgFormatterTCHAR, 1, 1),
- "LPCTSTR": (ArgFormatterTCHAR, 1, 1),
- "HANDLE": (ArgFormatterHANDLE, 0),
- "BSTR": (ArgFormatterBSTR, 1, 0),
- "const IID": (ArgFormatterIID, 0),
- "CLSID": (ArgFormatterIID, 0),
- "IID": (ArgFormatterIID, 0),
- "GUID": (ArgFormatterIID, 0),
- "const GUID": (ArgFormatterIID, 0),
- "const IID": (ArgFormatterIID, 0),
- "REFCLSID": (ArgFormatterIID, 0),
- "REFIID": (ArgFormatterIID, 0),
- "REFGUID": (ArgFormatterIID, 0),
- "const FILETIME": (ArgFormatterTime, 0),
- "const SYSTEMTIME":(ArgFormatterTime, 0),
- "const LPSYSTEMTIME":(ArgFormatterTime, 1, 1),
- "LPSYSTEMTIME": (ArgFormatterTime, 1, 1),
- "FILETIME": (ArgFormatterTime, 0),
- "SYSTEMTIME": (ArgFormatterTime, 0),
- "STATSTG": (ArgFormatterSTATSTG, 0),
- "LARGE_INTEGER": (ArgFormatterLARGE_INTEGER, 0),
- "ULARGE_INTEGER": (ArgFormatterULARGE_INTEGER, 0),
- "VARIANT": (ArgFormatterVARIANT, 0),
- "float": (ArgFormatterFloat, 0),
- "single": (ArgFormatterFloat, 0),
- "short": (ArgFormatterShort, 0),
- "WORD": (ArgFormatterShort, 0),
- "VARIANT_BOOL": (ArgFormatterShort, 0),
- "HWND": (ArgFormatterLONG_PTR, 1),
- "HMENU": (ArgFormatterLONG_PTR, 1),
- "HOLEMENU": (ArgFormatterLONG_PTR, 1),
- "HICON": (ArgFormatterLONG_PTR, 1),
- "HDC": (ArgFormatterLONG_PTR, 1),
- "LPARAM": (ArgFormatterLONG_PTR, 1),
- "WPARAM": (ArgFormatterLONG_PTR, 1),
- "LRESULT": (ArgFormatterLONG_PTR, 1),
- "UINT": (ArgFormatterShort, 0),
- "SVSIF": (ArgFormatterShort, 0),
- "Control": (ArgFormatterInterface, 0, 1),
- "DataObject": (ArgFormatterInterface, 0, 1),
- "_PropertyBag": (ArgFormatterInterface, 0, 1),
- "AsyncProp": (ArgFormatterInterface, 0, 1),
- "DataSource": (ArgFormatterInterface, 0, 1),
- "DataFormat": (ArgFormatterInterface, 0, 1),
- "void **": (ArgFormatterInterface, 2, 2),
- "ITEMIDLIST": (ArgFormatterIDLIST, 0, 0),
- "LPITEMIDLIST": (ArgFormatterIDLIST, 0, 1),
- "LPCITEMIDLIST": (ArgFormatterIDLIST, 0, 1),
- "const ITEMIDLIST": (ArgFormatterIDLIST, 0, 1),
- }
- # Auto-add all the simple types
- for key in ConvertSimpleTypes.keys():
- AllConverters[key] = ArgFormatterSimple, 0
- def make_arg_converter(arg):
- try:
- clz = AllConverters[arg.type][0]
- bin = AllConverters[arg.type][1]
- decl = 0
- if len(AllConverters[arg.type])>2:
- decl = AllConverters[arg.type][2]
- return clz(arg,bin, decl)
- except KeyError:
- if arg.type[0]=="I":
- return ArgFormatterInterface(arg, 0, 1)
- raise error_not_supported("The type '%s' (%s) is unknown." % (arg.type, arg.name))
- #############################################################
- #
- # The instances that represent the args, methods and interface
- class Argument:
- """A representation of an argument to a COM method
-
- This class contains information about a specific argument to a method.
- In addition, methods exist so that an argument knows how to convert itself
- to/from Python arguments.
- """
- # in,out type name [ ]
- # -------------- -------- ------------ ------
- regex = re.compile(r'/\* \[([^\]]*.*?)] \*/[ \t](.*[* ]+)(\w+)(\[ *])?[\),]')
- def __init__(self, good_interface_names):
- self.good_interface_names = good_interface_names
- self.inout = self.name = self.type = None
- self.const = 0
- self.arrayDecl = 0
- def BuildFromFile(self, file):
- """Parse and build my data from a file
-
- Reads the next line in the file, and matches it as an argument
- description. If not a valid argument line, an error_not_found exception
- is raised.
- """
- line = file.readline()
- mo = self.regex.search(line)
- if not mo:
- raise error_not_found
- self.name = mo.group(3)
- self.inout = mo.group(1).split('][')
- typ = mo.group(2).strip()
- self.raw_type = typ
- self.indirectionLevel = 0
- if mo.group(4): # Has "[ ]" decl
- self.arrayDecl = 1
- try:
- pos = typ.rindex("__RPC_FAR")
- self.indirectionLevel = self.indirectionLevel + 1
- typ = typ[:pos].strip()
- except ValueError:
- pass
- typ = typ.replace("__RPC_FAR", "")
- while 1:
- try:
- pos = typ.rindex("*")
- self.indirectionLevel = self.indirectionLevel + 1
- typ = typ[:pos].strip()
- except ValueError:
- break
- self.type = typ
- if self.type[:6]=="const ":
- self.unc_type = self.type[6:]
- else:
- self.unc_type = self.type
-
- if VERBOSE:
- print(" Arg %s of type %s%s (%s)" % (self.name, self.type, "*" * self.indirectionLevel, self.inout))
- def HasAttribute(self, typ):
- """Determines if the argument has the specific attribute.
-
- Argument attributes are specified in the header file, such as
- "[in][out][retval]" etc. You can pass a specific string (eg "out")
- to find if this attribute was specified for the argument
- """
- return typ in self.inout
- def GetRawDeclaration(self):
- ret = "%s %s" % (self.raw_type, self.name)
- if self.arrayDecl:
- ret = ret + "[]"
- return ret
- class Method:
- """A representation of a C++ method on a COM interface
-
- This class contains information about a specific method, as well as
- a list of all @Argument@s
- """
- # options ret type callconv name
- # ----------------- -------- -------- --------
- regex = re.compile(r'virtual (/\*.*?\*/ )?(.*?) (.*?) (.*?)\(\w?')
- def __init__(self, good_interface_names):
- self.good_interface_names = good_interface_names
- self.name = self.result = self.callconv = None
- self.args = []
- def BuildFromFile(self, file):
- """Parse and build my data from a file
-
- Reads the next line in the file, and matches it as a method
- description. If not a valid method line, an error_not_found exception
- is raised.
- """
- line = file.readline()
- mo = self.regex.search(line)
- if not mo:
- raise error_not_found
- self.name = mo.group(4)
- self.result = mo.group(2)
- if self.result != "HRESULT":
- if self.result=="DWORD": # DWORD is for old old stuff?
- print("Warning: Old style interface detected - compilation errors likely!")
- else:
- print("Method %s - Only HRESULT return types are supported." % self.name)
- # raise error_not_supported, if VERBOSE:
- print(" Method %s %s(" % (self.result, self.name))
- while 1:
- arg = Argument(self.good_interface_names)
- try:
- arg.BuildFromFile(file)
- self.args.append(arg)
- except error_not_found:
- break
- class Interface:
- """A representation of a C++ COM Interface
-
- This class contains information about a specific interface, as well as
- a list of all @Method@s
- """
- # name base
- # -------- --------
- regex = re.compile("(interface|) ([^ ]*) : public (.*)$")
- def __init__(self, mo):
- self.methods = []
- self.name = mo.group(2)
- self.base = mo.group(3)
- if VERBOSE:
- print("Interface %s : public %s" % (self.name, self.base))
- def BuildMethods(self, file):
- """Build all sub-methods for this interface"""
- # skip the next 2 lines.
- file.readline();file.readline();
- while 1:
- try:
- method = Method([self.name])
- method.BuildFromFile(file)
- self.methods.append(method)
- except error_not_found:
- break
- def find_interface(interfaceName, file):
- """Find and return an interface in a file
-
- Given an interface name and file, search for the specified interface.
-
- Upon return, the interface itself has been built,
- but not the methods.
- """
- interface = None
- line = file.readline()
- while line:
- mo = Interface.regex.search(line)
- if mo:
- name = mo.group(2)
- print(name)
- AllConverters[name] = (ArgFormatterInterface, 0, 1)
- if name==interfaceName:
- interface = Interface(mo)
- interface.BuildMethods(file)
- line = file.readline()
- if interface:
- return interface
- raise error_not_found
- def parse_interface_info(interfaceName, file):
- """Find, parse and return an interface in a file
-
- Given an interface name and file, search for the specified interface.
-
- Upon return, the interface itself is fully built,
- """
- try:
- return find_interface(interfaceName, file)
- except re.error:
- traceback.print_exc()
- print("The interface could not be built, as the regular expression failed!")
- def test():
- f=open("d:\\msdev\\include\\objidl.h")
- try:
- parse_interface_info("IPersistStream", f)
- finally:
- f.close()
- def test_regex(r,text):
- res=r.search(text,0)
- if res==-1:
- print("** Not found")
- else:
- print("%d\n%s\n%s\n%s\n%s" % (res, r.group(1), r.group(2), r.group(3), r.group(4)))
|