codekingpro/portable-devtools
114k
1# Code that packs and unpacks the Univgw structures.2 3# See if we have a special directory for the binaries (for developers)4 5import pythoncom6from win32com.client import gencache7 8com_error = pythoncom.com_error9_univgw = pythoncom._univgw10 11 12def RegisterInterfaces(typelibGUID, lcid, major, minor, interface_names=None):13 ret = [] # return a list of (dispid, funcname for our policy's benefit14 # First see if we have makepy support. If so, we can probably satisfy the request without loading the typelib.15 try:16 mod = gencache.GetModuleForTypelib(typelibGUID, lcid, major, minor)17 except ImportError:18 mod = None19 if mod is None:20 import win32com.client.build21 22 # Load up the typelib and build (but don't cache) it now23 tlb = pythoncom.LoadRegTypeLib(typelibGUID, major, minor, lcid)24 typecomp_lib = tlb.GetTypeComp()25 if interface_names is None:26 interface_names = []27 for i in range(tlb.GetTypeInfoCount()):28 info = tlb.GetTypeInfo(i)29 doc = tlb.GetDocumentation(i)30 attr = info.GetTypeAttr()31 if attr.typekind == pythoncom.TKIND_INTERFACE or (32 attr.typekind == pythoncom.TKIND_DISPATCH33 and attr.wTypeFlags & pythoncom.TYPEFLAG_FDUAL34 ):35 interface_names.append(doc[0])36 for name in interface_names:37 type_info, type_comp = typecomp_lib.BindType(38 name,39 )40 # Not sure why we don't get an exception here - BindType's C41 # impl looks correct..42 if type_info is None:43 raise ValueError("The interface '%s' can not be located" % (name,))44 # If we got back a Dispatch interface, convert to the real interface.45 attr = type_info.GetTypeAttr()46 if attr.typekind == pythoncom.TKIND_DISPATCH:47 refhtype = type_info.GetRefTypeOfImplType(-1)48 type_info = type_info.GetRefTypeInfo(refhtype)49 attr = type_info.GetTypeAttr()50 item = win32com.client.build.VTableItem(51 type_info, attr, type_info.GetDocumentation(-1)52 )53 _doCreateVTable(54 item.clsid, item.python_name, item.bIsDispatch, item.vtableFuncs55 )56 for info in item.vtableFuncs:57 names, dispid, desc = info58 invkind = desc[4]59 ret.append((dispid, invkind, names[0]))60 else:61 # Cool - can used cached info.62 if not interface_names:63 interface_names = list(mod.VTablesToClassMap.values())64 for name in interface_names:65 try:66 iid = mod.NamesToIIDMap[name]67 except KeyError:68 raise ValueError(69 "Interface '%s' does not exist in this cached typelib" % (name,)70 )71 # print "Processing interface", name72 sub_mod = gencache.GetModuleForCLSID(iid)73 is_dispatch = getattr(sub_mod, name + "_vtables_dispatch_", None)74 method_defs = getattr(sub_mod, name + "_vtables_", None)75 if is_dispatch is None or method_defs is None:76 raise ValueError("Interface '%s' is IDispatch only" % (name,))77 78 # And create the univgw defn79 _doCreateVTable(iid, name, is_dispatch, method_defs)80 for info in method_defs:81 names, dispid, desc = info82 invkind = desc[4]83 ret.append((dispid, invkind, names[0]))84 return ret85 86 87def _doCreateVTable(iid, interface_name, is_dispatch, method_defs):88 defn = Definition(iid, is_dispatch, method_defs)89 vtbl = _univgw.CreateVTable(defn, is_dispatch)90 _univgw.RegisterVTable(vtbl, iid, interface_name)91 92 93def _CalcTypeSize(typeTuple):94 t = typeTuple[0]95 if t & (pythoncom.VT_BYREF | pythoncom.VT_ARRAY):96 # Its a pointer.97 cb = _univgw.SizeOfVT(pythoncom.VT_PTR)[1]98 elif t == pythoncom.VT_RECORD:99 # Just because a type library uses records doesn't mean the user100 # is trying to. We need to better place to warn about this, but it101 # isn't here.102 # try:103 # import warnings104 # warnings.warn("warning: records are known to not work for vtable interfaces")105 # except ImportError:106 # print "warning: records are known to not work for vtable interfaces"107 cb = _univgw.SizeOfVT(pythoncom.VT_PTR)[1]108 # cb = typeInfo.GetTypeAttr().cbSizeInstance109 else:110 cb = _univgw.SizeOfVT(t)[1]111 return cb112 113 114class Arg:115 def __init__(self, arg_info, name=None):116 self.name = name117 self.vt, self.inOut, self.default, self.clsid = arg_info118 self.size = _CalcTypeSize(arg_info)119 # Offset from the beginning of the arguments of the stack.120 self.offset = 0121 122 123class Method:124 def __init__(self, method_info, isEventSink=0):125 all_names, dispid, desc = method_info126 name = all_names[0]127 names = all_names[1:]128 invkind = desc[4]129 arg_defs = desc[2]130 ret_def = desc[8]131 132 self.dispid = dispid133 self.invkind = invkind134 # We dont use this ATM.135 # self.ret = Arg(ret_def)136 if isEventSink and name[:2] != "On":137 name = "On%s" % name138 self.name = name139 cbArgs = 0140 self.args = []141 for argDesc in arg_defs:142 arg = Arg(argDesc)143 arg.offset = cbArgs144 cbArgs = cbArgs + arg.size145 self.args.append(arg)146 self.cbArgs = cbArgs147 self._gw_in_args = self._GenerateInArgTuple()148 self._gw_out_args = self._GenerateOutArgTuple()149 150 def _GenerateInArgTuple(self):151 # Given a method, generate the in argument tuple152 l = []153 for arg in self.args:154 if arg.inOut & pythoncom.PARAMFLAG_FIN or arg.inOut == 0:155 l.append((arg.vt, arg.offset, arg.size))156 return tuple(l)157 158 def _GenerateOutArgTuple(self):159 # Given a method, generate the out argument tuple160 l = []161 for arg in self.args:162 if (163 arg.inOut & pythoncom.PARAMFLAG_FOUT164 or arg.inOut & pythoncom.PARAMFLAG_FRETVAL165 or arg.inOut == 0166 ):167 l.append((arg.vt, arg.offset, arg.size, arg.clsid))168 return tuple(l)169 170 171class Definition:172 def __init__(self, iid, is_dispatch, method_defs):173 self._iid = iid174 self._methods = []175 self._is_dispatch = is_dispatch176 for info in method_defs:177 entry = Method(info)178 self._methods.append(entry)179 180 def iid(self):181 return self._iid182 183 def vtbl_argsizes(self):184 return [m.cbArgs for m in self._methods]185 186 def vtbl_argcounts(self):187 return [len(m.args) for m in self._methods]188 189 def dispatch(190 self,191 ob,192 index,193 argPtr,194 ReadFromInTuple=_univgw.ReadFromInTuple,195 WriteFromOutTuple=_univgw.WriteFromOutTuple,196 ):197 "Dispatch a call to an interface method."198 meth = self._methods[index]199 # Infer S_OK if they don't return anything bizarre.200 hr = 0201 args = ReadFromInTuple(meth._gw_in_args, argPtr)202 # If ob is a dispatcher, ensure a policy203 ob = getattr(ob, "policy", ob)204 # Ensure the correct dispid is setup205 ob._dispid_to_func_[meth.dispid] = meth.name206 retVal = ob._InvokeEx_(meth.dispid, 0, meth.invkind, args, None, None)207 # None is an allowed return value stating that208 # the code doesn't want to touch any output arguments.209 if type(retVal) == tuple: # Like pythoncom, we special case a tuple.210 # However, if they want to return a specific HRESULT,211 # then they have to return all of the out arguments212 # AND the HRESULT.213 if len(retVal) == len(meth._gw_out_args) + 1:214 hr = retVal[0]215 retVal = retVal[1:]216 else:217 raise TypeError(218 "Expected %s return values, got: %s"219 % (len(meth._gw_out_args) + 1, len(retVal))220 )221 else:222 retVal = [retVal]223 retVal.extend([None] * (len(meth._gw_out_args) - 1))224 retVal = tuple(retVal)225 WriteFromOutTuple(retVal, meth._gw_out_args, argPtr)226 return hr227 