You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ORPA-pyOpenRPA/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/comtypes/tools/tlbparser.py

753 lines
30 KiB

import sys
from comtypes import automation, typeinfo, COMError
from comtypes.tools import typedesc
from ctypes import c_void_p, sizeof, alignment
try:
set
except NameError:
from sets import Set as set
# Is the process 64-bit?
is_64bits = sys.maxsize > 2**32
################################
def PTR(typ):
return typedesc.PointerType(typ,
sizeof(c_void_p)*8,
alignment(c_void_p)*8)
# basic C data types, with size and alignment in bits
char_type = typedesc.FundamentalType("char", 8, 8)
uchar_type = typedesc.FundamentalType("unsigned char", 8, 8)
wchar_t_type = typedesc.FundamentalType("wchar_t", 16, 16)
short_type = typedesc.FundamentalType("short int", 16, 16)
ushort_type = typedesc.FundamentalType("short unsigned int", 16, 16)
int_type = typedesc.FundamentalType("int", 32, 32)
uint_type = typedesc.FundamentalType("unsigned int", 32, 32)
long_type = typedesc.FundamentalType("long int", 32, 32)
ulong_type = typedesc.FundamentalType("long unsigned int", 32, 32)
longlong_type = typedesc.FundamentalType("long long int", 64, 64)
ulonglong_type = typedesc.FundamentalType("long long unsigned int", 64, 64)
float_type = typedesc.FundamentalType("float", 32, 32)
double_type = typedesc.FundamentalType("double", 64, 64)
# basic COM data types
BSTR_type = typedesc.Typedef("BSTR", PTR(wchar_t_type))
SCODE_type = typedesc.Typedef("SCODE", int_type)
VARIANT_BOOL_type = typedesc.Typedef("VARIANT_BOOL", short_type)
HRESULT_type = typedesc.Typedef("HRESULT", ulong_type)
VARIANT_type = typedesc.Structure("VARIANT",
align=alignment(automation.VARIANT)*8,
members=[], bases=[],
size=sizeof(automation.VARIANT)*8)
IDISPATCH_type = typedesc.Typedef("IDispatch", None)
IUNKNOWN_type = typedesc.Typedef("IUnknown", None)
DECIMAL_type = typedesc.Structure("DECIMAL",
align=alignment(automation.DECIMAL)*8,
members=[], bases=[],
size=sizeof(automation.DECIMAL)*8)
def midlSAFEARRAY(typ):
return typedesc.SAFEARRAYType(typ)
# faked COM data types
CURRENCY_type = longlong_type # slightly wrong; should be scaled by 10000 - use subclass of longlong?
DATE_type = double_type # not *that* wrong...
COMTYPES = {
automation.VT_I2: short_type, # 2
automation.VT_I4: int_type, # 3
automation.VT_R4: float_type, # 4
automation.VT_R8: double_type, # 5
automation.VT_CY: CURRENCY_type, # 6
automation.VT_DATE: DATE_type, # 7
automation.VT_BSTR: BSTR_type, # 8
automation.VT_DISPATCH: PTR(IDISPATCH_type), # 9
automation.VT_ERROR: SCODE_type, # 10
automation.VT_BOOL: VARIANT_BOOL_type, # 11
automation.VT_VARIANT: VARIANT_type, # 12
automation.VT_UNKNOWN: PTR(IUNKNOWN_type), # 13
automation.VT_DECIMAL: DECIMAL_type, # 14
automation.VT_I1: char_type, # 16
automation.VT_UI1: uchar_type, # 17
automation.VT_UI2: ushort_type, # 18
automation.VT_UI4: ulong_type, # 19
automation.VT_I8: longlong_type, # 20
automation.VT_UI8: ulonglong_type, # 21
automation.VT_INT: int_type, # 22
automation.VT_UINT: uint_type, # 23
automation.VT_VOID: typedesc.FundamentalType("void", 0, 0), # 24
automation.VT_HRESULT: HRESULT_type, # 25
automation.VT_LPSTR: PTR(char_type), # 30
automation.VT_LPWSTR: PTR(wchar_t_type), # 31
}
#automation.VT_PTR = 26 # below
#automation.VT_SAFEARRAY = 27
#automation.VT_CARRAY = 28 # below
#automation.VT_USERDEFINED = 29 # below
#automation.VT_RECORD = 36
#automation.VT_ARRAY = 8192
#automation.VT_BYREF = 16384
################################################################
class Parser(object):
def make_type(self, tdesc, tinfo):
try:
return COMTYPES[tdesc.vt]
except KeyError:
pass
if tdesc.vt == automation.VT_CARRAY:
typ = self.make_type(tdesc._.lpadesc[0].tdescElem, tinfo)
for i in range(tdesc._.lpadesc[0].cDims):
typ = typedesc.ArrayType(typ,
tdesc._.lpadesc[0].rgbounds[i].lLbound,
tdesc._.lpadesc[0].rgbounds[i].cElements-1)
return typ
elif tdesc.vt == automation.VT_PTR:
typ = self.make_type(tdesc._.lptdesc[0], tinfo)
return PTR(typ)
elif tdesc.vt == automation.VT_USERDEFINED:
try:
ti = tinfo.GetRefTypeInfo(tdesc._.hreftype)
except COMError as details:
type_name = "__error_hreftype_%d__" % tdesc._.hreftype
tlib_name = get_tlib_filename(self.tlib)
if tlib_name is None:
tlib_name = "unknown typelib"
message = "\n\tGetRefTypeInfo failed in %s: %s\n\tgenerating type '%s' instead" % \
(tlib_name, details, type_name)
import warnings
warnings.warn(message, UserWarning);
result = typedesc.Structure(type_name,
align=8,
members=[], bases=[],
size=0)
return result
result = self.parse_typeinfo(ti)
assert result is not None, ti.GetDocumentation(-1)[0]
return result
elif tdesc.vt == automation.VT_SAFEARRAY:
# SAFEARRAY(<type>), see Don Box pp.331f
itemtype = self.make_type(tdesc._.lptdesc[0], tinfo)
return midlSAFEARRAY(itemtype)
raise NotImplementedError(tdesc.vt)
################################################################
# TKIND_ENUM = 0
def ParseEnum(self, tinfo, ta):
ta = tinfo.GetTypeAttr()
enum_name = tinfo.GetDocumentation(-1)[0]
enum = typedesc.Enumeration(enum_name, 32, 32)
self._register(enum_name, enum)
for i in range(ta.cVars):
vd = tinfo.GetVarDesc(i)
name = tinfo.GetDocumentation(vd.memid)[0]
assert vd.varkind == typeinfo.VAR_CONST
num_val = vd._.lpvarValue[0].value
v = typedesc.EnumValue(name, num_val, enum)
enum.add_value(v)
return enum
# TKIND_RECORD = 1
def ParseRecord(self, tinfo, ta):
members = [] # will be filled later
struct_name, doc, helpcntext, helpfile = tinfo.GetDocumentation(-1)
struct = typedesc.Structure(struct_name,
align=ta.cbAlignment*8,
members=members,
bases=[],
size=ta.cbSizeInstance*8)
self._register(struct_name, struct)
tlib, _ = tinfo.GetContainingTypeLib()
tlib_ta = tlib.GetLibAttr()
# If this is a 32-bit typlib being loaded in a 64-bit process, then the
# size and alignment are incorrect. Set the size to None to disable
# size checks and correct the alignment.
if is_64bits and tlib_ta.syskind == typeinfo.SYS_WIN32:
struct.size = None
struct.align = 64
if ta.guid:
struct._recordinfo_ = (str(tlib_ta.guid),
tlib_ta.wMajorVerNum, tlib_ta.wMinorVerNum,
tlib_ta.lcid,
str(ta.guid))
for i in range(ta.cVars):
vd = tinfo.GetVarDesc(i)
name = tinfo.GetDocumentation(vd.memid)[0]
offset = vd._.oInst * 8
assert vd.varkind == typeinfo.VAR_PERINSTANCE
typ = self.make_type(vd.elemdescVar.tdesc, tinfo)
field = typedesc.Field(name,
typ,
None, # bits
offset)
members.append(field)
return struct
# TKIND_MODULE = 2
def ParseModule(self, tinfo, ta):
assert 0 == ta.cImplTypes
# functions
for i in range(ta.cFuncs):
# We skip all function definitions. There are several
# problems with these, and we can, for comtypes, ignore them.
continue
fd = tinfo.GetFuncDesc(i)
dllname, func_name, ordinal = tinfo.GetDllEntry(fd.memid, fd.invkind)
func_doc = tinfo.GetDocumentation(fd.memid)[1]
assert 0 == fd.cParamsOpt # XXX
returns = self.make_type(fd.elemdescFunc.tdesc, tinfo)
if fd.callconv == typeinfo.CC_CDECL:
attributes = "__cdecl__"
elif fd.callconv == typeinfo.CC_STDCALL:
attributes = "__stdcall__"
else:
raise ValueError("calling convention %d" % fd.callconv)
func = typedesc.Function(func_name, returns, attributes, extern=1)
if func_doc is not None:
func.doc = func_doc.encode("mbcs")
func.dllname = dllname
self._register(func_name, func)
for i in range(fd.cParams):
argtype = self.make_type(fd.lprgelemdescParam[i].tdesc, tinfo)
func.add_argument(argtype)
# constants
for i in range(ta.cVars):
vd = tinfo.GetVarDesc(i)
name, var_doc = tinfo.GetDocumentation(vd.memid)[0:2]
assert vd.varkind == typeinfo.VAR_CONST
typ = self.make_type(vd.elemdescVar.tdesc, tinfo)
var_value = vd._.lpvarValue[0].value
v = typedesc.Constant(name, typ, var_value)
self._register(name, v)
if var_doc is not None:
v.doc = var_doc
# TKIND_INTERFACE = 3
def ParseInterface(self, tinfo, ta):
itf_name, itf_doc = tinfo.GetDocumentation(-1)[0:2]
assert ta.cImplTypes <= 1
if ta.cImplTypes == 0 and itf_name != "IUnknown":
# Windows defines an interface IOleControlTypes in ocidl.idl.
# Don't known what artefact that is - we ignore it.
# It's an interface without methods anyway.
if itf_name != "IOleControlTypes":
message = "Ignoring interface %s which has no base interface" % itf_name
import warnings
warnings.warn(message, UserWarning);
return None
itf = typedesc.ComInterface(itf_name,
members=[],
base=None,
iid=str(ta.guid),
idlflags=self.interface_type_flags(ta.wTypeFlags))
if itf_doc:
itf.doc = itf_doc
self._register(itf_name, itf)
if ta.cImplTypes:
hr = tinfo.GetRefTypeOfImplType(0)
tibase = tinfo.GetRefTypeInfo(hr)
itf.base = self.parse_typeinfo(tibase)
assert ta.cVars == 0, "vars on an Interface?"
members = []
for i in range(ta.cFuncs):
fd = tinfo.GetFuncDesc(i)
## func_name = tinfo.GetDocumentation(fd.memid)[0]
func_name, func_doc = tinfo.GetDocumentation(fd.memid)[:2]
assert fd.funckind == typeinfo.FUNC_PUREVIRTUAL
returns = self.make_type(fd.elemdescFunc.tdesc, tinfo)
names = tinfo.GetNames(fd.memid, fd.cParams+1)
names.append("rhs")
names = names[:fd.cParams + 1]
assert len(names) == fd.cParams + 1
flags = self.func_flags(fd.wFuncFlags)
flags += self.inv_kind(fd.invkind)
mth = typedesc.ComMethod(fd.invkind, fd.memid, func_name, returns, flags, func_doc)
mth.oVft = fd.oVft
for p in range(fd.cParams):
typ = self.make_type(fd.lprgelemdescParam[p].tdesc, tinfo)
name = names[p+1]
flags = fd.lprgelemdescParam[p]._.paramdesc.wParamFlags
if flags & typeinfo.PARAMFLAG_FHASDEFAULT:
# XXX should be handled by VARIANT itself
var = fd.lprgelemdescParam[p]._.paramdesc.pparamdescex[0].varDefaultValue
default = var.value
else:
default = None
mth.add_argument(typ, name, self.param_flags(flags), default)
members.append((fd.oVft, mth))
# Sort the methods by oVft (VTable offset): Some typeinfo
# don't list methods in VTable order.
members.sort()
itf.members.extend([m[1] for m in members])
return itf
# TKIND_DISPATCH = 4
def ParseDispatch(self, tinfo, ta):
itf_name, doc = tinfo.GetDocumentation(-1)[0:2]
assert ta.cImplTypes == 1
hr = tinfo.GetRefTypeOfImplType(0)
tibase = tinfo.GetRefTypeInfo(hr)
base = self.parse_typeinfo(tibase)
members = []
itf = typedesc.DispInterface(itf_name,
members=members,
base=base,
iid=str(ta.guid),
idlflags=self.interface_type_flags(ta.wTypeFlags))
if doc is not None:
itf.doc = str(doc.split("\0")[0])
self._register(itf_name, itf)
# This code can only handle pure dispinterfaces. Dual
# interfaces are parsed in ParseInterface().
assert ta.wTypeFlags & typeinfo.TYPEFLAG_FDUAL == 0
for i in range(ta.cVars):
vd = tinfo.GetVarDesc(i)
assert vd.varkind == typeinfo.VAR_DISPATCH
var_name, var_doc = tinfo.GetDocumentation(vd.memid)[0:2]
typ = self.make_type(vd.elemdescVar.tdesc, tinfo)
mth = typedesc.DispProperty(vd.memid, var_name, typ, self.var_flags(vd.wVarFlags), var_doc)
itf.members.append(mth)
# At least the EXCEL typelib lists the IUnknown and IDispatch
# methods even for this kind of interface. I didn't find any
# indication about these methods in the various flags, so we
# have to exclude them by name.
# CLF: 12/14/2012 Do this in a way that does not exclude other methods.
# I have encountered typlibs where only "QueryInterface", "AddRef"
# and "Release" are to be skipped.
ignored_names = set(["QueryInterface", "AddRef", "Release",
"GetTypeInfoCount", "GetTypeInfo",
"GetIDsOfNames", "Invoke"])
for i in range(ta.cFuncs):
fd = tinfo.GetFuncDesc(i)
func_name, func_doc = tinfo.GetDocumentation(fd.memid)[:2]
if func_name in ignored_names:
continue
assert fd.funckind == typeinfo.FUNC_DISPATCH
returns = self.make_type(fd.elemdescFunc.tdesc, tinfo)
names = tinfo.GetNames(fd.memid, fd.cParams+1)
names.append("rhs")
names = names[:fd.cParams + 1]
assert len(names) == fd.cParams + 1 # function name first, then parameter names
flags = self.func_flags(fd.wFuncFlags)
flags += self.inv_kind(fd.invkind)
mth = typedesc.DispMethod(fd.memid, fd.invkind, func_name, returns, flags, func_doc)
for p in range(fd.cParams):
typ = self.make_type(fd.lprgelemdescParam[p].tdesc, tinfo)
name = names[p+1]
flags = fd.lprgelemdescParam[p]._.paramdesc.wParamFlags
if flags & typeinfo.PARAMFLAG_FHASDEFAULT:
var = fd.lprgelemdescParam[p]._.paramdesc.pparamdescex[0].varDefaultValue
default = var.value
else:
default = None
mth.add_argument(typ, name, self.param_flags(flags), default)
itf.members.append(mth)
return itf
def inv_kind(self, invkind):
NAMES = {automation.DISPATCH_METHOD: [],
automation.DISPATCH_PROPERTYPUT: ["propput"],
automation.DISPATCH_PROPERTYPUTREF: ["propputref"],
automation.DISPATCH_PROPERTYGET: ["propget"]}
return NAMES[invkind]
def func_flags(self, flags):
# map FUNCFLAGS values to idl attributes
NAMES = {typeinfo.FUNCFLAG_FRESTRICTED: "restricted",
typeinfo.FUNCFLAG_FSOURCE: "source",
typeinfo.FUNCFLAG_FBINDABLE: "bindable",
typeinfo.FUNCFLAG_FREQUESTEDIT: "requestedit",
typeinfo.FUNCFLAG_FDISPLAYBIND: "displaybind",
typeinfo.FUNCFLAG_FDEFAULTBIND: "defaultbind",
typeinfo.FUNCFLAG_FHIDDEN: "hidden",
typeinfo.FUNCFLAG_FUSESGETLASTERROR: "usesgetlasterror",
typeinfo.FUNCFLAG_FDEFAULTCOLLELEM: "defaultcollelem",
typeinfo.FUNCFLAG_FUIDEFAULT: "uidefault",
typeinfo.FUNCFLAG_FNONBROWSABLE: "nonbrowsable",
# typeinfo.FUNCFLAG_FREPLACEABLE: "???",
typeinfo.FUNCFLAG_FIMMEDIATEBIND: "immediatebind"}
return [NAMES[bit] for bit in NAMES if bit & flags]
def param_flags(self, flags):
# map PARAMFLAGS values to idl attributes
NAMES = {typeinfo.PARAMFLAG_FIN: "in",
typeinfo.PARAMFLAG_FOUT: "out",
typeinfo.PARAMFLAG_FLCID: "lcid",
typeinfo.PARAMFLAG_FRETVAL: "retval",
typeinfo.PARAMFLAG_FOPT: "optional",
# typeinfo.PARAMFLAG_FHASDEFAULT: "",
# typeinfo.PARAMFLAG_FHASCUSTDATA: "",
}
return [NAMES[bit] for bit in NAMES if bit & flags]
def coclass_type_flags(self, flags):
# map TYPEFLAGS values to idl attributes
NAMES = {typeinfo.TYPEFLAG_FAPPOBJECT: "appobject",
# typeinfo.TYPEFLAG_FCANCREATE:
typeinfo.TYPEFLAG_FLICENSED: "licensed",
# typeinfo.TYPEFLAG_FPREDECLID:
typeinfo.TYPEFLAG_FHIDDEN: "hidden",
typeinfo.TYPEFLAG_FCONTROL: "control",
typeinfo.TYPEFLAG_FDUAL: "dual",
typeinfo.TYPEFLAG_FNONEXTENSIBLE: "nonextensible",
typeinfo.TYPEFLAG_FOLEAUTOMATION: "oleautomation",
typeinfo.TYPEFLAG_FRESTRICTED: "restricted",
typeinfo.TYPEFLAG_FAGGREGATABLE: "aggregatable",
# typeinfo.TYPEFLAG_FREPLACEABLE:
# typeinfo.TYPEFLAG_FDISPATCHABLE # computed, no flag for this
typeinfo.TYPEFLAG_FREVERSEBIND: "reversebind",
typeinfo.TYPEFLAG_FPROXY: "proxy",
}
NEGATIVE_NAMES = {typeinfo.TYPEFLAG_FCANCREATE: "noncreatable"}
return [NAMES[bit] for bit in NAMES if bit & flags] + \
[NEGATIVE_NAMES[bit] for bit in NEGATIVE_NAMES if not (bit & flags)]
def interface_type_flags(self, flags):
# map TYPEFLAGS values to idl attributes
NAMES = {typeinfo.TYPEFLAG_FAPPOBJECT: "appobject",
# typeinfo.TYPEFLAG_FCANCREATE:
typeinfo.TYPEFLAG_FLICENSED: "licensed",
# typeinfo.TYPEFLAG_FPREDECLID:
typeinfo.TYPEFLAG_FHIDDEN: "hidden",
typeinfo.TYPEFLAG_FCONTROL: "control",
typeinfo.TYPEFLAG_FDUAL: "dual",
typeinfo.TYPEFLAG_FNONEXTENSIBLE: "nonextensible",
typeinfo.TYPEFLAG_FOLEAUTOMATION: "oleautomation",
typeinfo.TYPEFLAG_FRESTRICTED: "restricted",
typeinfo.TYPEFLAG_FAGGREGATABLE: "aggregatable",
# typeinfo.TYPEFLAG_FREPLACEABLE:
# typeinfo.TYPEFLAG_FDISPATCHABLE # computed, no flag for this
typeinfo.TYPEFLAG_FREVERSEBIND: "reversebind",
typeinfo.TYPEFLAG_FPROXY: "proxy",
}
NEGATIVE_NAMES = {}
return [NAMES[bit] for bit in NAMES if bit & flags] + \
[NEGATIVE_NAMES[bit] for bit in NEGATIVE_NAMES if not (bit & flags)]
def var_flags(self, flags):
NAMES = {typeinfo.VARFLAG_FREADONLY: "readonly",
typeinfo.VARFLAG_FSOURCE: "source",
typeinfo.VARFLAG_FBINDABLE: "bindable",
typeinfo.VARFLAG_FREQUESTEDIT: "requestedit",
typeinfo.VARFLAG_FDISPLAYBIND: "displaybind",
typeinfo.VARFLAG_FDEFAULTBIND: "defaultbind",
typeinfo.VARFLAG_FHIDDEN: "hidden",
typeinfo.VARFLAG_FRESTRICTED: "restricted",
typeinfo.VARFLAG_FDEFAULTCOLLELEM: "defaultcollelem",
typeinfo.VARFLAG_FUIDEFAULT: "uidefault",
typeinfo.VARFLAG_FNONBROWSABLE: "nonbrowsable",
typeinfo.VARFLAG_FREPLACEABLE: "replaceable",
typeinfo.VARFLAG_FIMMEDIATEBIND: "immediatebind"
}
return [NAMES[bit] for bit in NAMES if bit & flags]
# TKIND_COCLASS = 5
def ParseCoClass(self, tinfo, ta):
# possible ta.wTypeFlags: helpstring, helpcontext, licensed,
# version, control, hidden, and appobject
coclass_name, doc = tinfo.GetDocumentation(-1)[0:2]
tlibattr = tinfo.GetContainingTypeLib()[0].GetLibAttr()
coclass = typedesc.CoClass(coclass_name,
str(ta.guid),
self.coclass_type_flags(ta.wTypeFlags),
tlibattr)
if doc is not None:
coclass.doc = doc
self._register(coclass_name, coclass)
for i in range(ta.cImplTypes):
hr = tinfo.GetRefTypeOfImplType(i)
ti = tinfo.GetRefTypeInfo(hr)
itf = self.parse_typeinfo(ti)
flags = tinfo.GetImplTypeFlags(i)
coclass.add_interface(itf, flags)
return coclass
# TKIND_ALIAS = 6
def ParseAlias(self, tinfo, ta):
name = tinfo.GetDocumentation(-1)[0]
typ = self.make_type(ta.tdescAlias, tinfo)
alias = typedesc.Typedef(name, typ)
self._register(name, alias)
return alias
# TKIND_UNION = 7
def ParseUnion(self, tinfo, ta):
union_name, doc, helpcntext, helpfile = tinfo.GetDocumentation(-1)
members = []
union = typedesc.Union(union_name,
align=ta.cbAlignment*8,
members=members,
bases=[],
size=ta.cbSizeInstance*8)
self._register(union_name, union)
tlib, _ = tinfo.GetContainingTypeLib()
tlib_ta = tlib.GetLibAttr()
# If this is a 32-bit typlib being loaded in a 64-bit process, then the
# size and alignment are incorrect. Set the size to None to disable
# size checks and correct the alignment.
if is_64bits and tlib_ta.syskind == typeinfo.SYS_WIN32:
union.size = None
union.align = 64
for i in range(ta.cVars):
vd = tinfo.GetVarDesc(i)
name = tinfo.GetDocumentation(vd.memid)[0]
offset = vd._.oInst * 8
assert vd.varkind == typeinfo.VAR_PERINSTANCE
typ = self.make_type(vd.elemdescVar.tdesc, tinfo)
field = typedesc.Field(name,
typ,
None, # bits
offset)
members.append(field)
return union
################################################################
def _typelib_module(self, tlib=None):
if tlib is None:
tlib = self.tlib
# return a string that uniquely identifies a typelib.
# The string doesn't have any meaning outside this instance.
return str(tlib.GetLibAttr())
def _register(self, name, value, tlib=None):
modname = self._typelib_module(tlib)
fullname = "%s.%s" % (modname, name)
if fullname in self.items:
# XXX Can we really allow this? It happens, at least.
if isinstance(value, typedesc.External):
return
# BUG: We try to register an item that's already registered.
raise ValueError("Bug: Multiple registered name '%s': %r" % (name, value))
self.items[fullname] = value
def parse_typeinfo(self, tinfo):
name = tinfo.GetDocumentation(-1)[0]
modname = self._typelib_module()
try:
return self.items["%s.%s" % (modname, name)]
except KeyError:
pass
tlib = tinfo.GetContainingTypeLib()[0]
if tlib != self.tlib:
ta = tinfo.GetTypeAttr()
size = ta.cbSizeInstance * 8
align = ta.cbAlignment * 8
typ = typedesc.External(tlib,
name,
size,
align,
tlib.GetDocumentation(-1)[:2])
self._register(name, typ, tlib)
return typ
ta = tinfo.GetTypeAttr()
tkind = ta.typekind
if tkind == typeinfo.TKIND_ENUM: # 0
return self.ParseEnum(tinfo, ta)
elif tkind == typeinfo.TKIND_RECORD: # 1
return self.ParseRecord(tinfo, ta)
elif tkind == typeinfo.TKIND_MODULE: # 2
return self.ParseModule(tinfo, ta)
elif tkind == typeinfo.TKIND_INTERFACE: # 3
return self.ParseInterface(tinfo, ta)
elif tkind == typeinfo.TKIND_DISPATCH: # 4
try:
# GetRefTypeOfImplType(-1) returns the custom portion
# of a dispinterface, if it is dual
href = tinfo.GetRefTypeOfImplType(-1)
except COMError:
# no dual interface
return self.ParseDispatch(tinfo, ta)
tinfo = tinfo.GetRefTypeInfo(href)
ta = tinfo.GetTypeAttr()
assert ta.typekind == typeinfo.TKIND_INTERFACE
return self.ParseInterface(tinfo, ta)
elif tkind == typeinfo.TKIND_COCLASS: # 5
return self.ParseCoClass(tinfo, ta)
elif tkind == typeinfo.TKIND_ALIAS: # 6
return self.ParseAlias(tinfo, ta)
elif tkind == typeinfo.TKIND_UNION: # 7
return self.ParseUnion(tinfo, ta)
else:
print("NYI", tkind)
## raise "NYI", tkind
def parse_LibraryDescription(self):
la = self.tlib.GetLibAttr()
name, doc = self.tlib.GetDocumentation(-1)[:2]
desc = typedesc.TypeLib(name,
str(la.guid), la.wMajorVerNum, la.wMinorVerNum,
doc)
self._register(None, desc)
################################################################
def parse(self):
self.parse_LibraryDescription()
for i in range(self.tlib.GetTypeInfoCount()):
tinfo = self.tlib.GetTypeInfo(i)
self.parse_typeinfo(tinfo)
return self.items
class TlbFileParser(Parser):
"Parses a type library from a file"
def __init__(self, path):
# XXX DOESN'T LOOK CORRECT: We should NOT register the typelib.
self.tlib = typeinfo.LoadTypeLibEx(path)#, regkind=typeinfo.REGKIND_REGISTER)
self.items = {}
class TypeLibParser(Parser):
def __init__(self, tlib):
self.tlib = tlib
self.items = {}
################################################################
# some interesting typelibs
## these do NOT work:
# XXX infinite loop?
## path = r"mshtml.tlb" # has propputref
# has SAFEARRAY
# HRESULT Run(BSTR, SAFEARRAY(VARIANT)*, VARIANT*)
## path = "msscript.ocx"
# has SAFEARRAY
# HRESULT AddAddress(SAFEARRAY(BSTR)*, SAFEARRAY(BSTR)*)
## path = r"c:\Programme\Microsoft Office\Office\MSWORD8.OLB" # has propputref
# has SAFEARRAY:
# SAFEARRAY(unsigned char) FileSignatureInfo(BSTR, long, MsiSignatureInfo)
## path = r"msi.dll" # DispProperty
# fails packing IDLDESC
## path = r"C:\Dokumente und Einstellungen\thomas\Desktop\tlb\win.tlb"
# fails packing WIN32_FIND_DATA
## path = r"C:\Dokumente und Einstellungen\thomas\Desktop\tlb\win32.tlb"
# has a POINTER(IUnknown) as default parameter value
## path = r"c:\Programme\Gemeinsame Dateien\Microsoft Shared\Speech\sapi.dll"
## path = r"hnetcfg.dll"
## path = r"simpdata.tlb"
## path = r"nscompat.tlb"
## path = r"stdole32.tlb"
## path = r"shdocvw.dll"
## path = r"c:\Programme\Microsoft Office\Office\MSO97.DLL"
## path = r"PICCLP32.OCX" # DispProperty
## path = r"MSHFLXGD.OCX" # DispProperty, propputref
## path = r"scrrun.dll" # propput AND propputref on IDictionary::Item
## path = r"C:\Dokumente und Einstellungen\thomas\Desktop\tlb\threadapi.tlb"
## path = r"..\samples\BITS\bits2_0.tlb"
## path = r"c:\vc98\include\activscp.tlb"
def get_tlib_filename(tlib):
# seems if the typelib is not registered, there's no way to
# determine the filename.
from ctypes import windll, byref
from comtypes import BSTR
la = tlib.GetLibAttr()
name = BSTR()
try:
windll.oleaut32.QueryPathOfRegTypeLib
except AttributeError:
# Windows CE doesn't have this function
return None
if 0 == windll.oleaut32.QueryPathOfRegTypeLib(byref(la.guid),
la.wMajorVerNum,
la.wMinorVerNum,
0, # lcid
byref(name)
):
return name.value.split("\0")[0]
return None
def _py2exe_hint():
# If the tlbparser is frozen, we need to include these
import comtypes.persist
import comtypes.typeinfo
import comtypes.automation
def generate_module(tlib, ofi, pathname):
known_symbols = {}
for name in ("comtypes.persist",
"comtypes.typeinfo",
"comtypes.automation",
"comtypes._others",
"comtypes",
"ctypes.wintypes",
"ctypes"):
try:
mod = __import__(name)
except ImportError:
if name == "comtypes._others":
continue
raise
for submodule in name.split(".")[1:]:
mod = getattr(mod, submodule)
for name in mod.__dict__:
known_symbols[name] = mod.__name__
p = TypeLibParser(tlib)
if pathname is None:
pathname = get_tlib_filename(tlib)
items = p.parse()
from .codegenerator import Generator
gen = Generator(ofi,
known_symbols=known_symbols,
)
gen.generate_code(list(items.values()), filename=pathname)
# -eof-