comtypes 1.4.7__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 (149) hide show
  1. {comtypes-1.4.7 → comtypes-1.4.9}/CHANGES.txt +39 -0
  2. {comtypes-1.4.7/comtypes.egg-info → comtypes-1.4.9}/PKG-INFO +6 -4
  3. {comtypes-1.4.7 → comtypes-1.4.9}/README.md +5 -3
  4. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/GUID.py +6 -5
  5. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/__init__.py +16 -5
  6. comtypes-1.4.9/comtypes/_comobject.py +507 -0
  7. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/_memberspec.py +81 -9
  8. comtypes-1.4.9/comtypes/_meta.py +95 -0
  9. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/_npsupport.py +2 -1
  10. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/_post_coinit/__init__.py +1 -0
  11. comtypes-1.4.9/comtypes/_post_coinit/_cominterface_meta_patcher.py +153 -0
  12. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/_post_coinit/misc.py +21 -40
  13. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/_post_coinit/unknwn.py +88 -209
  14. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/_safearray.py +1 -2
  15. comtypes-1.4.9/comtypes/_vtbl.py +448 -0
  16. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/automation.py +36 -45
  17. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/client/__init__.py +21 -31
  18. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/client/_code_cache.py +5 -4
  19. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/client/_constants.py +1 -1
  20. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/client/_events.py +1 -2
  21. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/client/_generate.py +9 -13
  22. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/client/lazybind.py +2 -7
  23. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/errorinfo.py +3 -3
  24. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/git.py +2 -2
  25. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/hints.pyi +11 -19
  26. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/persist.py +7 -7
  27. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/safearray.py +12 -6
  28. comtypes-1.4.9/comtypes/server/__init__.py +86 -0
  29. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/server/inprocserver.py +22 -17
  30. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/server/localserver.py +28 -16
  31. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/server/register.py +62 -73
  32. comtypes-1.4.9/comtypes/server/w_getopt.py +48 -0
  33. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/shelllink.py +49 -67
  34. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/TestComServer.py +1 -1
  35. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/TestDispServer.py +1 -1
  36. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/__init__.py +9 -12
  37. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/find_memleak.py +0 -1
  38. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_BSTR.py +4 -7
  39. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_agilent.py +0 -1
  40. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_avmc.py +1 -1
  41. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_casesensitivity.py +3 -5
  42. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_clear_cache.py +1 -0
  43. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_collections.py +3 -3
  44. comtypes-1.4.9/comtypes/test/test_comobject.py +146 -0
  45. comtypes-1.4.9/comtypes/test/test_comserver.py +319 -0
  46. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_createwrappers.py +2 -6
  47. comtypes-1.4.9/comtypes/test/test_dispinterface.py +153 -0
  48. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_excel.py +22 -13
  49. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_ie.py +2 -5
  50. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_inout_args.py +8 -5
  51. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_midl_safearray_create.py +9 -1
  52. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_outparam.py +17 -10
  53. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_safearray.py +1 -90
  54. comtypes-1.4.9/comtypes/test/test_server.py +350 -0
  55. comtypes-1.4.9/comtypes/test/test_server_register.py +536 -0
  56. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_shelllink.py +10 -14
  57. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_showevents.py +7 -17
  58. comtypes-1.4.9/comtypes/test/test_stream.py +131 -0
  59. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_typeannotator.py +1 -1
  60. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_urlhistory.py +1 -0
  61. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_variant.py +0 -19
  62. comtypes-1.4.9/comtypes/test/test_w_getopt.py +29 -0
  63. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_win32com_interop.py +80 -36
  64. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_wmi.py +0 -3
  65. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/codegenerator/codegenerator.py +62 -68
  66. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/codegenerator/helpers.py +8 -8
  67. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/codegenerator/namespaces.py +97 -27
  68. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/codegenerator/packing.py +4 -4
  69. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/codegenerator/typeannotator.py +9 -11
  70. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/tlbparser.py +33 -32
  71. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/typedesc.py +3 -8
  72. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/typeinfo.py +32 -47
  73. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/util.py +1 -0
  74. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/viewobject.py +1 -5
  75. {comtypes-1.4.7 → comtypes-1.4.9/comtypes.egg-info}/PKG-INFO +6 -4
  76. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes.egg-info/SOURCES.txt +6 -3
  77. comtypes-1.4.9/pyproject.toml +55 -0
  78. comtypes-1.4.7/comtypes/_comobject.py +0 -834
  79. comtypes-1.4.7/comtypes/_idl_stuff.py +0 -67
  80. comtypes-1.4.7/comtypes/_meta.py +0 -70
  81. comtypes-1.4.7/comtypes/server/__init__.py +0 -69
  82. comtypes-1.4.7/comtypes/server/w_getopt.py +0 -75
  83. comtypes-1.4.7/comtypes/test/test_comserver.py +0 -239
  84. comtypes-1.4.7/comtypes/test/test_dispinterface.py +0 -138
  85. comtypes-1.4.7/comtypes/test/test_propputref.py +0 -40
  86. comtypes-1.4.7/comtypes/test/test_server.py +0 -348
  87. comtypes-1.4.7/comtypes/test/test_stream.py +0 -53
  88. comtypes-1.4.7/pyproject.toml +0 -3
  89. {comtypes-1.4.7 → comtypes-1.4.9}/LICENSE.txt +0 -0
  90. {comtypes-1.4.7 → comtypes-1.4.9}/MANIFEST.in +0 -0
  91. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/_post_coinit/bstr.py +0 -0
  92. /comtypes-1.4.7/comtypes/_py_instance_method.py → /comtypes-1.4.9/comtypes/_post_coinit/instancemethod.py +0 -0
  93. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/_tlib_version_checker.py +0 -0
  94. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/clear_cache.py +0 -0
  95. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/client/dynamic.py +0 -0
  96. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/connectionpoints.py +0 -0
  97. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/hresult.py +0 -0
  98. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/logutil.py +0 -0
  99. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/messageloop.py +0 -0
  100. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/patcher.py +0 -0
  101. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/server/automation.py +0 -0
  102. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/server/connectionpoints.py +0 -0
  103. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/stream.py +0 -0
  104. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/TestComServer.idl +0 -0
  105. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/TestComServer.tlb +0 -0
  106. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/TestDispServer.idl +0 -0
  107. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/TestDispServer.tlb +0 -0
  108. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/mylib.idl +0 -0
  109. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/mylib.tlb +0 -0
  110. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/mytypelib.idl +0 -0
  111. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/runtests.py +0 -0
  112. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/setup.py +0 -0
  113. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_DISPPARAMS.py +0 -0
  114. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_GUID.py +0 -0
  115. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_QueryService.py +0 -0
  116. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_basic.py +0 -0
  117. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_client.py +0 -0
  118. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_client_dynamic.py +0 -0
  119. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_client_regenerate_modules.py +0 -0
  120. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_dict.py +0 -0
  121. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_dispifc_records.py +0 -0
  122. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_dispifc_safearrays.py +0 -0
  123. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_dyndispatch.py +0 -0
  124. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_findgendir.py +0 -0
  125. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_getactiveobj.py +0 -0
  126. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_ienum.py +0 -0
  127. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_imfattributes.py +0 -0
  128. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_jscript.js +0 -0
  129. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_monikers.py +0 -0
  130. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_msscript.py +0 -0
  131. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_npsupport.py +0 -0
  132. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_persist.py +0 -0
  133. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_pump_events.py +0 -0
  134. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_recordinfo.py +0 -0
  135. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_sapi.py +0 -0
  136. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_storage.py +0 -0
  137. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_subinterface.py +0 -0
  138. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_typeinfo.py +0 -0
  139. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/test_word.py +0 -0
  140. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/test/urlhist.tlb +0 -0
  141. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/__init__.py +0 -0
  142. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/codegenerator/__init__.py +0 -0
  143. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/codegenerator/modulenamer.py +0 -0
  144. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes/tools/typedesc_base.py +0 -0
  145. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes.egg-info/dependency_links.txt +0 -0
  146. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes.egg-info/entry_points.txt +0 -0
  147. {comtypes-1.4.7 → comtypes-1.4.9}/comtypes.egg-info/top_level.txt +0 -0
  148. {comtypes-1.4.7 → comtypes-1.4.9}/setup.cfg +0 -0
  149. {comtypes-1.4.7 → comtypes-1.4.9}/setup.py +0 -0
