universal.py 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. # Code that packs and unpacks the Univgw structures.
  2. # See if we have a special directory for the binaries (for developers)
  3. import types
  4. import pythoncom
  5. from win32com.client import gencache
  6. com_error = pythoncom.com_error
  7. _univgw = pythoncom._univgw
  8. def RegisterInterfaces(typelibGUID, lcid, major, minor, interface_names = None):
  9. ret = [] # return a list of (dispid, funcname for our policy's benefit
  10. # First see if we have makepy support. If so, we can probably satisfy the request without loading the typelib.
  11. try:
  12. mod = gencache.GetModuleForTypelib(typelibGUID, lcid, major, minor)
  13. except ImportError:
  14. mod = None
  15. if mod is None:
  16. import win32com.client.build
  17. # Load up the typelib and build (but don't cache) it now
  18. tlb = pythoncom.LoadRegTypeLib(typelibGUID, major, minor, lcid)
  19. typecomp_lib = tlb.GetTypeComp()
  20. if interface_names is None:
  21. interface_names = []
  22. for i in range(tlb.GetTypeInfoCount()):
  23. info = tlb.GetTypeInfo(i)
  24. doc = tlb.GetDocumentation(i)
  25. attr = info.GetTypeAttr()
  26. if attr.typekind == pythoncom.TKIND_INTERFACE or \
  27. (attr.typekind == pythoncom.TKIND_DISPATCH and attr.wTypeFlags & pythoncom.TYPEFLAG_FDUAL):
  28. interface_names.append(doc[0])
  29. for name in interface_names:
  30. type_info, type_comp = typecomp_lib.BindType(name, )
  31. # Not sure why we don't get an exception here - BindType's C
  32. # impl looks correct..
  33. if type_info is None:
  34. raise ValueError("The interface '%s' can not be located" % (name,))
  35. # If we got back a Dispatch interface, convert to the real interface.
  36. attr = type_info.GetTypeAttr()
  37. if attr.typekind == pythoncom.TKIND_DISPATCH:
  38. refhtype = type_info.GetRefTypeOfImplType(-1)
  39. type_info = type_info.GetRefTypeInfo(refhtype)
  40. attr = type_info.GetTypeAttr()
  41. item = win32com.client.build.VTableItem(type_info, attr, type_info.GetDocumentation(-1))
  42. _doCreateVTable(item.clsid, item.python_name, item.bIsDispatch, item.vtableFuncs)
  43. for info in item.vtableFuncs:
  44. names, dispid, desc = info
  45. invkind = desc[4]
  46. ret.append((dispid, invkind, names[0]))
  47. else:
  48. # Cool - can used cached info.
  49. if not interface_names:
  50. interface_names = list(mod.VTablesToClassMap.values())
  51. for name in interface_names:
  52. try:
  53. iid = mod.NamesToIIDMap[name]
  54. except KeyError:
  55. raise ValueError("Interface '%s' does not exist in this cached typelib" % (name,))
  56. # print "Processing interface", name
  57. sub_mod = gencache.GetModuleForCLSID(iid)
  58. is_dispatch = getattr(sub_mod, name + "_vtables_dispatch_", None)
  59. method_defs = getattr(sub_mod, name + "_vtables_", None)
  60. if is_dispatch is None or method_defs is None:
  61. raise ValueError("Interface '%s' is IDispatch only" % (name,))
  62. # And create the univgw defn
  63. _doCreateVTable(iid, name, is_dispatch, method_defs)
  64. for info in method_defs:
  65. names, dispid, desc = info
  66. invkind = desc[4]
  67. ret.append((dispid, invkind, names[0]))
  68. return ret
  69. def _doCreateVTable(iid, interface_name, is_dispatch, method_defs):
  70. defn = Definition(iid, is_dispatch, method_defs)
  71. vtbl = _univgw.CreateVTable(defn, is_dispatch)
  72. _univgw.RegisterVTable(vtbl, iid, interface_name)
  73. def _CalcTypeSize(typeTuple):
  74. t = typeTuple[0]
  75. if t & (pythoncom.VT_BYREF | pythoncom.VT_ARRAY):
  76. # Its a pointer.
  77. cb = _univgw.SizeOfVT(pythoncom.VT_PTR)[1]
  78. elif t == pythoncom.VT_RECORD:
  79. # Just because a type library uses records doesn't mean the user
  80. # is trying to. We need to better place to warn about this, but it
  81. # isn't here.
  82. #try:
  83. # import warnings
  84. # warnings.warn("warning: records are known to not work for vtable interfaces")
  85. #except ImportError:
  86. # print "warning: records are known to not work for vtable interfaces"
  87. cb = _univgw.SizeOfVT(pythoncom.VT_PTR)[1]
  88. #cb = typeInfo.GetTypeAttr().cbSizeInstance
  89. else:
  90. cb = _univgw.SizeOfVT(t)[1]
  91. return cb
  92. class Arg:
  93. def __init__(self, arg_info, name = None):
  94. self.name = name
  95. self.vt, self.inOut, self.default, self.clsid = arg_info
  96. self.size = _CalcTypeSize(arg_info)
  97. # Offset from the beginning of the arguments of the stack.
  98. self.offset = 0
  99. class Method:
  100. def __init__(self, method_info, isEventSink=0):
  101. all_names, dispid, desc = method_info
  102. name = all_names[0]
  103. names = all_names[1:]
  104. invkind = desc[4]
  105. arg_defs = desc[2]
  106. ret_def = desc[8]
  107. self.dispid = dispid
  108. self.invkind = invkind
  109. # We dont use this ATM.
  110. # self.ret = Arg(ret_def)
  111. if isEventSink and name[:2] != "On":
  112. name = "On%s" % name
  113. self.name = name
  114. cbArgs = 0
  115. self.args = []
  116. for argDesc in arg_defs:
  117. arg = Arg(argDesc)
  118. arg.offset = cbArgs
  119. cbArgs = cbArgs + arg.size
  120. self.args.append(arg)
  121. self.cbArgs = cbArgs
  122. self._gw_in_args = self._GenerateInArgTuple()
  123. self._gw_out_args = self._GenerateOutArgTuple()
  124. def _GenerateInArgTuple(self):
  125. # Given a method, generate the in argument tuple
  126. l = []
  127. for arg in self.args:
  128. if arg.inOut & pythoncom.PARAMFLAG_FIN or \
  129. arg.inOut == 0:
  130. l.append((arg.vt, arg.offset, arg.size))
  131. return tuple(l)
  132. def _GenerateOutArgTuple(self):
  133. # Given a method, generate the out argument tuple
  134. l = []
  135. for arg in self.args:
  136. if arg.inOut & pythoncom.PARAMFLAG_FOUT or \
  137. arg.inOut & pythoncom.PARAMFLAG_FRETVAL or \
  138. arg.inOut == 0:
  139. l.append((arg.vt, arg.offset, arg.size, arg.clsid))
  140. return tuple(l)
  141. class Definition:
  142. def __init__(self, iid, is_dispatch, method_defs):
  143. self._iid = iid
  144. self._methods = []
  145. self._is_dispatch = is_dispatch
  146. for info in method_defs:
  147. entry = Method(info)
  148. self._methods.append(entry)
  149. def iid(self):
  150. return self._iid
  151. def vtbl_argsizes(self):
  152. return [m.cbArgs for m in self._methods]
  153. def vtbl_argcounts(self):
  154. return [len(m.args) for m in self._methods]
  155. def dispatch(self, ob, index, argPtr,
  156. ReadFromInTuple=_univgw.ReadFromInTuple,
  157. WriteFromOutTuple=_univgw.WriteFromOutTuple):
  158. "Dispatch a call to an interface method."
  159. meth = self._methods[index]
  160. # Infer S_OK if they don't return anything bizarre.
  161. hr = 0
  162. args = ReadFromInTuple(meth._gw_in_args, argPtr)
  163. # If ob is a dispatcher, ensure a policy
  164. ob = getattr(ob, "policy", ob)
  165. # Ensure the correct dispid is setup
  166. ob._dispid_to_func_[meth.dispid] = meth.name
  167. retVal = ob._InvokeEx_(meth.dispid, 0, meth.invkind, args, None, None)
  168. # None is an allowed return value stating that
  169. # the code doesn't want to touch any output arguments.
  170. if type(retVal) == tuple: # Like pythoncom, we special case a tuple.
  171. # However, if they want to return a specific HRESULT,
  172. # then they have to return all of the out arguments
  173. # AND the HRESULT.
  174. if len(retVal) == len(meth._gw_out_args) + 1:
  175. hr = retVal[0]
  176. retVal = retVal[1:]
  177. else:
  178. raise TypeError("Expected %s return values, got: %s" % (len(meth._gw_out_args) + 1, len(retVal)))
  179. else:
  180. retVal = [retVal]
  181. retVal.extend([None] * (len(meth._gw_out_args)-1))
  182. retVal = tuple(retVal)
  183. WriteFromOutTuple(retVal, meth._gw_out_args, argPtr)
  184. return hr