openmedialibrary_platform_w.../Lib/site-packages/win32com/universal.py

197 lines
8.2 KiB
Python
Raw Normal View History

2016-04-14 19:54:42 +00:00
# Code that packs and unpacks the Univgw structures.
# See if we have a special directory for the binaries (for developers)
import types
import pythoncom
from win32com.client import gencache
com_error = pythoncom.com_error
_univgw = pythoncom._univgw
def RegisterInterfaces(typelibGUID, lcid, major, minor, interface_names = None):
ret = [] # return a list of (dispid, funcname for our policy's benefit
# First see if we have makepy support. If so, we can probably satisfy the request without loading the typelib.
try:
mod = gencache.GetModuleForTypelib(typelibGUID, lcid, major, minor)
except ImportError:
mod = None
if mod is None:
import win32com.client.build
# Load up the typelib and build (but don't cache) it now
tlb = pythoncom.LoadRegTypeLib(typelibGUID, major, minor, lcid)
typecomp_lib = tlb.GetTypeComp()
if interface_names is None:
interface_names = []
for i in range(tlb.GetTypeInfoCount()):
info = tlb.GetTypeInfo(i)
doc = tlb.GetDocumentation(i)
attr = info.GetTypeAttr()
if attr.typekind == pythoncom.TKIND_INTERFACE or \
(attr.typekind == pythoncom.TKIND_DISPATCH and attr.wTypeFlags & pythoncom.TYPEFLAG_FDUAL):
interface_names.append(doc[0])
for name in interface_names:
type_info, type_comp = typecomp_lib.BindType(name, )
# Not sure why we don't get an exception here - BindType's C
# impl looks correct..
if type_info is None:
raise ValueError("The interface '%s' can not be located" % (name,))
# If we got back a Dispatch interface, convert to the real interface.
attr = type_info.GetTypeAttr()
if attr.typekind == pythoncom.TKIND_DISPATCH:
refhtype = type_info.GetRefTypeOfImplType(-1)
type_info = type_info.GetRefTypeInfo(refhtype)
attr = type_info.GetTypeAttr()
item = win32com.client.build.VTableItem(type_info, attr, type_info.GetDocumentation(-1))
_doCreateVTable(item.clsid, item.python_name, item.bIsDispatch, item.vtableFuncs)
for info in item.vtableFuncs:
names, dispid, desc = info
invkind = desc[4]
ret.append((dispid, invkind, names[0]))
else:
# Cool - can used cached info.
if not interface_names:
interface_names = list(mod.VTablesToClassMap.values())
for name in interface_names:
try:
iid = mod.NamesToIIDMap[name]
except KeyError:
raise ValueError("Interface '%s' does not exist in this cached typelib" % (name,))
# print "Processing interface", name
sub_mod = gencache.GetModuleForCLSID(iid)
is_dispatch = getattr(sub_mod, name + "_vtables_dispatch_", None)
method_defs = getattr(sub_mod, name + "_vtables_", None)
if is_dispatch is None or method_defs is None:
raise ValueError("Interface '%s' is IDispatch only" % (name,))
# And create the univgw defn
_doCreateVTable(iid, name, is_dispatch, method_defs)
for info in method_defs:
names, dispid, desc = info
invkind = desc[4]
ret.append((dispid, invkind, names[0]))
return ret
def _doCreateVTable(iid, interface_name, is_dispatch, method_defs):
defn = Definition(iid, is_dispatch, method_defs)
vtbl = _univgw.CreateVTable(defn, is_dispatch)
_univgw.RegisterVTable(vtbl, iid, interface_name)
def _CalcTypeSize(typeTuple):
t = typeTuple[0]
if t & (pythoncom.VT_BYREF | pythoncom.VT_ARRAY):
# Its a pointer.
cb = _univgw.SizeOfVT(pythoncom.VT_PTR)[1]
elif t == pythoncom.VT_RECORD:
# Just because a type library uses records doesn't mean the user
# is trying to. We need to better place to warn about this, but it
# isn't here.
#try:
# import warnings
# warnings.warn("warning: records are known to not work for vtable interfaces")
#except ImportError:
# print "warning: records are known to not work for vtable interfaces"
cb = _univgw.SizeOfVT(pythoncom.VT_PTR)[1]
#cb = typeInfo.GetTypeAttr().cbSizeInstance
else:
cb = _univgw.SizeOfVT(t)[1]
return cb
class Arg:
def __init__(self, arg_info, name = None):
self.name = name
self.vt, self.inOut, self.default, self.clsid = arg_info
self.size = _CalcTypeSize(arg_info)
# Offset from the beginning of the arguments of the stack.
self.offset = 0
class Method:
def __init__(self, method_info, isEventSink=0):
all_names, dispid, desc = method_info
name = all_names[0]
names = all_names[1:]
invkind = desc[4]
arg_defs = desc[2]
ret_def = desc[8]
self.dispid = dispid
self.invkind = invkind
# We dont use this ATM.
# self.ret = Arg(ret_def)
if isEventSink and name[:2] != "On":
name = "On%s" % name
self.name = name
cbArgs = 0
self.args = []
for argDesc in arg_defs:
arg = Arg(argDesc)
arg.offset = cbArgs
cbArgs = cbArgs + arg.size
self.args.append(arg)
self.cbArgs = cbArgs
self._gw_in_args = self._GenerateInArgTuple()
self._gw_out_args = self._GenerateOutArgTuple()
def _GenerateInArgTuple(self):
# Given a method, generate the in argument tuple
l = []
for arg in self.args:
if arg.inOut & pythoncom.PARAMFLAG_FIN or \
arg.inOut == 0:
l.append((arg.vt, arg.offset, arg.size))
return tuple(l)
def _GenerateOutArgTuple(self):
# Given a method, generate the out argument tuple
l = []
for arg in self.args:
if arg.inOut & pythoncom.PARAMFLAG_FOUT or \
arg.inOut & pythoncom.PARAMFLAG_FRETVAL or \
arg.inOut == 0:
l.append((arg.vt, arg.offset, arg.size, arg.clsid))
return tuple(l)
class Definition:
def __init__(self, iid, is_dispatch, method_defs):
self._iid = iid
self._methods = []
self._is_dispatch = is_dispatch
for info in method_defs:
entry = Method(info)
self._methods.append(entry)
def iid(self):
return self._iid
def vtbl_argsizes(self):
return [m.cbArgs for m in self._methods]
def vtbl_argcounts(self):
return [len(m.args) for m in self._methods]
def dispatch(self, ob, index, argPtr,
ReadFromInTuple=_univgw.ReadFromInTuple,
WriteFromOutTuple=_univgw.WriteFromOutTuple):
"Dispatch a call to an interface method."
meth = self._methods[index]
# Infer S_OK if they don't return anything bizarre.
hr = 0
args = ReadFromInTuple(meth._gw_in_args, argPtr)
# If ob is a dispatcher, ensure a policy
ob = getattr(ob, "policy", ob)
# Ensure the correct dispid is setup
ob._dispid_to_func_[meth.dispid] = meth.name
retVal = ob._InvokeEx_(meth.dispid, 0, meth.invkind, args, None, None)
# None is an allowed return value stating that
# the code doesn't want to touch any output arguments.
if type(retVal) == tuple: # Like pythoncom, we special case a tuple.
# However, if they want to return a specific HRESULT,
# then they have to return all of the out arguments
# AND the HRESULT.
if len(retVal) == len(meth._gw_out_args) + 1:
hr = retVal[0]
retVal = retVal[1:]
else:
raise TypeError("Expected %s return values, got: %s" % (len(meth._gw_out_args) + 1, len(retVal)))
else:
retVal = [retVal]
retVal.extend([None] * (len(meth._gw_out_args)-1))
retVal = tuple(retVal)
WriteFromOutTuple(retVal, meth._gw_out_args, argPtr)
return hr