PageRenderTime 65ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/comtypes/client/__init__.py

https://gitlab.com/hoiwai930/comtypes
Python | 266 lines | 244 code | 11 blank | 11 comment | 2 complexity | ed9c9191d01943564af2ed0bebde08c5 MD5 | raw file
  1. '''comtypes.client - High level client level COM support package.
  2. '''
  3. ################################################################
  4. #
  5. # TODO:
  6. #
  7. # - refactor some code into modules
  8. #
  9. ################################################################
  10. import sys, os
  11. import ctypes
  12. import comtypes
  13. from comtypes.hresult import *
  14. import comtypes.automation
  15. import comtypes.typeinfo
  16. import comtypes.client.dynamic
  17. from comtypes.client._events import GetEvents, ShowEvents, PumpEvents
  18. from comtypes.client._generate import GetModule
  19. import logging
  20. logger = logging.getLogger(__name__)
  21. __all__ = ["CreateObject", "GetActiveObject", "CoGetObject",
  22. "GetEvents", "ShowEvents", "PumpEvents", "GetModule",
  23. "GetClassObject"]
  24. from comtypes.client._code_cache import _find_gen_dir
  25. gen_dir = _find_gen_dir()
  26. import comtypes.gen
  27. ### for testing
  28. ##gen_dir = None
  29. def wrap_outparam(punk):
  30. logger.debug("wrap_outparam(%s)", punk)
  31. if not punk:
  32. return None
  33. if punk.__com_interface__ == comtypes.automation.IDispatch:
  34. return GetBestInterface(punk)
  35. return punk
  36. def GetBestInterface(punk):
  37. """Try to QueryInterface a COM pointer to the 'most useful'
  38. interface.
  39. Get type information for the provided object, either via
  40. IDispatch.GetTypeInfo(), or via IProvideClassInfo.GetClassInfo().
  41. Generate a wrapper module for the typelib, and QI for the
  42. interface found.
  43. """
  44. if not punk: # NULL COM pointer
  45. return punk # or should we return None?
  46. # find the typelib and the interface name
  47. logger.debug("GetBestInterface(%s)", punk)
  48. try:
  49. try:
  50. pci = punk.QueryInterface(comtypes.typeinfo.IProvideClassInfo)
  51. logger.debug("Does implement IProvideClassInfo")
  52. except comtypes.COMError:
  53. # Some COM objects support IProvideClassInfo2, but not IProvideClassInfo.
  54. # These objects are broken, but we support them anyway.
  55. logger.debug("Does NOT implement IProvideClassInfo, trying IProvideClassInfo2")
  56. pci = punk.QueryInterface(comtypes.typeinfo.IProvideClassInfo2)
  57. logger.debug("Does implement IProvideClassInfo2")
  58. tinfo = pci.GetClassInfo() # TypeInfo for the CoClass
  59. # find the interface marked as default
  60. ta = tinfo.GetTypeAttr()
  61. for index in range(ta.cImplTypes):
  62. if tinfo.GetImplTypeFlags(index) == 1:
  63. break
  64. else:
  65. if ta.cImplTypes != 1:
  66. # Hm, should we use dynamic now?
  67. raise TypeError("No default interface found")
  68. # Only one interface implemented, use that (even if
  69. # not marked as default).
  70. index = 0
  71. href = tinfo.GetRefTypeOfImplType(index)
  72. tinfo = tinfo.GetRefTypeInfo(href)
  73. except comtypes.COMError:
  74. logger.debug("Does NOT implement IProvideClassInfo/IProvideClassInfo2")
  75. try:
  76. pdisp = punk.QueryInterface(comtypes.automation.IDispatch)
  77. except comtypes.COMError:
  78. logger.debug("No Dispatch interface: %s", punk)
  79. return punk
  80. try:
  81. tinfo = pdisp.GetTypeInfo(0)
  82. except comtypes.COMError:
  83. pdisp = comtypes.client.dynamic.Dispatch(pdisp)
  84. logger.debug("IDispatch.GetTypeInfo(0) failed: %s" % pdisp)
  85. return pdisp
  86. typeattr = tinfo.GetTypeAttr()
  87. logger.debug("Default interface is %s", typeattr.guid)
  88. try:
  89. punk.QueryInterface(comtypes.IUnknown, typeattr.guid)
  90. except comtypes.COMError:
  91. logger.debug("Does not implement default interface, returning dynamic object")
  92. return comtypes.client.dynamic.Dispatch(punk)
  93. itf_name = tinfo.GetDocumentation(-1)[0] # interface name
  94. tlib = tinfo.GetContainingTypeLib()[0] # typelib
  95. # import the wrapper, generating it on demand
  96. mod = GetModule(tlib)
  97. # Python interface class
  98. interface = getattr(mod, itf_name)
  99. logger.debug("Implements default interface from typeinfo %s", interface)
  100. # QI for this interface
  101. # XXX
  102. # What to do if this fails?
  103. # In the following example the engine.Eval() call returns
  104. # such an object.
  105. #
  106. # engine = CreateObject("MsScriptControl.ScriptControl")
  107. # engine.Language = "JScript"
  108. # engine.Eval("[1, 2, 3]")
  109. #
  110. # Could the above code, as an optimization, check that QI works,
  111. # *before* generating the wrapper module?
  112. result = punk.QueryInterface(interface)
  113. logger.debug("Final result is %s", result)
  114. return result
  115. # backwards compatibility:
  116. wrap = GetBestInterface
  117. # Should we do this for POINTER(IUnknown) also?
  118. ctypes.POINTER(comtypes.automation.IDispatch).__ctypes_from_outparam__ = wrap_outparam
  119. ################################################################
  120. #
  121. # Typelib constants
  122. #
  123. class Constants(object):
  124. """This class loads the type library from the supplied object,
  125. then exposes constants in the type library as attributes."""
  126. def __init__(self, obj):
  127. obj = obj.QueryInterface(comtypes.automation.IDispatch)
  128. tlib, index = obj.GetTypeInfo(0).GetContainingTypeLib()
  129. self.tcomp = tlib.GetTypeComp()
  130. def __getattr__(self, name):
  131. try:
  132. kind, desc = self.tcomp.Bind(name)
  133. except (WindowsError, comtypes.COMError):
  134. raise AttributeError(name)
  135. if kind != "variable":
  136. raise AttributeError(name)
  137. return desc._.lpvarValue[0].value
  138. def _bind_type(self, name):
  139. return self.tcomp.BindType(name)
  140. ################################################################
  141. #
  142. # Object creation
  143. #
  144. def GetActiveObject(progid, interface=None, dynamic=False):
  145. """Return a pointer to a running COM object that has been
  146. registered with COM.
  147. 'progid' may be a string like "Excel.Application",
  148. a string specifying a clsid, a GUID instance, or an object with
  149. a _clsid_ attribute which should be any of the above.
  150. 'interface' allows to force a certain interface.
  151. 'dynamic=True' will return a dynamic dispatch object.
  152. """
  153. clsid = comtypes.GUID.from_progid(progid)
  154. if dynamic:
  155. if interface is not None:
  156. raise ValueError("interface and dynamic are mutually exclusive")
  157. interface = comtypes.automation.IDispatch
  158. elif interface is None:
  159. interface = getattr(progid, "_com_interfaces_", [None])[0]
  160. obj = comtypes.GetActiveObject(clsid, interface=interface)
  161. if dynamic:
  162. return comtypes.client.dynamic.Dispatch(obj)
  163. return _manage(obj, clsid, interface=interface)
  164. def _manage(obj, clsid, interface):
  165. obj.__dict__['__clsid'] = str(clsid)
  166. if interface is None:
  167. obj = GetBestInterface(obj)
  168. return obj
  169. def GetClassObject(progid,
  170. clsctx=None,
  171. pServerInfo=None,
  172. interface=None):
  173. """Create and return the class factory for a COM object.
  174. 'clsctx' specifies how to create the object, use the CLSCTX_... constants.
  175. 'pServerInfo', if used, must be a pointer to a comtypes.COSERVERINFO instance
  176. 'interface' may be used to request an interface other than IClassFactory
  177. """
  178. clsid = comtypes.GUID.from_progid(progid)
  179. return comtypes.CoGetClassObject(clsid,
  180. clsctx, pServerInfo, interface)
  181. def CreateObject(progid, # which object to create
  182. clsctx=None, # how to create the object
  183. machine=None, # where to create the object
  184. interface=None, # the interface we want
  185. dynamic=False, # use dynamic dispatch
  186. pServerInfo=None): # server info struct for remoting
  187. """Create a COM object from 'progid', and try to QueryInterface()
  188. it to the most useful interface, generating typelib support on
  189. demand. A pointer to this interface is returned.
  190. 'progid' may be a string like "InternetExplorer.Application",
  191. a string specifying a clsid, a GUID instance, or an object with
  192. a _clsid_ attribute which should be any of the above.
  193. 'clsctx' specifies how to create the object, use the CLSCTX_... constants.
  194. 'machine' allows to specify a remote machine to create the object on.
  195. 'interface' allows to force a certain interface
  196. 'dynamic=True' will return a dynamic dispatch object
  197. 'pServerInfo', if used, must be a pointer to a comtypes.COSERVERINFO instance
  198. This supercedes 'machine'.
  199. You can also later request to receive events with GetEvents().
  200. """
  201. clsid = comtypes.GUID.from_progid(progid)
  202. logger.debug("%s -> %s", progid, clsid)
  203. if dynamic:
  204. if interface:
  205. raise ValueError("interface and dynamic are mutually exclusive")
  206. interface = comtypes.automation.IDispatch
  207. elif interface is None:
  208. interface = getattr(progid, "_com_interfaces_", [None])[0]
  209. if machine is None and pServerInfo is None:
  210. logger.debug("CoCreateInstance(%s, clsctx=%s, interface=%s)",
  211. clsid, clsctx, interface)
  212. obj = comtypes.CoCreateInstance(clsid, clsctx=clsctx, interface=interface)
  213. else:
  214. logger.debug("CoCreateInstanceEx(%s, clsctx=%s, interface=%s, machine=%s,\
  215. pServerInfo=%s)",
  216. clsid, clsctx, interface, machine, pServerInfo)
  217. if machine is not None and pServerInfo is not None:
  218. msg = "You can notset both the machine name and server info."
  219. raise ValueError(msg)
  220. obj = comtypes.CoCreateInstanceEx(clsid, clsctx=clsctx,
  221. interface=interface, machine=machine, pServerInfo=pServerInfo)
  222. if dynamic:
  223. return comtypes.client.dynamic.Dispatch(obj)
  224. return _manage(obj, clsid, interface=interface)
  225. def CoGetObject(displayname, interface=None, dynamic=False):
  226. """Create an object by calling CoGetObject(displayname).
  227. Additional parameters have the same meaning as in CreateObject().
  228. """
  229. if dynamic:
  230. if interface is not None:
  231. raise ValueError("interface and dynamic are mutually exclusive")
  232. interface = comtypes.automation.IDispatch
  233. punk = comtypes.CoGetObject(displayname, interface)
  234. if dynamic:
  235. return comtypes.client.dynamic.Dispatch(punk)
  236. return _manage(punk,
  237. clsid=None,
  238. interface=interface)