comtypes 1.4.8__zip → 1.4.9__zip

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (146) hide show
  1. {comtypes-1.4.8 → comtypes-1.4.9}/CHANGES.txt +21 -0
  2. {comtypes-1.4.8/comtypes.egg-info → comtypes-1.4.9}/PKG-INFO +2 -2
  3. {comtypes-1.4.8 → comtypes-1.4.9}/README.md +1 -1
  4. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/GUID.py +6 -5
  5. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/__init__.py +16 -5
  6. comtypes-1.4.9/comtypes/_comobject.py +507 -0
  7. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/_memberspec.py +80 -8
  8. comtypes-1.4.9/comtypes/_post_coinit/_cominterface_meta_patcher.py +153 -0
  9. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/_post_coinit/misc.py +1 -1
  10. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/_post_coinit/unknwn.py +25 -171
  11. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/_safearray.py +1 -2
  12. comtypes-1.4.9/comtypes/_vtbl.py +448 -0
  13. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/automation.py +36 -45
  14. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/client/_code_cache.py +4 -4
  15. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/client/_constants.py +1 -1
  16. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/client/_events.py +1 -1
  17. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/client/_generate.py +4 -8
  18. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/client/lazybind.py +2 -2
  19. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/errorinfo.py +3 -3
  20. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/git.py +1 -2
  21. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/hints.pyi +7 -15
  22. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/safearray.py +10 -0
  23. comtypes-1.4.9/comtypes/server/__init__.py +86 -0
  24. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/server/inprocserver.py +22 -17
  25. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/server/localserver.py +28 -16
  26. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/server/register.py +61 -73
  27. comtypes-1.4.9/comtypes/server/w_getopt.py +48 -0
  28. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/shelllink.py +3 -26
  29. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/__init__.py +9 -11
  30. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_BSTR.py +4 -7
  31. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_avmc.py +1 -1
  32. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_casesensitivity.py +3 -5
  33. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_collections.py +3 -3
  34. comtypes-1.4.9/comtypes/test/test_comobject.py +146 -0
  35. comtypes-1.4.9/comtypes/test/test_comserver.py +319 -0
  36. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_createwrappers.py +2 -4
  37. comtypes-1.4.9/comtypes/test/test_dispinterface.py +153 -0
  38. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_excel.py +22 -12
  39. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_ie.py +2 -5
  40. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_inout_args.py +7 -4
  41. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_midl_safearray_create.py +9 -1
  42. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_outparam.py +17 -10
  43. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_safearray.py +1 -90
  44. comtypes-1.4.9/comtypes/test/test_server.py +350 -0
  45. comtypes-1.4.9/comtypes/test/test_server_register.py +536 -0
  46. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_showevents.py +7 -17
  47. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_variant.py +0 -17
  48. comtypes-1.4.9/comtypes/test/test_w_getopt.py +29 -0
  49. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_win32com_interop.py +80 -36
  50. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_wmi.py +0 -3
  51. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/tools/codegenerator/codegenerator.py +62 -68
  52. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/tools/codegenerator/helpers.py +8 -8
  53. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/tools/codegenerator/packing.py +4 -4
  54. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/tools/codegenerator/typeannotator.py +7 -7
  55. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/tools/typedesc.py +1 -6
  56. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/typeinfo.py +11 -22
  57. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/viewobject.py +1 -5
  58. {comtypes-1.4.8 → comtypes-1.4.9/comtypes.egg-info}/PKG-INFO +2 -2
  59. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes.egg-info/SOURCES.txt +6 -3
  60. {comtypes-1.4.8 → comtypes-1.4.9}/pyproject.toml +1 -0
  61. comtypes-1.4.8/comtypes/_comobject.py +0 -833
  62. comtypes-1.4.8/comtypes/_idl_stuff.py +0 -67
  63. comtypes-1.4.8/comtypes/server/__init__.py +0 -70
  64. comtypes-1.4.8/comtypes/server/w_getopt.py +0 -75
  65. comtypes-1.4.8/comtypes/test/test_comserver.py +0 -239
  66. comtypes-1.4.8/comtypes/test/test_dispinterface.py +0 -137
  67. comtypes-1.4.8/comtypes/test/test_propputref.py +0 -40
  68. comtypes-1.4.8/comtypes/test/test_server.py +0 -354
  69. {comtypes-1.4.8 → comtypes-1.4.9}/LICENSE.txt +0 -0
  70. {comtypes-1.4.8 → comtypes-1.4.9}/MANIFEST.in +0 -0
  71. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/_meta.py +0 -0
  72. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/_npsupport.py +0 -0
  73. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/_post_coinit/__init__.py +0 -0
  74. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/_post_coinit/bstr.py +0 -0
  75. /comtypes-1.4.8/comtypes/_py_instance_method.py → /comtypes-1.4.9/comtypes/_post_coinit/instancemethod.py +0 -0
  76. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/_tlib_version_checker.py +0 -0
  77. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/clear_cache.py +0 -0
  78. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/client/__init__.py +0 -0
  79. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/client/dynamic.py +0 -0
  80. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/connectionpoints.py +0 -0
  81. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/hresult.py +0 -0
  82. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/logutil.py +0 -0
  83. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/messageloop.py +0 -0
  84. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/patcher.py +0 -0
  85. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/persist.py +0 -0
  86. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/server/automation.py +0 -0
  87. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/server/connectionpoints.py +0 -0
  88. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/stream.py +0 -0
  89. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/TestComServer.idl +0 -0
  90. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/TestComServer.py +0 -0
  91. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/TestComServer.tlb +0 -0
  92. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/TestDispServer.idl +0 -0
  93. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/TestDispServer.py +0 -0
  94. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/TestDispServer.tlb +0 -0
  95. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/find_memleak.py +0 -0
  96. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/mylib.idl +0 -0
  97. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/mylib.tlb +0 -0
  98. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/mytypelib.idl +0 -0
  99. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/runtests.py +0 -0
  100. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/setup.py +0 -0
  101. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_DISPPARAMS.py +0 -0
  102. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_GUID.py +0 -0
  103. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_QueryService.py +0 -0
  104. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_agilent.py +0 -0
  105. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_basic.py +0 -0
  106. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_clear_cache.py +0 -0
  107. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_client.py +0 -0
  108. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_client_dynamic.py +0 -0
  109. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_client_regenerate_modules.py +0 -0
  110. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_dict.py +0 -0
  111. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_dispifc_records.py +0 -0
  112. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_dispifc_safearrays.py +0 -0
  113. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_dyndispatch.py +0 -0
  114. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_findgendir.py +0 -0
  115. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_getactiveobj.py +0 -0
  116. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_ienum.py +0 -0
  117. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_imfattributes.py +0 -0
  118. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_jscript.js +0 -0
  119. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_monikers.py +0 -0
  120. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_msscript.py +0 -0
  121. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_npsupport.py +0 -0
  122. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_persist.py +0 -0
  123. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_pump_events.py +0 -0
  124. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_recordinfo.py +0 -0
  125. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_sapi.py +0 -0
  126. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_shelllink.py +0 -0
  127. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_storage.py +0 -0
  128. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_stream.py +0 -0
  129. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_subinterface.py +0 -0
  130. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_typeannotator.py +0 -0
  131. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_typeinfo.py +0 -0
  132. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_urlhistory.py +0 -0
  133. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/test_word.py +0 -0
  134. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/test/urlhist.tlb +0 -0
  135. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/tools/__init__.py +0 -0
  136. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/tools/codegenerator/__init__.py +0 -0
  137. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/tools/codegenerator/modulenamer.py +0 -0
  138. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/tools/codegenerator/namespaces.py +0 -0
  139. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/tools/tlbparser.py +0 -0
  140. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/tools/typedesc_base.py +0 -0
  141. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes/util.py +0 -0
  142. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes.egg-info/dependency_links.txt +0 -0
  143. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes.egg-info/entry_points.txt +0 -0
  144. {comtypes-1.4.8 → comtypes-1.4.9}/comtypes.egg-info/top_level.txt +0 -0
  145. {comtypes-1.4.8 → comtypes-1.4.9}/setup.cfg +0 -0
  146. {comtypes-1.4.8 → comtypes-1.4.9}/setup.py +0 -0