@@ -1,10 +1,16 @@
1
+ import logging
2
+ import queue
1
3
  import sys
2
- from ctypes import *
4
+ from ctypes import byref, c_ulong, c_void_p, oledll
5
+ from typing import TYPE_CHECKING, Any, Literal, Optional, Sequence, Type
6
+
3
7
  import comtypes
4
- from comtypes.hresult import *
8
+ from comtypes import hresult
5
9
  from comtypes.server import IClassFactory
6
- import logging
7
- import queue
10
+
11
+ if TYPE_CHECKING:
12
+ from ctypes import _Pointer
13
+
8
14
 
9
15
  logger = logging.getLogger(__name__)
10
16
  _debug = logger.debug
@@ -16,31 +22,31 @@ REGCLS_SUSPENDED = 4 # register it as suspended, will be activated
16
22
  REGCLS_SURROGATE = 8 # must be used when a surrogate process
17
23
 
18
24
 
19
- def run(classes):
25
+ def run(classes: Sequence[Type[comtypes.COMObject]]) -> None:
20
26
  classobjects = [ClassFactory(cls) for cls in classes]
21
27
  comtypes.COMObject.__run_localserver__(classobjects)
22
28
 
23
29
 
24
30
  class ClassFactory(comtypes.COMObject):
25
31
  _com_interfaces_ = [IClassFactory]
26
- _locks = 0
27
- _queue = None
28
- regcls = REGCLS_MULTIPLEUSE
32
+ _locks: int = 0
33
+ _queue: Optional[queue.Queue] = None
34
+ regcls: int = REGCLS_MULTIPLEUSE
29
35
 
30
- def __init__(self, cls, *args, **kw):
36
+ def __init__(self, cls: Type[comtypes.COMObject], *args, **kw) -> None:
31
37
  super(ClassFactory, self).__init__()
32
38
  self._cls = cls
33
39
  self._register_class()
34
40
  self._args = args
35
41
  self._kw = kw
36
42
 
37
- def IUnknown_AddRef(self, this):
43
+ def IUnknown_AddRef(self, this: Any) -> int:
38
44
  return 2
