Uploaded Test files

This commit is contained in:
Batuhan Berk Başoğlu 2020-11-12 11:05:57 -05:00
parent f584ad9d97
commit 2e81cb7d99
16627 changed files with 2065359 additions and 102444 deletions

View file

@ -0,0 +1 @@
# indicates a python package.

View file

@ -0,0 +1,451 @@
"""Utility functions for writing out gateway C++ files
This module will generate a C++/Python binding for a specific COM
interface.
At this stage, no command line interface exists. You must start Python,
import this module, change to the directory where the generated code should
be written, and run the public function.
This module is capable of generating both 'Interfaces' (ie, Python
client side support for the interface) and 'Gateways' (ie, Python
server side support for the interface). Many COM interfaces are useful
both as Client and Server. Other interfaces, however, really only make
sense to implement one side or the other. For example, it would be pointless
for Python to implement Server side for 'IRunningObjectTable', unless we were
implementing core COM for an operating system in Python (hey - now there's an idea!)
Most COM interface code is totally boiler-plate - it consists of
converting arguments, dispatching the call to Python, and processing
any result values.
This module automates the generation of such code. It has the ability to
parse a .H file generated by the MIDL tool (ie, almost all COM .h files)
and build almost totally complete C++ code.
The module understands some of the well known data types, and how to
convert them. There are only a couple of places where hand-editing is
necessary, as detailed below:
unsupported types -- If a type is not known, the generator will
pretty much ignore it, but write a comment to the generated code. You
may want to add custom support for this type. In some cases, C++ compile errors
will result. These are intentional - generating code to remove these errors would
imply a false sense of security that the generator has done the right thing.
other return policies -- By default, Python never sees the return SCODE from
a COM function. The interface usually returns None if OK, else a COM exception
if "FAILED(scode)" is TRUE. You may need to change this if:
* EXCEPINFO is passed to the COM function. This is not detected and handled
* For some reason Python should always see the result SCODE, even if it
did fail or succeed. For example, some functions return a BOOLEAN result
in the SCODE, meaning Python should always see it.
* FAILED(scode) for the interface still has valid data to return (by default,
the code generated does not process the return values, and raise an exception
to Python/COM
"""
import re
from . import makegwparse
def make_framework_support(header_file_name, interface_name, bMakeInterface = 1, bMakeGateway = 1):
"""Generate C++ code for a Python Interface and Gateway
header_file_name -- The full path to the .H file which defines the interface.
interface_name -- The name of the interface to search for, and to generate.
bMakeInterface = 1 -- Should interface (ie, client) support be generated.
bMakeGatewayInterface = 1 -- Should gateway (ie, server) support be generated.
This method will write a .cpp and .h file into the current directory,
(using the name of the interface to build the file name.
"""
fin=open(header_file_name)
try:
interface = makegwparse.parse_interface_info(interface_name, fin)
finally:
fin.close()
if bMakeInterface and bMakeGateway:
desc = "Interface and Gateway"
elif bMakeInterface and not bMakeGateway:
desc = "Interface"
else:
desc = "Gateway"
if interface.name[:5]=="IEnum": # IEnum - use my really simple template-based one
import win32com.makegw.makegwenum
ifc_cpp_writer = win32com.makegw.makegwenum._write_enumifc_cpp
gw_cpp_writer = win32com.makegw.makegwenum._write_enumgw_cpp
else: # Use my harder working ones.
ifc_cpp_writer = _write_ifc_cpp
gw_cpp_writer = _write_gw_cpp
fout=open("Py%s.cpp" % interface.name, "w")
try:
fout.write(\
'''\
// This file implements the %s %s for Python.
// Generated by makegw.py
#include "shell_pch.h"
''' % (interface.name, desc))
# if bMakeGateway:
# fout.write('#include "PythonCOMServer.h"\n')
# if interface.base not in ["IUnknown", "IDispatch"]:
# fout.write('#include "Py%s.h"\n' % interface.base)
fout.write('#include "Py%s.h"\n\n// @doc - This file contains autoduck documentation\n' % interface.name)
if bMakeInterface: ifc_cpp_writer(fout, interface)
if bMakeGateway: gw_cpp_writer(fout, interface)
finally:
fout.close()
fout=open("Py%s.h" % interface.name, "w")
try:
fout.write(\
'''\
// This file declares the %s %s for Python.
// Generated by makegw.py
''' % (interface.name, desc))
if bMakeInterface: _write_ifc_h(fout, interface)
if bMakeGateway: _write_gw_h(fout, interface)
finally:
fout.close()
###########################################################################
#
# INTERNAL FUNCTIONS
#
#
def _write_ifc_h(f, interface):
f.write(\
'''\
// ---------------------------------------------------
//
// Interface Declaration
class Py%s : public Py%s
{
public:
MAKE_PYCOM_CTOR(Py%s);
static %s *GetI(PyObject *self);
static PyComTypeObject type;
// The Python methods
''' % (interface.name, interface.base, interface.name, interface.name))
for method in interface.methods:
f.write('\tstatic PyObject *%s(PyObject *self, PyObject *args);\n' % method.name)
f.write(\
'''\
protected:
Py%s(IUnknown *pdisp);
~Py%s();
};
''' % (interface.name, interface.name))
def _write_ifc_cpp(f, interface):
name = interface.name
f.write(\
'''\
// ---------------------------------------------------
//
// Interface Implementation
Py%(name)s::Py%(name)s(IUnknown *pdisp):
Py%(base)s(pdisp)
{
ob_type = &type;
}
Py%(name)s::~Py%(name)s()
{
}
/* static */ %(name)s *Py%(name)s::GetI(PyObject *self)
{
return (%(name)s *)Py%(base)s::GetI(self);
}
''' % (interface.__dict__))
ptr = re.sub('[a-z]', '', interface.name)
strdict = {'interfacename':interface.name, 'ptr': ptr}
for method in interface.methods:
strdict['method'] = method.name
f.write(\
'''\
// @pymethod |Py%(interfacename)s|%(method)s|Description of %(method)s.
PyObject *Py%(interfacename)s::%(method)s(PyObject *self, PyObject *args)
{
%(interfacename)s *p%(ptr)s = GetI(self);
if ( p%(ptr)s == NULL )
return NULL;
''' % strdict)
argsParseTuple = argsCOM = formatChars = codePost = \
codePobjects = codeCobjects = cleanup = cleanup_gil = ""
needConversion = 0
# if method.name=="Stat": import win32dbg;win32dbg.brk()
for arg in method.args:
try:
argCvt = makegwparse.make_arg_converter(arg)
if arg.HasAttribute("in"):
val = argCvt.GetFormatChar()
if val:
f.write ('\t' + argCvt.GetAutoduckString() + "\n")
formatChars = formatChars + val
argsParseTuple = argsParseTuple + ", " + argCvt.GetParseTupleArg()
codePobjects = codePobjects + argCvt.DeclareParseArgTupleInputConverter()
codePost = codePost + argCvt.GetParsePostCode()
needConversion = needConversion or argCvt.NeedUSES_CONVERSION()
cleanup = cleanup + argCvt.GetInterfaceArgCleanup()
cleanup_gil = cleanup_gil + argCvt.GetInterfaceArgCleanupGIL()
comArgName, comArgDeclString = argCvt.GetInterfaceCppObjectInfo()
if comArgDeclString: # If we should declare a variable
codeCobjects = codeCobjects + "\t%s;\n" % (comArgDeclString)
argsCOM = argsCOM + ", " + comArgName
except makegwparse.error_not_supported as why:
f.write('// *** The input argument %s of type "%s" was not processed ***\n// Please check the conversion function is appropriate and exists!\n' % (arg.name, arg.raw_type))
f.write('\t%s %s;\n\tPyObject *ob%s;\n' % (arg.type, arg.name, arg.name))
f.write('\t// @pyparm <o Py%s>|%s||Description for %s\n' % (arg.type, arg.name, arg.name))
codePost = codePost + '\tif (bPythonIsHappy && !PyObject_As%s( ob%s, &%s )) bPythonIsHappy = FALSE;\n' % (arg.type, arg.name, arg.name)
formatChars = formatChars + "O"
argsParseTuple = argsParseTuple + ", &ob%s" % (arg.name)
argsCOM = argsCOM + ", " + arg.name
cleanup = cleanup + "\tPyObject_Free%s(%s);\n" % (arg.type, arg.name)
if needConversion: f.write("\tUSES_CONVERSION;\n")
f.write(codePobjects);
f.write(codeCobjects);
f.write('\tif ( !PyArg_ParseTuple(args, "%s:%s"%s) )\n\t\treturn NULL;\n' % (formatChars, method.name, argsParseTuple))
if codePost:
f.write('\tBOOL bPythonIsHappy = TRUE;\n')
f.write(codePost);
f.write('\tif (!bPythonIsHappy) return NULL;\n')
strdict['argsCOM'] = argsCOM[1:]
strdict['cleanup'] = cleanup
strdict['cleanup_gil'] = cleanup_gil
f.write(\
''' HRESULT hr;
PY_INTERFACE_PRECALL;
hr = p%(ptr)s->%(method)s(%(argsCOM)s );
%(cleanup)s
PY_INTERFACE_POSTCALL;
%(cleanup_gil)s
if ( FAILED(hr) )
return PyCom_BuildPyException(hr, p%(ptr)s, IID_%(interfacename)s );
''' % strdict)
codePre = codePost = formatChars = codeVarsPass = codeDecl = ""
for arg in method.args:
if not arg.HasAttribute("out"):
continue
try:
argCvt = makegwparse.make_arg_converter(arg)
formatChar = argCvt.GetFormatChar()
if formatChar:
formatChars = formatChars + formatChar
codePre = codePre + argCvt.GetBuildForInterfacePreCode()
codePost = codePost + argCvt.GetBuildForInterfacePostCode()
codeVarsPass = codeVarsPass + ", " + argCvt.GetBuildValueArg()
codeDecl = codeDecl + argCvt.DeclareParseArgTupleInputConverter()
except makegwparse.error_not_supported as why:
f.write('// *** The output argument %s of type "%s" was not processed ***\n// %s\n' % (arg.name, arg.raw_type, why))
continue
if formatChars:
f.write('%s\n%s\tPyObject *pyretval = Py_BuildValue("%s"%s);\n%s\treturn pyretval;' % (codeDecl, codePre, formatChars, codeVarsPass, codePost))
else:
f.write('\tPy_INCREF(Py_None);\n\treturn Py_None;\n')
f.write('\n}\n\n')
f.write ('// @object Py%s|Description of the interface\n' % (name))
f.write('static struct PyMethodDef Py%s_methods[] =\n{\n' % name)
for method in interface.methods:
f.write('\t{ "%s", Py%s::%s, 1 }, // @pymeth %s|Description of %s\n' % (method.name, interface.name, method.name, method.name, method.name))
interfacebase = interface.base
f.write('''\
{ NULL }
};
PyComTypeObject Py%(name)s::type("Py%(name)s",
&Py%(interfacebase)s::type,
sizeof(Py%(name)s),
Py%(name)s_methods,
GET_PYCOM_CTOR(Py%(name)s));
''' % locals())
def _write_gw_h(f, interface):
if interface.name[0] == "I":
gname = 'PyG' + interface.name[1:]
else:
gname = 'PyG' + interface.name
name = interface.name
if interface.base == "IUnknown" or interface.base == "IDispatch":
base_name = "PyGatewayBase"
else:
if interface.base[0] == "I":
base_name = 'PyG' + interface.base[1:]
else:
base_name = 'PyG' + interface.base
f.write(\
'''\
// ---------------------------------------------------
//
// Gateway Declaration
class %s : public %s, public %s
{
protected:
%s(PyObject *instance) : %s(instance) { ; }
PYGATEWAY_MAKE_SUPPORT2(%s, %s, IID_%s, %s)
''' % (gname, base_name, name, gname, base_name, gname, name, name, base_name))
if interface.base != "IUnknown":
f.write("\t// %s\n\t// *** Manually add %s method decls here\n\n" % (interface.base, interface.base))
else:
f.write('\n\n')
f.write("\t// %s\n" % name)
for method in interface.methods:
f.write('\tSTDMETHOD(%s)(\n' % method.name)
if method.args:
for arg in method.args[:-1]:
f.write("\t\t%s,\n" % (arg.GetRawDeclaration()))
arg = method.args[-1]
f.write("\t\t%s);\n\n" % (arg.GetRawDeclaration()))
else:
f.write('\t\tvoid);\n\n')
f.write('};\n')
f.close()
def _write_gw_cpp(f, interface):
if interface.name[0] == "I":
gname = 'PyG' + interface.name[1:]
else:
gname = 'PyG' + interface.name
name = interface.name
if interface.base == "IUnknown" or interface.base == "IDispatch":
base_name = "PyGatewayBase"
else:
if interface.base[0] == "I":
base_name = 'PyG' + interface.base[1:]
else:
base_name = 'PyG' + interface.base
f.write('''\
// ---------------------------------------------------
//
// Gateway Implementation
''' % {'name':name, 'gname':gname, 'base_name':base_name})
for method in interface.methods:
f.write(\
'''\
STDMETHODIMP %s::%s(
''' % (gname, method.name))
if method.args:
for arg in method.args[:-1]:
inoutstr = ']['.join(arg.inout)
f.write("\t\t/* [%s] */ %s,\n" % (inoutstr, arg.GetRawDeclaration()))
arg = method.args[-1]
inoutstr = ']['.join(arg.inout)
f.write("\t\t/* [%s] */ %s)\n" % (inoutstr, arg.GetRawDeclaration()))
else:
f.write('\t\tvoid)\n')
f.write("{\n\tPY_GATEWAY_METHOD;\n")
cout = 0
codePre = codePost = codeVars = ""
argStr = ""
needConversion = 0
formatChars = ""
if method.args:
for arg in method.args:
if arg.HasAttribute("out"):
cout = cout + 1
if arg.indirectionLevel ==2 :
f.write("\tif (%s==NULL) return E_POINTER;\n" % arg.name)
if arg.HasAttribute("in"):
try:
argCvt = makegwparse.make_arg_converter(arg)
argCvt.SetGatewayMode()
formatchar = argCvt.GetFormatChar();
needConversion = needConversion or argCvt.NeedUSES_CONVERSION()
if formatchar:
formatChars = formatChars + formatchar
codeVars = codeVars + argCvt.DeclareParseArgTupleInputConverter()
argStr = argStr + ", " + argCvt.GetBuildValueArg()
codePre = codePre + argCvt.GetBuildForGatewayPreCode()
codePost = codePost + argCvt.GetBuildForGatewayPostCode()
except makegwparse.error_not_supported as why:
f.write('// *** The input argument %s of type "%s" was not processed ***\n// - Please ensure this conversion function exists, and is appropriate\n// - %s\n' % (arg.name, arg.raw_type, why))
f.write('\tPyObject *ob%s = PyObject_From%s(%s);\n' % (arg.name, arg.type, arg.name))
f.write('\tif (ob%s==NULL) return MAKE_PYCOM_GATEWAY_FAILURE_CODE("%s");\n' % (arg.name, method.name))
codePost = codePost + "\tPy_DECREF(ob%s);\n" % arg.name
formatChars = formatChars + "O"
argStr = argStr + ", ob%s" % (arg.name)
if needConversion: f.write('\tUSES_CONVERSION;\n')
f.write(codeVars)
f.write(codePre)
if cout:
f.write("\tPyObject *result;\n")
resStr = "&result"
else:
resStr = "NULL"
if formatChars:
fullArgStr = '%s, "%s"%s' % (resStr, formatChars, argStr)
else:
fullArgStr = resStr
f.write('\tHRESULT hr=InvokeViaPolicy("%s", %s);\n' % (method.name, fullArgStr))
f.write(codePost)
if cout:
f.write("\tif (FAILED(hr)) return hr;\n")
f.write("\t// Process the Python results, and convert back to the real params\n")
# process the output arguments.
formatChars = codePobjects = codePost = argsParseTuple = ""
needConversion = 0
for arg in method.args:
if not arg.HasAttribute("out"):
continue
try:
argCvt = makegwparse.make_arg_converter(arg)
argCvt.SetGatewayMode()
val = argCvt.GetFormatChar()
if val:
formatChars = formatChars + val
argsParseTuple = argsParseTuple + ", " + argCvt.GetParseTupleArg()
codePobjects = codePobjects + argCvt.DeclareParseArgTupleInputConverter()
codePost = codePost + argCvt.GetParsePostCode()
needConversion = needConversion or argCvt.NeedUSES_CONVERSION()
except makegwparse.error_not_supported as why:
f.write('// *** The output argument %s of type "%s" was not processed ***\n// %s\n' % (arg.name, arg.raw_type, why))
if formatChars: # If I have any to actually process.
if len(formatChars)==1:
parseFn = "PyArg_Parse"
else:
parseFn = "PyArg_ParseTuple"
if codePobjects: f.write(codePobjects)
f.write('\tif (!%s(result, "%s" %s))\n\t\treturn MAKE_PYCOM_GATEWAY_FAILURE_CODE("%s");\n' % (parseFn, formatChars, argsParseTuple, method.name))
if codePost:
f.write('\tBOOL bPythonIsHappy = TRUE;\n')
f.write(codePost)
f.write('\tif (!bPythonIsHappy) hr = MAKE_PYCOM_GATEWAY_FAILURE_CODE("%s");\n' % method.name)
f.write('\tPy_DECREF(result);\n');
f.write('\treturn hr;\n}\n\n')
def test():
# make_framework_support("d:\\msdev\\include\\objidl.h", "ILockBytes")
make_framework_support("d:\\msdev\\include\\objidl.h", "IStorage")
# make_framework_support("d:\\msdev\\include\\objidl.h", "IEnumSTATSTG")

View file

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

View file

@ -0,0 +1,783 @@
"""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 PyTime>"
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)))