@@ -1,6 +1,27 @@
1
1
  Comtypes CHANGELOG
2
2
  ==================
3
3
 
4
+ Release 1.4.9
5
+ --------------
6
+ * Separate patch processing within ``_com_interface_meta`` into a module. By @junkmd.
7
+ * Replace ``Literal`` and ``Protocol`` with runtime-referable symbols. By @junkmd.
8
+ * Refactor from ``%`` string formatting to f-strings in many modules. By @newwingbird.
9
+ * Refactor from ``%`` string formatting to f-strings in ``_post_coinit.unknwn``. By @junkmd.
10
+ * Remove the script entry point in ``comtypes.shelllink``. By @cosmastech.
11
+ * Move the modules that define IDL stuff and ``instancemethod``. By @junkmd.
12
+ * Allow the definition of the ``_midlSAFEARRAY(HRESULT)`` type. By @davidschranz.
13
+ * Split ``server/w_getopt.py`` into production code and test code. By @junkmd.
14
+ * Add docstrings to the module defining the ``GUID`` symbol. By @junkmd.
15
+ * Fix broken unregistration of 64bit type libraries. By @forderud.
16
+ * Replace alias definitions with ``ctypes.wintypes`` imports. By @fmtabler.
17
+ * Revive ``pywin32`` related tests. By @junkmd.
18
+ * Revive comserver related tests. By @junkmd.
19
+ * Separate the part that creates entries from ``server.register.Registrar`` and refactor it. By @junkmd.
20
+ * Add ``Test_Registrar_...``. By @junkmd.
21
+ * Many typing improvements. By @junkmd.
22
+ * Separate ``vtbl`` creation within ``_comobject`` into a module. By @junkmd.
23
+ * Migrate the documentation from PythonHosted to ReadTheDocs. By @junkmd.
24
+
4
25
  Release 1.4.8