39
45
 
40
- def IUnknown_Release(self, this):
46
+ def IUnknown_Release(self, this: Any) -> int:
41
47
  return 1
42
48
 
43
- def _register_class(self):
49
+ def _register_class(self) -> None:
44
50
  regcls = getattr(self._cls, "_regcls_", self.regcls)
45
51
  cookie = c_ulong()
46
52
  ptr = self._com_pointers_[comtypes.IUnknown._iid_]
@@ -55,19 +61,25 @@ class ClassFactory(comtypes.COMObject):
55
61
  )
56
62
  self.cookie = cookie
57
63
 
58
- def _revoke_class(self):
64
+ def _revoke_class(self) -> None:
59
65
  oledll.ole32.CoRevokeClassObject(self.cookie)
60
66
 
61
- def CreateInstance(self, this, punkOuter, riid, ppv):
67
+ def CreateInstance(
68
+ self,
69
+ this: Any,
70
+ punkOuter: Optional[Type["_Pointer[comtypes.IUnknown]"]],
71
+ riid: "_Pointer[comtypes.GUID]",
72
+ ppv: c_void_p,
73
+ ) -> int:
62
74
  _debug("ClassFactory.CreateInstance(%s)", riid[0])
63
75
  obj = self._cls(*self._args, **self._kw)
64
76
  result = obj.IUnknown_QueryInterface(None, riid, ppv)
65
77
  _debug("CreateInstance() -> %s", result)
66
78
  return result
67
79
 
68
- def LockServer(self, this, fLock):
80
+ def LockServer(self, this: Any, fLock: bool) -> Literal[0]:
69
81
  if fLock:
70
82
  comtypes.COMObject.__server__.Lock()
71
83
  else:
72
84
  comtypes.COMObject.__server__.Unlock()
73
- return S_OK
85
+ return hresult.S_OK
@@ -35,17 +35,19 @@ Now, debug the object, and when done delete logging info:
35
35
 
36
36
  python mycomobj.py /nodebug
37
37
  """
38
- import sys
38
+
39
+ import logging
39
40
  import os
41
+ import sys
40
42
  import winreg
41
- import logging
43
+ from ctypes import WinError, c_ulong, c_wchar_p, create_string_buffer, sizeof, windll
44
+ from typing import Iterator, Tuple
42
45
 
43
46
  import comtypes
44
- from comtypes.typeinfo import LoadTypeLibEx, UnRegisterTypeLib, REGKIND_REGISTER
47
+ import comtypes.server.inprocserver
45
48
  from comtypes.hresult import *
46
49
  from comtypes.server import w_getopt
47
- import comtypes.server.inprocserver
48
- from ctypes import windll, c_ulong, c_wchar_p, WinError, sizeof, create_string_buffer
50
+ from comtypes.typeinfo import REGKIND_REGISTER, LoadTypeLibEx, UnRegisterTypeLib
49
51
 
50
52
  _debug = logging.getLogger(__name__).debug
51
53
 
@@ -99,7 +101,7 @@ class Registrar(object):
99
101
  'DeleteKey( %s\\CLSID\\%s\\Logging"'
100
102
  % (_explain(winreg.HKEY_CLASSES_ROOT), clsid)
101
103
  )
102
- hkey = winreg.OpenKey(winreg.HKEY_CLASSES_ROOT, r"CLSID\%s" % clsid)
104
+ hkey = winreg.OpenKey(winreg.HKEY_CLASSES_ROOT, rf"CLSID\{clsid}")
103
105
  winreg.DeleteKey(hkey, "Logging")
104
106
  except WindowsError as detail:
105
107
  if get_winerror(detail) != 2:
@@ -114,7 +116,7 @@ class Registrar(object):
114
116
  'CreateKey( %s\\CLSID\\%s\\Logging"'
115
117
  % (_explain(winreg.HKEY_CLASSES_ROOT), clsid)
116
118
  )
117
- hkey = winreg.CreateKey(winreg.HKEY_CLASSES_ROOT, r"CLSID\%s\Logging" % clsid)
119
+ hkey = winreg.CreateKey(winreg.HKEY_CLASSES_ROOT, rf"CLSID\{clsid}\Logging")
118
120
  for item in levels:
119
121
  name, value = item.split("=")
120
122
  v = getattr(logging, value)
@@ -146,8 +148,7 @@ class Registrar(object):
146
148
  self._register(cls, executable)
147
149
 
148
150
  def _register(self, cls, executable=None):
149
- table = self._registry_entries(cls)
150
- table.sort()
151
+ table = sorted(RegistryEntries(cls))
151
152
  _debug("Registering %s", cls)
152
153
  for hkey, subkey, valuename, value in table:
153
154
  _debug("[%s\\%s]", _explain(hkey), subkey)
@@ -158,7 +159,7 @@ class Registrar(object):
158
159
  tlib = getattr(cls, "_reg_typelib_", None)
159
160
  if tlib is not None:
160
161
  if hasattr(sys, "frozendllhandle"):
161
- dll = self._get_serverdll()
162
+ dll = _get_serverdll()
162
163
  _debug("LoadTypeLibEx(%s, REGKIND_REGISTER)", dll)
163
164
  LoadTypeLibEx(dll, REGKIND_REGISTER)
164
165
  else:
@@ -183,7 +184,7 @@ class Registrar(object):
183
184
  def _unregister(self, cls, force=False):
184
185
  # If force==False, we only remove those entries that we
185
186
  # actually would have written. It seems ATL does the same.
186
- table = [t[:2] for t in self._registry_entries(cls)]
187
+ table = [t[:2] for t in RegistryEntries(cls)]
187
188
  # only unique entries
188
189
  table = list(set(table))
189
190
  table.sort()
@@ -213,23 +214,29 @@ class Registrar(object):
213
214
  raise
214
215
  _debug("Done")
215
216
 
216
- def _get_serverdll(self):
217
- """Return the pathname of the dll hosting the COM object."""
218
- handle = getattr(sys, "frozendllhandle", None)
219
- if handle is not None:
220
- buf = create_string_buffer(260)
221
- windll.kernel32.GetModuleFileNameA(handle, buf, sizeof(buf))
222
- return buf[:]
223
- import _ctypes
224
217
 
225
- return _ctypes.__file__
218
+ def _get_serverdll():
219
+ """Return the pathname of the dll hosting the COM object."""
220
+ handle = getattr(sys, "frozendllhandle", None)
221
+ if handle is not None:
222
+ buf = create_string_buffer(260)
223
+ windll.kernel32.GetModuleFileNameA(handle, buf, sizeof(buf))
224
+ return buf[:]
225
+ import _ctypes
226
+
227
+ return _ctypes.__file__
228
+
229
+
230
+ class RegistryEntries(object):
231
+ def __init__(self, cls):
232
+ self._cls = cls
226
233
 
227
234
  def _get_full_classname(self, cls):
228
235
  """Return <modulename>.<classname> for 'cls'."""
229
236
  modname = cls.__module__
230
237
  if modname == "__main__":
231
238
  modname = os.path.splitext(os.path.basename(sys.argv[0]))[0]
232
- return "%s.%s" % (modname, cls.__name__)
239
+ return f"{modname}.{cls.__name__}"
233
240
 
234
241
  def _get_pythonpath(self, cls):
235
242
  """Return the filesystem path of the module containing 'cls'."""
@@ -237,8 +244,8 @@ class Registrar(object):
237
244
  dirname = os.path.dirname(sys.modules[modname].__file__)
238
245
  return os.path.abspath(dirname)
239
246
 
240
- def _registry_entries(self, cls):
241
- """Return a sequence of tuples containing registry entries.
247
+ def __iter__(self) -> Iterator[Tuple[int, str, str, str]]:
248
+ """Return a iterator of tuples containing registry entries.
242
249
 
243
250
  The tuples must be (key, subkey, name, value).
244
251
 
@@ -258,16 +265,13 @@ class Registrar(object):
258
265
  Note that the first part of the progid string is typically the
259
266
  IDL library name of the type library containing the coclass.
260
267
  """