5
26
  --------------
6
27
  * Remove Python 3.7 and add Python 3.13 to the CI pipelines. By @junkmd.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: comtypes
3
- Version: 1.4.8
3
+ Version: 1.4.9
4
4
  Summary: Pure Python COM package
5
5
  Home-page: https://github.com/enthought/comtypes
6
6
  Download-URL: https://github.com/enthought/comtypes/releases
@@ -99,4 +99,4 @@ However, if the script implementation does not use `comtypes.client.GetModule` o
99
99
 
100
100
  ## Documentation
101
101
 
102
- The documentation is currently hosted [here](https://pythonhosted.org/comtypes) on PythonHosted.
102
+ The documentation is currently hosted [here](https://comtypes.readthedocs.io/) on ReadTheDocs.
@@ -80,4 +80,4 @@ However, if the script implementation does not use `comtypes.client.GetModule` o
80
80
 
81
81
  ## Documentation
82
82
 
83
- The documentation is currently hosted [here](https://pythonhosted.org/comtypes) on PythonHosted.
83
+ The documentation is currently hosted [here](https://comtypes.readthedocs.io/) on ReadTheDocs.
@@ -1,5 +1,8 @@
1
+ """comtypes.GUID module"""
2
+
1
3
  from ctypes import oledll, windll
2
- from ctypes import byref, c_byte, c_ushort, c_ulong, c_wchar_p, Structure
4
+ from ctypes import byref, c_wchar_p, Structure
5
+ from ctypes.wintypes import BYTE, WORD, DWORD
3
6
  from typing import Any, TYPE_CHECKING
4
7
 
5
8
  if TYPE_CHECKING:
@@ -10,10 +13,6 @@ def binary(obj: "GUID") -> bytes:
10
13
  return bytes(obj)
11
14
 
12
15
 
13
- BYTE = c_byte
14
- WORD = c_ushort
15
- DWORD = c_ulong
16
-
17
16
  _ole32 = oledll.ole32
18
17
 
19
18
  _StringFromCLSID = _ole32.StringFromCLSID
@@ -28,6 +27,8 @@ _CoCreateGuid = _ole32.CoCreateGuid
28
27
 
29
28
 
30
29
  class GUID(Structure):
30
+ """Globally unique identifier structure."""
31
+
31
32
  _fields_ = [("Data1", DWORD), ("Data2", WORD), ("Data3", WORD), ("Data4", BYTE * 8)]
32
33
 
33
34
  def __init__(self, name=None):
@@ -1,5 +1,5 @@
1
1
  # comtypes version numbers follow semver (http://semver.org/) and PEP 440
2
- __version__ = "1.4.8"
2
+ __version__ = "1.4.9"
3
3
 
4
4
  try:
5
5
  from _ctypes import COMError # noqa
@@ -25,6 +25,7 @@ from ctypes import * # noqa
25
25
  from ctypes import HRESULT # noqa
26
26
  from ctypes import _Pointer, _SimpleCData # noqa
27
27
  from ctypes import c_int, c_ulong, oledll, windll
28
+ from ctypes.wintypes import DWORD # noqa
28
29
  import logging
29
30
  import sys
30
31
  from typing import TYPE_CHECKING
@@ -39,9 +40,6 @@ from comtypes.GUID import GUID
39
40
  from comtypes import patcher # noqa
40
41
  from comtypes._npsupport import interop as npsupport # noqa
41
42
  from comtypes._tlib_version_checker import _check_version # noqa
42
- from comtypes._py_instance_method import instancemethod # noqa
43
- from comtypes._idl_stuff import defaultvalue, helpstring, dispid # noqa
44
- from comtypes._idl_stuff import STDMETHOD, DISPMETHOD, DISPPROPERTY, COMMETHOD # noqa
45
43
 
46
44
  _all_slice = slice(None, None, None)
47
45
 
@@ -75,7 +73,6 @@ class ReturnHRESULT(Exception):
75
73
 
76
74
  _GUID = GUID
77
75
  IID = GUID
78
- DWORD = c_ulong
79
76
 
80
77
  wireHWND = c_ulong
81
78
 
@@ -172,6 +169,19 @@ com_interface_registry = {}
172
169
  com_coclass_registry = {}
173
170
 
174
171
 
172
+ ################################################################
173
+ # IDL stuff
174
+
175
+ from comtypes._memberspec import ( # noqa
176
+ COMMETHOD,
177
+ DISPMETHOD,
178
+ DISPPROPERTY,
179
+ STDMETHOD,
180
+ defaultvalue,
181
+ dispid,
182
+ helpstring,
183
+ )
184
+
175
185
  ################################################################
176
186
  # IUnknown, the root of all evil...
177
187
  from comtypes._post_coinit import _shutdown
@@ -193,6 +203,7 @@ from comtypes._post_coinit.misc import IPersist, IServiceProvider # noqa
193
203
  ################################################################
194
204
 
195
205
 
206
+ from comtypes._post_coinit.instancemethod import instancemethod # noqa
196
207
  from comtypes._post_coinit.misc import ( # noqa
197
208
  _is_object,
198
209
  CoGetObject,
@@ -0,0 +1,507 @@
1
+ import logging
2
+ import queue
3
+ from _ctypes import COMError, CopyComPointer
4
+ from ctypes import (
5
+ POINTER,
6
+ FormatError,
7
+ Structure,
8
+ byref,
9
+ c_long,
10
+ c_void_p,
11
+ oledll,
12
+ pointer,
13
+ windll,
14
+ )
15
+ from typing import (
16
+ TYPE_CHECKING,
17
+ Any,
18
+ Callable,
19
+ ClassVar,
20
+ Dict,
21
+ List,
22
+ Optional,
23
+ Sequence,
24
+ Tuple,
25
+ Type,
26
+ TypeVar,
27
+ )
28
+ from typing import Union as _UnionT
29
+
30
+ from comtypes import GUID, IPersist, IUnknown, hresult
31
+ from comtypes._vtbl import _MethodFinder, create_dispimpl, create_vtbl_mapping
32
+ from comtypes.errorinfo import ISupportErrorInfo
33
+ from comtypes.typeinfo import IProvideClassInfo, IProvideClassInfo2, ITypeInfo
34
+
35
+ if TYPE_CHECKING:
36
+ from ctypes import _CArgObject, _Pointer
37
+
38
+ from comtypes import hints # type: ignore
39
+
40
+ logger = logging.getLogger(__name__)
41
+ _debug = logger.debug
42
+
43
+ ################################################################
44
+ # COM object implementation
45
+
46
+ # so we don't have to import comtypes.automation
47
+ DISPATCH_METHOD = 1
48
+ DISPATCH_PROPERTYGET = 2
49
+ DISPATCH_PROPERTYPUT = 4
50
+ DISPATCH_PROPERTYPUTREF = 8
51
+
52
+ ################################################################
53
+
54
+ try:
55
+ _InterlockedIncrement = windll.kernel32.InterlockedIncrement
56
+ _InterlockedDecrement = windll.kernel32.InterlockedDecrement
57
+ except AttributeError:
58
+ import threading
59
+
60
+ _lock = threading.Lock()
61
+ _acquire = _lock.acquire
62
+ _release = _lock.release
63
+ # win 64 doesn't have these functions
64
+
65
+ def _InterlockedIncrement(ob: c_long) -> int:
66
+ _acquire()
67
+ refcnt = ob.value + 1
68
+ ob.value = refcnt
69
+ _release()
70
+ return refcnt
71
+
72
+ def _InterlockedDecrement(ob: c_long) -> int:
73
+ _acquire()
74
+ refcnt = ob.value - 1
75
+ ob.value = refcnt
76
+ _release()
77
+ return refcnt
78
+
79
+ else:
80
+ _InterlockedIncrement.argtypes = [POINTER(c_long)]
81
+ _InterlockedDecrement.argtypes = [POINTER(c_long)]
82
+ _InterlockedIncrement.restype = c_long
83
+ _InterlockedDecrement.restype = c_long
84
+
85
+
86
+ class LocalServer(object):
87
+ _queue: Optional[queue.Queue] = None
88
+
89
+ def run(self, classobjects: Sequence["hints.localserver.ClassFactory"]) -> None:
90
+ # Use windll instead of oledll so that we don't get an
91
+ # exception on a FAILED hresult:
92
+ hr = windll.ole32.CoInitialize(None)
93
+ if hresult.RPC_E_CHANGED_MODE == hr:
94
+ # we're running in MTA: no message pump needed
95
+ _debug("Server running in MTA")
96
+ self.run_mta()
97
+ else:
98
+ # we're running in STA: need a message pump
99
+ _debug("Server running in STA")
100
+ if hr >= 0:
101
+ # we need a matching CoUninitialize() call for a successful
102
+ # CoInitialize().
103
+ windll.ole32.CoUninitialize()
104
+ self.run_sta()
105
+
106
+ for obj in classobjects:
107
+ obj._revoke_class()
108
+
109
+ def run_sta(self) -> None:
110
+ from comtypes import messageloop
111
+
112
+ messageloop.run()
113
+
114
+ def run_mta(self) -> None:
115
+ self._queue = queue.Queue()
116
+ self._queue.get()
117
+
118
+ def Lock(self) -> None:
119
+ oledll.ole32.CoAddRefServerProcess()
120
+
121
+ def Unlock(self) -> None:
122
+ rc = oledll.ole32.CoReleaseServerProcess()
123
+ if rc == 0:
124
+ if self._queue:
125
+ self._queue.put(42)
126
+ else:
127
+ windll.user32.PostQuitMessage(0)
128
+
129
+
130
+ class InprocServer(object):
131
+ def __init__(self) -> None:
132
+ self.locks = c_long(0)
133
+
134
+ def Lock(self) -> None:
135
+ _InterlockedIncrement(self.locks)
136
+
137
+ def Unlock(self) -> None:
138
+ _InterlockedDecrement(self.locks)
139
+
140
+ def DllCanUnloadNow(self) -> int:
141
+ if self.locks.value:
142
+ return hresult.S_FALSE
143
+ if COMObject._instances_:
144
+ return hresult.S_FALSE
145
+ return hresult.S_OK
146
+
147
+
148
+ _T_IUnknown = TypeVar("_T_IUnknown", bound=IUnknown)
149
+
150
+
151
+ class COMObject(object):
152
+ _com_interfaces_: ClassVar[List[Type[IUnknown]]]
153
+ _outgoing_interfaces_: ClassVar[List[Type["hints.IDispatch"]]]
154
+ _instances_: ClassVar[Dict["COMObject", None]] = {}
155
+ _reg_clsid_: ClassVar[GUID]
156
+ _reg_typelib_: ClassVar[Tuple[str, int, int]]
157
+ __typelib: "hints.ITypeLib"
158
+ _com_pointers_: Dict[GUID, "_Pointer[_Pointer[Structure]]"]
159
+ _dispimpl_: Dict[Tuple[int, int], Callable[..., Any]]
160
+
161
+ def __new__(cls, *args, **kw):
162
+ self = super(COMObject, cls).__new__(cls)
163
+ if isinstance(self, c_void_p):
164
+ # We build the VTables only for direct instances of
165
+ # CoClass, not for POINTERs to CoClass.
166
+ return self
167
+ if hasattr(self, "_com_interfaces_"):
168
+ self.__prepare_comobject()
169
+ return self
170
+
171
+ def __prepare_comobject(self) -> None:
172
+ # When a CoClass instance is created, COM pointers to all
173
+ # interfaces are created. Also, the CoClass must be kept alive as
174
+ # until the COM reference count drops to zero, even if no Python
175
+ # code keeps a reference to the object.
176
+ #
177
+ # The _com_pointers_ instance variable maps string interface iids
178
+ # to C compatible COM pointers.
179
+ self._com_pointers_ = {}
180
+ # COM refcount starts at zero.
181
+ self._refcnt = c_long(0)
182
+
183
+ # Some interfaces have a default implementation in COMObject:
184
+ # - ISupportErrorInfo
185
+ # - IPersist (if the subclass has a _reg_clsid_ attribute)
186
+ # - IProvideClassInfo (if the subclass has a _reg_clsid_ attribute)
187
+ # - IProvideClassInfo2 (if the subclass has a _outgoing_interfaces_
188
+ # attribute)
189
+ #
190
+ # Add these if they are not listed in _com_interfaces_.
191
+ interfaces = tuple(self._com_interfaces_)
192
+ if ISupportErrorInfo not in interfaces:
193
+ interfaces += (ISupportErrorInfo,)
194
+ if hasattr(self, "_reg_typelib_"):
195
+ from comtypes.typeinfo import LoadRegTypeLib
196
+
197
+ self._COMObject__typelib = LoadRegTypeLib(*self._reg_typelib_)
198
+ if hasattr(self, "_reg_clsid_"):
199
+ if IProvideClassInfo not in interfaces:
200
+ interfaces += (IProvideClassInfo,)
201
+ if (
202
+ hasattr(self, "_outgoing_interfaces_")
203
+ and IProvideClassInfo2 not in interfaces
204
+ ):
205
+ interfaces += (IProvideClassInfo2,)
206
+ if hasattr(self, "_reg_clsid_"):
207
+ if IPersist not in interfaces:
208
+ interfaces += (IPersist,)
209
+ for itf in interfaces[::-1]:
210
+ self.__make_interface_pointer(itf)
211
+
212
+ def __make_interface_pointer(self, itf: Type[IUnknown]) -> None:
213
+ finder = self._get_method_finder_(itf)
214
+ iids, vtbl = create_vtbl_mapping(itf, finder)
215
+ for iid in iids:
216
+ self._com_pointers_[iid] = pointer(pointer(vtbl))
217
+ if hasattr(itf, "_disp_methods_"):
218
+ self._dispimpl_ = create_dispimpl(itf, finder)
219
+
220
+ def _get_method_finder_(self, itf: Type[IUnknown]) -> _MethodFinder:
221
+ # This method can be overridden to customize how methods are found.
222
+ return _MethodFinder(self)
223
+
224
+ ################################################################
225
+ # LocalServer / InprocServer stuff
226
+ __server__: _UnionT[None, InprocServer, LocalServer] = None
227
+
228
+ @staticmethod
229
+ def __run_inprocserver__() -> None:
230
+ if COMObject.__server__ is None:
231
+ COMObject.__server__ = InprocServer()
232
+ elif isinstance(COMObject.__server__, InprocServer):
233
+ pass
234
+ else:
235
+ raise RuntimeError("Wrong server type")
236
+
237
+ @staticmethod
238
+ def __run_localserver__(
239
+ classobjects: Sequence["hints.localserver.ClassFactory"],
240
+ ) -> None:
241
+ assert COMObject.__server__ is None
242
+ # XXX Decide whether we are in STA or MTA
243
+ server = COMObject.__server__ = LocalServer()
244
+ server.run(classobjects)
245
+ COMObject.__server__ = None
246
+
247
+ @staticmethod
248
+ def __keep__(obj: "COMObject") -> None:
249
+ COMObject._instances_[obj] = None
250
+ _debug("%d active COM objects: Added %r", len(COMObject._instances_), obj)
251
+ if COMObject.__server__:
252
+ COMObject.__server__.Lock()
253
+
254
+ @staticmethod
255
+ def __unkeep__(obj: "COMObject") -> None:
256
+ try:
257
+ del COMObject._instances_[obj]
258
+ except AttributeError:
259
+ _debug("? active COM objects: Removed %r", obj)
260
+ else:
261
+ _debug("%d active COM objects: Removed %r", len(COMObject._instances_), obj)
262
+ _debug("Remaining: %s", list(COMObject._instances_.keys()))
263
+ if COMObject.__server__:
264
+ COMObject.__server__.Unlock()
265
+
266
+ #
267
+ ################################################################
268
+
269
+ #########################################################
270
+ # IUnknown methods implementations
271
+ def IUnknown_AddRef(
272
+ self,
273
+ this: Any,
274
+ __InterlockedIncrement: Callable[[c_long], int] = _InterlockedIncrement,
275
+ _debug=_debug,
276
+ ) -> int:
277
+ result = __InterlockedIncrement(self._refcnt)
278
+ if result == 1:
279
+ self.__keep__(self)
280
+ _debug("%r.AddRef() -> %s", self, result)
281
+ return result
282
+
283
+ def _final_release_(self) -> None:
284
+ """This method may be overridden in subclasses
285
+ to free allocated resources or so."""
286
+ pass
287
+
288
+ def IUnknown_Release(
289
+ self,
290
+ this: Any,
291
+ __InterlockedDecrement: Callable[[c_long], int] = _InterlockedDecrement,
292
+ _debug=_debug,
293
+ ) -> int:
294
+ # If this is called at COM shutdown, _InterlockedDecrement()
295
+ # must still be available, although module level variables may
296
+ # have been deleted already - so we supply it as default
297
+ # argument.
298
+ result = __InterlockedDecrement(self._refcnt)
299
+ _debug("%r.Release() -> %s", self, result)
300
+ if result == 0:
301
+ self._final_release_()
302
+ self.__unkeep__(self)
303
+ # Hm, why isn't this cleaned up by the cycle gc?
304
+ self._com_pointers_ = {}
305
+ return result
306
+
307
+ def IUnknown_QueryInterface(
308
+ self,
309
+ this: Any,
310
+ riid: "_Pointer[GUID]",
311
+ ppvObj: _UnionT[c_void_p, "_CArgObject"],
312
+ _debug=_debug,
313
+ ) -> int:
314
+ # XXX This is probably too slow.
315
+ # riid[0].hashcode() alone takes 33 us!
316
+ iid = riid[0]
317
+ ptr = self._com_pointers_.get(iid, None)
318
+ if ptr is not None:
319
+ # CopyComPointer(src, dst) calls AddRef!
320
+ _debug("%r.QueryInterface(%s) -> S_OK", self, iid)
321
+ return CopyComPointer(ptr, ppvObj)
322
+ _debug("%r.QueryInterface(%s) -> E_NOINTERFACE", self, iid)
323
+ return hresult.E_NOINTERFACE
324
+
325
+ def QueryInterface(self, interface: Type[_T_IUnknown]) -> _T_IUnknown:
326
+ "Query the object for an interface pointer"
327
+ # This method is NOT the implementation of
328
+ # IUnknown::QueryInterface, instead it is supposed to be
329
+ # called on an COMObject by user code. It allows to get COM
330
+ # interface pointers from COMObject instances.
331
+ ptr = self._com_pointers_.get(interface._iid_, None)
332
+ if ptr is None:
333
+ raise COMError(
334
+ hresult.E_NOINTERFACE,
335
+ FormatError(hresult.E_NOINTERFACE),
336
+ (None, None, None, 0, None),
337
+ )
338
+ # CopyComPointer(src, dst) calls AddRef!
339
+ result = POINTER(interface)()
340
+ CopyComPointer(ptr, byref(result))
341
+ return result # type: ignore
342
+
343
+ ################################################################
344
+ # ISupportErrorInfo::InterfaceSupportsErrorInfo implementation
345
+ def ISupportErrorInfo_InterfaceSupportsErrorInfo(
346
+ self, this: Any, riid: "_Pointer[GUID]"
347
+ ) -> int:
348
+ if riid[0] in self._com_pointers_:
349
+ return hresult.S_OK
350
+ return hresult.S_FALSE
351
+
352
+ ################################################################
353
+ # IProvideClassInfo::GetClassInfo implementation
354
+ def IProvideClassInfo_GetClassInfo(self) -> ITypeInfo:
355
+ try:
356
+ self.__typelib
357
+ except AttributeError:
358
+ raise WindowsError(hresult.E_NOTIMPL)
359
+ return self.__typelib.GetTypeInfoOfGuid(self._reg_clsid_)
360
+
361
+ ################################################################
362
+ # IProvideClassInfo2::GetGUID implementation
363
+
364
+ def IProvideClassInfo2_GetGUID(self, dwGuidKind: int) -> GUID:
365
+ # GUIDKIND_DEFAULT_SOURCE_DISP_IID = 1
366
+ if dwGuidKind != 1:
367
+ raise WindowsError(hresult.E_INVALIDARG)
368
+ return self._outgoing_interfaces_[0]._iid_
369
+
370
+ ################################################################
371
+ # IDispatch methods
372
+ @property
373
+ def __typeinfo(self):
374
+ # XXX Looks like this better be a static property, set by the
375
+ # code that sets __typelib also...
376
+ iid = self._com_interfaces_[0]._iid_
377
+ return self.__typelib.GetTypeInfoOfGuid(iid)
378
+
379
+ def IDispatch_GetTypeInfoCount(self):
380
+ try:
381
+ self.__typelib
382
+ except AttributeError:
383
+ return 0
384
+ else:
385
+ return 1
386
+
387
+ def IDispatch_GetTypeInfo(self, this, itinfo, lcid, ptinfo):
388
+ if itinfo != 0:
389
+ return hresult.DISP_E_BADINDEX
390
+ try:
391
+ ptinfo[0] = self.__typeinfo
392
+ return hresult.S_OK
393
+ except AttributeError:
394
+ return hresult.E_NOTIMPL
395
+
396
+ def IDispatch_GetIDsOfNames(self, this, riid, rgszNames, cNames, lcid, rgDispId):
397
+ # This call uses windll instead of oledll so that a failed
398
+ # call to DispGetIDsOfNames will return a HRESULT instead of
399
+ # raising an error.
400
+ try:
401
+ tinfo = self.__typeinfo
402
+ except AttributeError:
403
+ return hresult.E_NOTIMPL
404
+ return windll.oleaut32.DispGetIDsOfNames(tinfo, rgszNames, cNames, rgDispId)
405
+
406
+ def IDispatch_Invoke(
407
+ self,
408
+ this,
409
+ dispIdMember,
410
+ riid,
411
+ lcid,
412
+ wFlags,
413
+ pDispParams,
414
+ pVarResult,
415
+ pExcepInfo,
416
+ puArgErr,
417
+ ):
418
+ try:
419
+ self._dispimpl_
420
+ except AttributeError:
421
+ try:
422
+ tinfo = self.__typeinfo
423
+ except AttributeError:
424
+ # Hm, we pretend to implement IDispatch, but have no
425
+ # typeinfo, and so cannot fulfill the contract. Should we
426
+ # better return E_NOTIMPL or DISP_E_MEMBERNOTFOUND? Some
427
+ # clients call IDispatch_Invoke with 'known' DISPID_...'
428
+ # values, without going through GetIDsOfNames first.
429
+ return hresult.DISP_E_MEMBERNOTFOUND
430
+ # This call uses windll instead of oledll so that a failed
431
+ # call to DispInvoke will return a HRESULT instead of raising
432
+ # an error.
433
+ interface = self._com_interfaces_[0]
434
+ ptr = self._com_pointers_[interface._iid_]
435
+ return windll.oleaut32.DispInvoke(
436
+ ptr,
437
+ tinfo,
438
+ dispIdMember,
439
+ wFlags,
440
+ pDispParams,
441
+ pVarResult,
442
+ pExcepInfo,
443
+ puArgErr,
444
+ )
445
+
446
+ try:
447
+ # XXX Hm, wFlags should be considered a SET of flags...
448
+ mth = self._dispimpl_[(dispIdMember, wFlags)]
449
+ except KeyError:
450
+ return hresult.DISP_E_MEMBERNOTFOUND
451
+
452
+ # Unpack the parameters: It would be great if we could use the
453
+ # DispGetParam function - but we cannot since it requires that
454
+ # we pass a VARTYPE for each argument and we do not know that.
455
+ #
456
+ # Seems that n arguments have dispids (0, 1, ..., n-1).
457
+ # Unnamed arguments are packed into the DISPPARAMS array in
458
+ # reverse order (starting with the highest dispid), named
459
+ # arguments are packed in the order specified by the
460
+ # rgdispidNamedArgs array.
461
+ #
462
+ params = pDispParams[0]
463
+
464
+ if wFlags & (4 | 8):
465
+ # DISPATCH_PROPERTYPUT
466
+ # DISPATCH_PROPERTYPUTREF
467
+ #
468
+ # How are the parameters unpacked for propertyput
469
+ # operations with additional parameters? Can propput
470
+ # have additional args?
471
+ args = [
472
+ params.rgvarg[i].value for i in reversed(list(range(params.cNamedArgs)))
473
+ ]
474
+ # MSDN: pVarResult is ignored if DISPATCH_PROPERTYPUT or
475
+ # DISPATCH_PROPERTYPUTREF is specified.
476
+ return mth(this, *args)
477
+
478
+ else:
479
+ # DISPATCH_METHOD
480
+ # DISPATCH_PROPERTYGET
481
+ # the positions of named arguments
482
+ #
483
+ # 2to3 has problems to translate 'range(...)[::-1]'
484
+ # correctly, so use 'list(range)[::-1]' instead (will be
485
+ # fixed in Python 3.1, probably):
486
+ named_indexes = [
487
+ params.rgdispidNamedArgs[i] for i in range(params.cNamedArgs)
488
+ ]
489
+ # the positions of unnamed arguments
490
+ num_unnamed = params.cArgs - params.cNamedArgs
491
+ unnamed_indexes = list(reversed(list(range(num_unnamed))))
492
+ # It seems that this code calculates the indexes of the
493
+ # parameters in the params.rgvarg array correctly.
494
+ indexes = named_indexes + unnamed_indexes
495
+ args = [params.rgvarg[i].value for i in indexes]
496
+
497
+ if pVarResult and getattr(mth, "has_outargs", False):
498
+ args.append(pVarResult)
499
+ return mth(this, *args)
500
+
501
+ ################################################################
502
+ # IPersist interface
503
+ def IPersist_GetClassID(self) -> GUID:
504
+ return self._reg_clsid_
505
+
506
+
507
+ __all__ = ["COMObject"]