268
+ cls = self._cls
261
269
  HKCR = winreg.HKEY_CLASSES_ROOT
262
270
 
263
- # table format: rootkey, subkey, valuename, value
264
- table = []
265
- append = lambda *args: table.append(args)
266
-
267
271
  # basic entry - names the comobject
268
- reg_clsid = str(
269
- cls._reg_clsid_
270
- ) # that's the only required attribute for registration
272
+
273
+ # that's the only required attribute for registration
274
+ reg_clsid = str(cls._reg_clsid_)
271
275
  reg_desc = getattr(cls, "_reg_desc_", "")
272
276
  if not reg_desc:
273
277
  # Simple minded algorithm to construct a description from
@@ -277,95 +281,83 @@ class Registrar(object):
277
281
  )
278
282
  if reg_desc:
279
283
  reg_desc = reg_desc.replace(".", " ")
280
- append(HKCR, "CLSID\\%s" % reg_clsid, "", reg_desc)
284
+ yield (HKCR, f"CLSID\\{reg_clsid}", "", reg_desc)
281
285
 
282
286
  reg_progid = getattr(cls, "_reg_progid_", None)
283
287
  if reg_progid:
284
288
  # for ProgIDFromCLSID:
285
- append(HKCR, "CLSID\\%s\\ProgID" % reg_clsid, "", reg_progid) # 1
289
+ yield (HKCR, f"CLSID\\{reg_clsid}\\ProgID", "", reg_progid) # 1
286
290
 
287
291
  # for CLSIDFromProgID
288
292
  if reg_desc:
289
- append(HKCR, reg_progid, "", reg_desc) # 2
290
- append(HKCR, "%s\\CLSID" % reg_progid, "", reg_clsid) # 3
293
+ yield (HKCR, reg_progid, "", reg_desc) # 2
294
+ yield (HKCR, f"{reg_progid}\\CLSID", "", reg_clsid) # 3
291
295
 
292
296
  reg_novers_progid = getattr(cls, "_reg_novers_progid_", None)
293
297
  if reg_novers_progid:
294
- append(
298
+ yield (
295
299
  HKCR,
296
- "CLSID\\%s\\VersionIndependentProgID" % reg_clsid, # 1a
300
+ f"CLSID\\{reg_clsid}\\VersionIndependentProgID", # 1a
297
301
  "",
298
302
  reg_novers_progid,
299
303
  )
300
304
  if reg_desc:
301
- append(HKCR, reg_novers_progid, "", reg_desc) # 2a
302
- append(HKCR, "%s\\CurVer" % reg_novers_progid, "", reg_progid) #
303
- append(HKCR, "%s\\CLSID" % reg_novers_progid, "", reg_clsid) # 3a
305
+ yield (HKCR, reg_novers_progid, "", reg_desc) # 2a
306
+ yield (HKCR, f"{reg_novers_progid}\\CurVer", "", reg_progid) #
307
+ yield (HKCR, f"{reg_novers_progid}\\CLSID", "", reg_clsid) # 3a
304
308
 
305
- clsctx = getattr(cls, "_reg_clsctx_", 0)
309
+ clsctx: int = getattr(cls, "_reg_clsctx_", 0)
310
+ localsvr_ctx = bool(clsctx & comtypes.CLSCTX_LOCAL_SERVER)
311
+ inprocsvr_ctx = bool(clsctx & comtypes.CLSCTX_INPROC_SERVER)
306
312
 
307
- if clsctx & comtypes.CLSCTX_LOCAL_SERVER and not hasattr(
308
- sys, "frozendllhandle"
309
- ):
313
+ if localsvr_ctx and not hasattr(sys, "frozendllhandle"):
310
314
  exe = sys.executable
311
315
  if " " in exe:
312
- exe = '"%s"' % exe
316
+ exe = f'"{exe}"'
313
317
  if not hasattr(sys, "frozen"):
314
318
  if not __debug__:
315
- exe = "%s -O" % exe
319
+ exe = f"{exe} -O"
316
320
  script = os.path.abspath(sys.modules[cls.__module__].__file__)
317
321
  if " " in script:
318
- script = '"%s"' % script
319
- append(
320
- HKCR,
321
- "CLSID\\%s\\LocalServer32" % reg_clsid,
322
- "",
323
- "%s %s" % (exe, script),
324
- )
322
+ script = f'"{script}"'
323
+ yield (HKCR, rf"CLSID\{reg_clsid}\LocalServer32", "", f"{exe} {script}")
325
324
  else:
326
- append(HKCR, "CLSID\\%s\\LocalServer32" % reg_clsid, "", "%s" % exe)
325
+ yield (HKCR, rf"CLSID\{reg_clsid}\LocalServer32", "", f"{exe}")
327
326
 
328
327
  # Register InprocServer32 only when run from script or from
329
328
  # py2exe dll server, not from py2exe exe server.
330
- if clsctx & comtypes.CLSCTX_INPROC_SERVER and getattr(sys, "frozen", None) in (
331
- None,
332
- "dll",
333
- ):
334
- append(
335
- HKCR, "CLSID\\%s\\InprocServer32" % reg_clsid, "", self._get_serverdll()
336
- )
329
+ if inprocsvr_ctx and getattr(sys, "frozen", None) in (None, "dll"):
330
+ yield (HKCR, rf"CLSID\{reg_clsid}\InprocServer32", "", _get_serverdll())
337
331
  # only for non-frozen inproc servers the PythonPath/PythonClass is needed.
338
332
  if (
339
333
  not hasattr(sys, "frozendllhandle")
340
334
  or not comtypes.server.inprocserver._clsid_to_class
341
335
  ):
342
- append(
336
+ yield (
343
337
  HKCR,
344
- "CLSID\\%s\\InprocServer32" % reg_clsid,
338
+ rf"CLSID\{reg_clsid}\InprocServer32",
345
339
  "PythonClass",
346
340
  self._get_full_classname(cls),
347
341
  )
348
- append(
342
+ yield (
349
343
  HKCR,
350
- "CLSID\\%s\\InprocServer32" % reg_clsid,
344
+ rf"CLSID\{reg_clsid}\InprocServer32",
351
345
  "PythonPath",
352
346
  self._get_pythonpath(cls),
353
347
  )
354
348
 
355
349
  reg_threading = getattr(cls, "_reg_threading_", None)
356
350
  if reg_threading is not None:
357
- append(
351
+ yield (
358
352
  HKCR,
359
- "CLSID\\%s\\InprocServer32" % reg_clsid,
353
+ rf"CLSID\{reg_clsid}\InprocServer32",
360
354
  "ThreadingModel",
361
355
  reg_threading,
362
356
  )
363
357
 
364
358
  reg_tlib = getattr(cls, "_reg_typelib_", None)
365
359
  if reg_tlib is not None:
366
- append(HKCR, "CLSID\\%s\\Typelib" % reg_clsid, "", reg_tlib[0])
367
-
368
- return table
360
+ yield (HKCR, rf"CLSID\{reg_clsid}\Typelib", "", reg_tlib[0])
369
361
 
370
362
 
371
363
  ################################################################
@@ -380,10 +372,7 @@ def unregister(cls):
380
372
 
381
373
 
382
374
  def UseCommandLine(*classes):
383
- usage = (
384
- """Usage: %s [-regserver] [-unregserver] [-nodebug] [-f logformat] [-l loggername=level]"""
385
- % sys.argv[0]
386
- )
375
+ usage = f"""Usage: {sys.argv[0]} [-regserver] [-unregserver] [-nodebug] [-f logformat] [-l loggername=level]"""
387
376
  opts, args = w_getopt.w_getopt(
388
377
  sys.argv[1:], "regserver unregserver embedding l: f: nodebug"
389
378
  )
@@ -0,0 +1,48 @@
1
+ from typing import Sequence, Tuple
2
+
3
+
4
+ class GetoptError(Exception):
5
+ pass
6
+
7
+
8
+ def w_getopt(
9
+ args: Sequence[str], options: str
10
+ ) -> Tuple[Sequence[Tuple[str, str]], Sequence[str]]:
11
+ """A getopt for Windows.
12
+
13
+ Options may start with either '-' or '/', the option names may
14
+ have more than one letter (/tlb or -RegServer), and option names
15
+ are case insensitive.
16
+
17
+ Returns two elements, just as getopt.getopt. The first is a list
18
+ of (option, value) pairs in the same way getopt.getopt does, but
19
+ there is no '-' or '/' prefix to the option name, and the option
20
+ name is always lower case. The second is the list of arguments
21
+ which do not belong to an option.
22
+
23
+ Different from getopt.getopt, a single argument not belonging to an option
24
+ does not terminate parsing.
25
+ """
26
+ opts = []
27
+ arguments = []
28
+ while args:
29
+ if args[0][:1] in "/-":
30
+ arg = args[0][1:] # strip the '-' or '/'
31
+ arg = arg.lower()
32
+
33
+ if arg + ":" in options:
34
+ try:
35
+ opts.append((arg, args[1]))
36
+ except IndexError:
37
+ raise GetoptError(f"option '{args[0]}' requires an argument")
38
+ args = args[1:]
39
+ elif arg in options:
40
+ opts.append((arg, ""))
41
+ else:
42
+ raise GetoptError(f"invalid option '{args[0]}'")
43
+ args = args[1:]
44
+ else:
45
+ arguments.append(args[0])
46
+ args = args[1:]
47
+
48
+ return opts, arguments
@@ -1,9 +1,8 @@
1
- from __future__ import print_function
2
1
  from ctypes import c_char_p, c_int, c_short, c_wchar_p
3
2
  from ctypes import POINTER
4
3
  from ctypes import byref, create_string_buffer, create_unicode_buffer
5
4
  from ctypes.wintypes import DWORD, WIN32_FIND_DATAA, WIN32_FIND_DATAW, MAX_PATH
6
- from typing import Tuple, TYPE_CHECKING
5
+ from typing import Tuple, TYPE_CHECKING, Literal
7
6
 
8
7
  from comtypes import IUnknown, GUID, COMMETHOD, HRESULT, CoClass
9
8
 
@@ -18,19 +17,24 @@ SLGP_UNCPRIORITY = 0x2
18
17
  SLGP_RAWPATH = 0x4
19
18
 
20
19
  # for SetShowCmd, GetShowCmd
21
- ##SW_SHOWNORMAL
22
- ##SW_SHOWMAXIMIZED
23
- ##SW_SHOWMINNOACTIVE
24
-
20
+ SW_SHOWNORMAL = 0x01
21
+ SW_SHOWMAXIMIZED = 0x03
22
+ SW_SHOWMINNOACTIVE = 0x07
25
23
 
26
24
  # for Resolve
27
- ##SLR_INVOKE_MSI
28
- ##SLR_NOLINKINFO
29
- ##SLR_NO_UI
30
- ##SLR_NOUPDATE
31
- ##SLR_NOSEARCH
32
- ##SLR_NOTRACK
33
- ##SLR_UPDATE
25
+ SLR_INVOKE_MSI = 0x0080
26
+ SLR_NOLINKINFO = 0x0040
27
+ SLR_NO_UI = 0x0001
28
+ SLR_NOUPDATE = 0x0008
29
+ SLR_NOSEARCH = 0x0010
30
+ SLR_NOTRACK = 0x0020
31
+ SLR_UPDATE = 0x0004
32
+
33
+ # for Hotkey
34
+ HOTKEYF_ALT = 0x04
35
+ HOTKEYF_CONTROL = 0x02
36
+ HOTKEYF_EXT = 0x08
37
+ HOTKEYF_SHIFT = 0x01
34
38
 
35
39
  # fake these...
36
40
  ITEMIDLIST = c_int
@@ -123,25 +127,26 @@ class IShellLinkA(IUnknown):
123
127
  ]
124
128
 
125
129
  if TYPE_CHECKING:
126
- # fmt: off
127
- def GetIDList(self) -> hints.Incomplete: ... # noqa
128
- def SetIDList(self, pidl: hints.Incomplete) -> hints.Incomplete: ... # noqa
129
- def SetDescription(self, pszName: bytes) -> hints.Incomplete: ... # noqa
130
- def SetWorkingDirectory(self, pszDir: bytes) -> hints.Hresult: ... # noqa
131
- def SetArguments(self, pszArgs: bytes) -> hints.Hresult: ... # noqa
130
+
131
+ def GetIDList(self) -> hints.Incomplete: ...
132
+ def SetIDList(self, pidl: hints.Incomplete) -> hints.Incomplete: ...
133
+ def SetDescription(self, pszName: bytes) -> hints.Incomplete: ...
134
+ def SetWorkingDirectory(self, pszDir: bytes) -> hints.Hresult: ...
135
+ def SetArguments(self, pszArgs: bytes) -> hints.Hresult: ...
132
136
  @property
133
- def Hotkey(self) -> int: ... # noqa
137
+ def Hotkey(self) -> int: ...
134
138
  @Hotkey.setter
135
- def Hotkey(self, pwHotkey: int) -> None: ... # noqa
139
+ def Hotkey(self, pwHotkey: int) -> None: ...
136
140
  @property
137
- def ShowCmd(self) -> int: ... # noqa
141
+ def ShowCmd(self) -> int: ...
138
142
  @ShowCmd.setter
139
- def ShowCmd(self, piShowCmd: int) -> None: ... # noqa
140
- def SetIconLocation(self, pszIconPath: bytes, iIcon: int) -> hints.Hresult: ... # noqa
141
- def SetRelativePath(self, pszPathRel: bytes, dwReserved: hints.Literal[0]) -> hints.Hresult: ... # noqa
142
- def Resolve(self, hwnd: int, fFlags: int) -> hints.Hresult: ... # noqa
143
- def SetPath(self, pszFile: bytes) -> hints.Hresult: ... # noqa
144
- # fmt: on
143
+ def ShowCmd(self, piShowCmd: int) -> None: ...
144
+ def SetIconLocation(self, pszIconPath: bytes, iIcon: int) -> hints.Hresult: ...
145
+ def SetRelativePath(
146
+ self, pszPathRel: bytes, dwReserved: Literal[0]
147
+ ) -> hints.Hresult: ...
148
+ def Resolve(self, hwnd: int, fFlags: int) -> hints.Hresult: ...
149
+ def SetPath(self, pszFile: bytes) -> hints.Hresult: ...
145
150
 
146
151
  def GetPath(self, flags: int = SLGP_SHORTPATH) -> bytes:
147
152
  buf = create_string_buffer(MAX_PATH)
@@ -257,25 +262,26 @@ class IShellLinkW(IUnknown):
257
262
  ]
258
263
 
259
264
  if TYPE_CHECKING:
260
- # fmt: off
261
- def GetIDList(self) -> hints.Incomplete: ... # noqa
262
- def SetIDList(self, pidl: hints.Incomplete) -> hints.Incomplete: ... # noqa
263
- def SetDescription(self, pszName: str) -> hints.Incomplete: ... # noqa
264
- def SetWorkingDirectory(self, pszDir: str) -> hints.Hresult: ... # noqa
265
- def SetArguments(self, pszArgs: str) -> hints.Hresult: ... # noqa
265
+
266
+ def GetIDList(self) -> hints.Incomplete: ...
267
+ def SetIDList(self, pidl: hints.Incomplete) -> hints.Incomplete: ...
268
+ def SetDescription(self, pszName: str) -> hints.Incomplete: ...
269
+ def SetWorkingDirectory(self, pszDir: str) -> hints.Hresult: ...
270
+ def SetArguments(self, pszArgs: str) -> hints.Hresult: ...
266
271
  @property
267
- def Hotkey(self) -> int: ... # noqa
272
+ def Hotkey(self) -> int: ...
268
273
  @Hotkey.setter
269
- def Hotkey(self, pwHotkey: int) -> None: ... # noqa
274
+ def Hotkey(self, pwHotkey: int) -> None: ...
270
275
  @property
271
- def ShowCmd(self) -> int: ... # noqa
276
+ def ShowCmd(self) -> int: ...
272
277
  @ShowCmd.setter
273
- def ShowCmd(self, piShowCmd: int) -> None: ... # noqa
274
- def SetIconLocation(self, pszIconPath: str, iIcon: int) -> hints.Hresult: ... # noqa
275
- def SetRelativePath(self, pszPathRel: str, dwReserved: hints.Literal[0]) -> hints.Hresult: ... # noqa
276
- def Resolve(self, hwnd: int, fFlags: int) -> hints.Hresult: ... # noqa
277
- def SetPath(self, pszFile: str) -> hints.Hresult: ... # noqa
278
- # fmt: on
278
+ def ShowCmd(self, piShowCmd: int) -> None: ...
279
+ def SetIconLocation(self, pszIconPath: str, iIcon: int) -> hints.Hresult: ...
280
+ def SetRelativePath(
281
+ self, pszPathRel: str, dwReserved: Literal[0]
282
+ ) -> hints.Hresult: ...
283
+ def Resolve(self, hwnd: int, fFlags: int) -> hints.Hresult: ...
284
+ def SetPath(self, pszFile: str) -> hints.Hresult: ...
279
285
 
280
286
  def GetPath(self, flags: int = SLGP_SHORTPATH) -> str:
281
287
  buf = create_unicode_buffer(MAX_PATH)
@@ -311,27 +317,3 @@ class ShellLink(CoClass):
311
317
  _reg_clsid_ = GUID("{00021401-0000-0000-C000-000000000046}")
312
318
  _idlflags_ = []
313
319
  _com_interfaces_ = [IShellLinkW, IShellLinkA]
314
-
315
-
316
- if __name__ == "__main__":
317
-
318
- import sys
319
- import comtypes
320
- from comtypes.client import CreateObject
321
- from comtypes.persist import IPersistFile
322
-
323
- shortcut = CreateObject(ShellLink)
324
- print(shortcut)
325
- ##help(shortcut)
326
-
327
- shortcut.SetPath(sys.executable)
328
-
329
- shortcut.SetDescription("Python %s" % sys.version)
330
- shortcut.SetIconLocation(sys.executable, 1)
331
-
332
- print(shortcut.GetPath(2))
333
- print(shortcut.GetIconLocation())
334
-
335
- pf = shortcut.QueryInterface(IPersistFile)
336
- pf.Save("foo.lnk", True)
337
- print(pf.GetCurFile())
@@ -33,6 +33,7 @@ from comtypes.gen import TestComServerLib
33
33
 
34
34
  ################################################################
35
35
 
36
+
36
37
  # Implement the CoClass. Use the coclass from the wrapper as base
37
38
  # class, and use DualDispMixin as base class which provides default
38
39
  # implementations of IDispatch, IProvideClassInfo, IProvideClassInfo2
@@ -42,7 +43,6 @@ class TestComServer(
42
43
  TestComServerLib.TestComServer, # the coclass from the typelib wrapper
43
44
  comtypes.server.connectionpoints.ConnectableObjectMixin,
44
45
  ):
45
-
46
46
  # The default interface from the typelib MUST be the first
47
47
  # interface, other interfaces can follow
48
48
 
@@ -31,6 +31,7 @@ from comtypes.gen import TestDispServerLib
31
31
 
32
32
  ################################################################
33
33
 
34
+
34
35
  # Implement the CoClass by defining a subclass of the
35
36
  # TestDispServerLib.TestDispServer class in the wrapper file. The
36
37
  # COMObject base class provides default implementations of the
@@ -42,7 +43,6 @@ class TestDispServer(
42
43
  TestDispServerLib.TestDispServer, # the coclass from the typelib wrapper
43
44
  comtypes.server.connectionpoints.ConnectableObjectMixin,
44
45
  ):
45
-
46
46
  # The default interface from the typelib MUST be the first
47
47
  # interface, other interfaces can follow
48
48
 
@@ -1,6 +1,5 @@
1
1
  # comtypes.test package.
2
2
 
3
- from __future__ import print_function
4
3
  import ctypes
5
4
  import getopt
6
5
  import os
@@ -65,7 +64,7 @@ def requires(resource, msg=None):
65
64
  return
66
65
  if not is_resource_enabled(resource):
67
66
  if msg is None:
68
- msg = "Use of the `%s' resource not enabled" % resource
67
+ msg = f"Use of the `{resource}` resource not enabled"
69
68
  raise ResourceDenied(msg)
70
69
 
71
70
 
@@ -95,12 +94,10 @@ def get_tests(package, mask, verbosity):
95
94
  except ResourceDenied as detail:
96
95
  skipped.append(modname)
97
96
  if verbosity > 1:
98
- print("Skipped %s: %s" % (modname, detail), file=sys.stderr)
97
+ print(f"Skipped {modname}: {detail}", file=sys.stderr)
99
98
  continue
100
99
  except Exception as detail:
101
- print(
102
- "Warning: could not import %s: %s" % (modname, detail), file=sys.stderr
103
- )
100
+ print(f"Warning: could not import {modname}: {detail}", file=sys.stderr)
104
101
  continue
105
102
  for name in dir(mod):
106
103
  if name.startswith("_"):
@@ -150,9 +147,9 @@ def test_with_refcounts(runner, verbosity, testcase):
150
147
  cleanup()
151
148
  refcounts[i] = sys.gettotalrefcount() - rc
152
149
  if [_f for _f in refcounts if _f]:
153
- print("%s leaks:\n\t" % testcase, refcounts)
150
+ print(f"{testcase} leaks:\n\t", refcounts)
154
151
  elif verbosity:
155
- print("%s: ok." % testcase)
152
+ print(f"{testcase}: ok.")
156
153
 
157
154
 
158
155
  class TestRunner(unittest.TextTestRunner):
@@ -181,21 +178,21 @@ class TestRunner(unittest.TextTestRunner):
181
178
  len(skipped) != 1 and "s" or "",
182
179
  )
183
180
  )
184
- self.stream.writeln("Unavailable resources: %s" % ", ".join(requested))
181
+ self.stream.writeln(f"Unavailable resources: {', '.join(requested)}")
185
182
  else:
186
183
  self.stream.writeln(
187
- "Ran %d test%s in %.3fs" % (run, run != 1 and "s" or "", timeTaken)
184
+ f"Ran {run} test{'s' if run != 1 else ''} in {timeTaken:.3f}s"
188
185
  )
189
186
  self.stream.writeln()
190
187
  if not result.wasSuccessful():
191
188
  self.stream.write("FAILED (")
192
189
  failed, errored = list(map(len, (result.failures, result.errors)))
193
190
  if failed:
194
- self.stream.write("failures=%d" % failed)
191
+ self.stream.write(f"failures={failed}")
195
192
  if errored:
196
193
  if failed:
197
194
  self.stream.write(", ")
198
- self.stream.write("errors=%d" % errored)
195
+ self.stream.write(f"errors={errored}")
199
196
  self.stream.writeln(")")
200
197
  else:
201
198
  self.stream.writeln("OK")