comtypes 1.4.4__zip → 1.4.6__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 (133) hide show
  1. {comtypes-1.4.4 → comtypes-1.4.6}/CHANGES.txt +24 -0
  2. {comtypes-1.4.4/comtypes.egg-info → comtypes-1.4.6}/PKG-INFO +1 -1
  3. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/GUID.py +24 -24
  4. comtypes-1.4.6/comtypes/__init__.py +268 -0
  5. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/_comobject.py +2 -1
  6. comtypes-1.4.6/comtypes/_idl_stuff.py +67 -0
  7. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/_memberspec.py +4 -12
  8. comtypes-1.4.6/comtypes/_post_coinit/__init__.py +15 -0
  9. comtypes-1.4.6/comtypes/_post_coinit/bstr.py +30 -0
  10. comtypes-1.4.6/comtypes/_post_coinit/misc.py +385 -0
  11. comtypes-1.4.6/comtypes/_post_coinit/unknwn.py +537 -0
  12. comtypes-1.4.6/comtypes/_py_instance_method.py +13 -0
  13. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/_safearray.py +3 -2
  14. comtypes-1.4.6/comtypes/_tlib_version_checker.py +18 -0
  15. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/automation.py +34 -45
  16. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/client/__init__.py +2 -9
  17. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/client/_code_cache.py +2 -2
  18. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/client/_generate.py +2 -1
  19. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/hints.pyi +38 -16
  20. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/safearray.py +11 -4
  21. comtypes-1.4.6/comtypes/stream.py +65 -0
  22. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/test_client.py +11 -0
  23. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/test_dispifc_records.py +1 -1
  24. comtypes-1.4.6/comtypes/test/test_dispifc_safearrays.py +89 -0
  25. comtypes-1.4.6/comtypes/test/test_istream.py +53 -0
  26. comtypes-1.4.6/comtypes/test/test_midl_safearray_create.py +100 -0
  27. comtypes-1.4.6/comtypes/test/test_recordinfo.py +79 -0
  28. comtypes-1.4.6/comtypes/test/test_typeannotator.py +127 -0
  29. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/test_wmi.py +11 -18
  30. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/tools/codegenerator/codegenerator.py +0 -1
  31. comtypes-1.4.6/comtypes/tools/codegenerator/modulenamer.py +23 -0
  32. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/tools/codegenerator/typeannotator.py +27 -22
  33. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/tools/tlbparser.py +22 -24
  34. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/tools/typedesc_base.py +2 -8
  35. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/typeinfo.py +33 -35
  36. {comtypes-1.4.4 → comtypes-1.4.6/comtypes.egg-info}/PKG-INFO +1 -1
  37. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes.egg-info/SOURCES.txt +13 -0
  38. {comtypes-1.4.4 → comtypes-1.4.6}/setup.cfg +1 -0
  39. comtypes-1.4.4/comtypes/__init__.py +0 -1229
  40. comtypes-1.4.4/comtypes/tools/codegenerator/modulenamer.py +0 -24
  41. {comtypes-1.4.4 → comtypes-1.4.6}/LICENSE.txt +0 -0
  42. {comtypes-1.4.4 → comtypes-1.4.6}/MANIFEST.in +0 -0
  43. {comtypes-1.4.4 → comtypes-1.4.6}/README.md +0 -0
  44. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/_meta.py +0 -0
  45. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/_npsupport.py +0 -0
  46. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/clear_cache.py +0 -0
  47. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/client/_constants.py +0 -0
  48. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/client/_events.py +0 -0
  49. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/client/dynamic.py +0 -0
  50. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/client/lazybind.py +0 -0
  51. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/connectionpoints.py +0 -0
  52. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/errorinfo.py +0 -0
  53. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/git.py +0 -0
  54. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/hresult.py +0 -0
  55. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/logutil.py +0 -0
  56. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/messageloop.py +0 -0
  57. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/patcher.py +0 -0
  58. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/persist.py +0 -0
  59. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/server/__init__.py +0 -0
  60. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/server/automation.py +0 -0
  61. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/server/connectionpoints.py +0 -0
  62. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/server/inprocserver.py +0 -0
  63. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/server/localserver.py +0 -0
  64. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/server/register.py +0 -0
  65. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/server/w_getopt.py +0 -0
  66. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/shelllink.py +0 -0
  67. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/TestComServer.idl +0 -0
  68. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/TestComServer.py +0 -0
  69. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/TestComServer.tlb +0 -0
  70. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/TestDispServer.idl +0 -0
  71. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/TestDispServer.py +0 -0
  72. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/TestDispServer.tlb +0 -0
  73. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/__init__.py +0 -0
  74. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/find_memleak.py +0 -0
  75. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/mylib.idl +0 -0
  76. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/mylib.tlb +0 -0
  77. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/mytypelib.idl +0 -0
  78. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/runtests.py +0 -0
  79. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/setup.py +0 -0
  80. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/test_BSTR.py +0 -0
  81. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/test_DISPPARAMS.py +0 -0
  82. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/test_GUID.py +0 -0
  83. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/test_QueryService.py +0 -0
  84. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/test_agilent.py +0 -0
  85. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/test_avmc.py +0 -0
  86. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/test_basic.py +0 -0
  87. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/test_casesensitivity.py +0 -0
  88. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/test_clear_cache.py +0 -0
  89. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/test_client_dynamic.py +0 -0
  90. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/test_client_regenerate_modules.py +0 -0
  91. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/test_collections.py +0 -0
  92. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/test_comserver.py +0 -0
  93. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/test_createwrappers.py +0 -0
  94. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/test_dict.py +0 -0
  95. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/test_dispinterface.py +0 -0
  96. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/test_dyndispatch.py +0 -0
  97. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/test_excel.py +0 -0
  98. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/test_findgendir.py +0 -0
  99. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/test_getactiveobj.py +0 -0
  100. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/test_ie.py +0 -0
  101. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/test_ienum.py +0 -0
  102. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/test_imfattributes.py +0 -0
  103. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/test_inout_args.py +0 -0
  104. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/test_jscript.js +0 -0
  105. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/test_msscript.py +0 -0
  106. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/test_npsupport.py +0 -0
  107. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/test_outparam.py +0 -0
  108. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/test_propputref.py +0 -0
  109. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/test_pump_events.py +0 -0
  110. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/test_safearray.py +0 -0
  111. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/test_sapi.py +0 -0
  112. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/test_server.py +0 -0
  113. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/test_showevents.py +0 -0
  114. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/test_subinterface.py +0 -0
  115. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/test_typeinfo.py +0 -0
  116. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/test_urlhistory.py +0 -0
  117. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/test_variant.py +0 -0
  118. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/test_win32com_interop.py +0 -0
  119. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/test_word.py +0 -0
  120. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/test/urlhist.tlb +0 -0
  121. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/tools/__init__.py +0 -0
  122. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/tools/codegenerator/__init__.py +0 -0
  123. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/tools/codegenerator/helpers.py +0 -0
  124. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/tools/codegenerator/namespaces.py +0 -0
  125. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/tools/codegenerator/packing.py +0 -0
  126. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/tools/typedesc.py +0 -0
  127. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/util.py +0 -0
  128. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes/viewobject.py +0 -0
  129. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes.egg-info/dependency_links.txt +0 -0
  130. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes.egg-info/entry_points.txt +0 -0
  131. {comtypes-1.4.4 → comtypes-1.4.6}/comtypes.egg-info/top_level.txt +0 -0
  132. {comtypes-1.4.4 → comtypes-1.4.6}/pyproject.toml +0 -0
  133. {comtypes-1.4.4 → comtypes-1.4.6}/setup.py +0 -0
@@ -7,31 +7,24 @@ from ctypes import *
7
7
  from ctypes import _Pointer
8
8
  from _ctypes import CopyComPointer
9
9
  from ctypes.wintypes import DWORD, LONG, UINT, VARIANT_BOOL, WCHAR, WORD
10
- from typing import (
11
- Any,
12
- Callable,
13
- ClassVar,
14
- List,
15
- Optional,
16
- TYPE_CHECKING,
17
- Tuple,
18
- Union as _UnionT,
19
- )
20
-
21
- from comtypes import BSTR, COMError, COMMETHOD, GUID, IID, IUnknown, STDMETHOD
10
+ from typing import Any, ClassVar, Dict, List, Optional, TYPE_CHECKING, Type
11
+
12
+ from comtypes import _CData, BSTR, COMError, COMMETHOD, GUID, IID, IUnknown, STDMETHOD
22
13
  from comtypes.hresult import *
14
+ from comtypes._memberspec import _DispMemberSpec
23
15
  import comtypes.patcher
24
16
  import comtypes
25
17
 
26
18
  if TYPE_CHECKING:
27
19
  from comtypes import hints # type: ignore
28
-
29
- try:
30
20
  from comtypes import _safearray
31
- except (ImportError, AttributeError):
21
+ else:
22
+ try:
23
+ from comtypes import _safearray
24
+ except (ImportError, AttributeError):
32
25
 
33
- class _safearray(object):
34
- tagSAFEARRAY = None
26
+ class _safearray(object):
27
+ tagSAFEARRAY = None
35
28
 
36
29
 
37
30
  LCID = DWORD
@@ -404,6 +397,11 @@ class tagVARIANT(Structure):
404
397
  ri.AddRef()
405
398
  self._.pRecInfo = ri
406
399
  self._.pvRecord = cast(value, c_void_p)
400
+ elif isinstance(ref, _Pointer) and isinstance(
401
+ ref.contents, _safearray.tagSAFEARRAY
402
+ ):
403
+ self.vt = VT_ARRAY | ref._vartype_ | VT_BYREF
404
+ self._.pparray = cast(value, POINTER(POINTER(_safearray.tagSAFEARRAY)))
407
405
  else:
408
406
  self.vt = _ctype_to_vartype[type(ref)] | VT_BYREF
409
407
  elif isinstance(value, _Pointer):
@@ -421,6 +419,15 @@ class tagVARIANT(Structure):
421
419
  ri.AddRef()
422
420
  self._.pRecInfo = ri
423
421
  self._.pvRecord = cast(value, c_void_p)
422
+ elif isinstance(ref, _safearray.tagSAFEARRAY):
423
+ obj = _midlSAFEARRAY(value._itemtype_).create(value.unpack())
424
+ memmove(byref(self._), byref(obj), sizeof(obj))
425
+ self.vt = VT_ARRAY | obj._vartype_
426
+ elif isinstance(ref, _Pointer) and isinstance(
427
+ ref.contents, _safearray.tagSAFEARRAY
428
+ ):
429
+ self.vt = VT_ARRAY | ref._vartype_ | VT_BYREF
430
+ self._.pparray = cast(value, POINTER(POINTER(_safearray.tagSAFEARRAY)))
424
431
  else:
425
432
  self.vt = _ctype_to_vartype[type(ref)] | VT_BYREF
426
433
  else:
@@ -633,7 +640,7 @@ class _(object):
633
640
  def __setitem__(self, index, value):
634
641
  # This is to support the same sematics as a pointer instance:
635
642
  # variant[0] = value
636
- self[index].value = value
643
+ self[index].value = value # type: ignore
637
644
 
638
645
 
639
646
  ################################################################
@@ -773,28 +780,8 @@ DISPID_DESTRUCTOR = -7
773
780
  DISPID_COLLECT = -8
774
781
 
775
782
 
776
- RawGetIDsOfNamesFunc = Callable[
777
- [_byref_type, "Array[c_wchar_p]", int, int, "Array[DISPID]"], int
778
- ]
779
- # fmt: off
780
- RawInvokeFunc = Callable[
781
- [
782
- int, _byref_type, int, int, # dispIdMember, riid, lcid, wFlags
783
- _UnionT[_byref_type, DISPPARAMS], # *pDispParams
784
- _UnionT[_byref_type, VARIANT], # pVarResult
785
- _UnionT[_byref_type, EXCEPINFO, None], # pExcepInfo
786
- _UnionT[_byref_type, c_uint], # puArgErr
787
- ],
788
- int,
789
- ]
790
- # fmt: on
791
-
792
-
793
783
  class IDispatch(IUnknown):
794
- _disp_methods_: ClassVar[List[comtypes._DispMemberSpec]]
795
- _GetTypeInfo: Callable[[int, int], IUnknown]
796
- __com_GetIDsOfNames: RawGetIDsOfNamesFunc
797
- __com_Invoke: RawInvokeFunc
784
+ _disp_methods_: ClassVar[List[_DispMemberSpec]]
798
785
 
799
786
  _iid_ = GUID("{00020400-0000-0000-C000-000000000046}")
800
787
  _methods_ = [
@@ -835,7 +822,7 @@ class IDispatch(IUnknown):
835
822
  """Return type information. Index 0 specifies typeinfo for IDispatch"""
836
823
  import comtypes.typeinfo
837
824
 
838
- result = self._GetTypeInfo(index, lcid)
825
+ result = self._GetTypeInfo(index, lcid) # type: ignore
839
826
  return result.QueryInterface(comtypes.typeinfo.ITypeInfo)
840
827
 
841
828
  def GetIDsOfNames(self, *names: str, **kw: Any) -> List[int]:
@@ -844,7 +831,7 @@ class IDispatch(IUnknown):
844
831
  assert not kw
845
832
  arr = (c_wchar_p * len(names))(*names)
846
833
  ids = (DISPID * len(names))()
847
- self.__com_GetIDsOfNames(riid_null, arr, len(names), lcid, ids)
834
+ self.__com_GetIDsOfNames(riid_null, arr, len(names), lcid, ids) # type: ignore
848
835
  return ids[:]
849
836
 
850
837
  def _invoke(self, memid: int, invkind: int, lcid: int, *args: Any) -> Any:
@@ -864,7 +851,9 @@ class IDispatch(IUnknown):
864
851
  dp.rgdispidNamedArgs = pointer(DISPID(DISPID_PROPERTYPUT))
865
852
  dp.rgvarg = array
866
853
 
867
- self.__com_Invoke(memid, riid_null, lcid, invkind, dp, var, None, argerr)
854
+ self.__com_Invoke( # type: ignore
855
+ memid, riid_null, lcid, invkind, dp, var, None, argerr
856
+ )
868
857
  return var._get_value(dynamic=True)
869
858
 
870
859
  def __make_dp(self, _invkind: int, *args: Any) -> DISPPARAMS:
@@ -900,7 +889,7 @@ class IDispatch(IUnknown):
900
889
  excepinfo = EXCEPINFO()
901
890
  argerr = c_uint()
902
891
  try:
903
- self.__com_Invoke(
892
+ self.__com_Invoke( # type: ignore
904
893
  dispid,
905
894
  riid_null,
906
895
  _lcid,
@@ -964,7 +953,7 @@ _arraycode_to_vartype = {
964
953
  "B": VT_UI1,
965
954
  }
966
955
 
967
- _ctype_to_vartype = {
956
+ _ctype_to_vartype: Dict[Type[_CData], int] = {
968
957
  c_byte: VT_I1,
969
958
  c_ubyte: VT_UI1,
970
959
  c_short: VT_I2,
@@ -1000,7 +989,7 @@ _ctype_to_vartype = {
1000
989
  # POINTER(IDispatch): VT_DISPATCH,
1001
990
  }
1002
991
 
1003
- _vartype_to_ctype = {}
992
+ _vartype_to_ctype: Dict[int, Type[_CData]] = {}
1004
993
  for c, v in _ctype_to_vartype.items():
1005
994
  _vartype_to_ctype[v] = c
1006
995
  _vartype_to_ctype[VT_INT] = _vartype_to_ctype[VT_I4]
@@ -12,15 +12,8 @@ import ctypes
12
12
  import logging
13
13
  import os
14
14
  import sys
15
- from typing import (
16
- Any,
17
- Optional,
18
- overload,
19
- Type,
20
- TYPE_CHECKING,
21
- TypeVar,
22
- Union as _UnionT,
23
- )
15
+ from typing import Any, overload, TypeVar, TYPE_CHECKING
16
+ from typing import Optional, Type, Union as _UnionT
24
17
 
25
18
  import comtypes
26
19
  from comtypes.hresult import *
@@ -34,10 +34,10 @@ def _find_gen_dir():
34
34
  appended to comtypes.gen.__path__ .
35
35
 
36
36
  For a Python script using comtypes, the additional directory is
37
- '%APPDATA%\<username>\Python\Python25\comtypes_cache'.
37
+ '%APPDATA%\\<username>\\Python\\Python25\\comtypes_cache'.
38
38
 
39
39
  For an executable frozen with py2exe, the additional directory is
40
- '%TEMP%\comtypes_cache\<imagebasename>-25'.
40
+ '%TEMP%\\comtypes_cache\\<imagebasename>-25'.
41
41
  """
42
42
  _create_comtypes_gen_package()
43
43
  from comtypes import gen
@@ -262,7 +262,7 @@ def _get_known_namespaces() -> Tuple[
262
262
  Note:
263
263
  The interfaces that should be included in `__known_symbols__` should be limited
264
264
  to those that can be said to be bound to the design concept of COM, such as
265
- `IUnknown`, and those defined in `objidl` and `oaidl`.
265
+ `IUnknown`, `IDispatch` and `ITypeInfo`.
266
266
  `comtypes` does NOT aim to statically define all COM object interfaces in
267
267
  its repository.
268
268
  """
@@ -272,6 +272,7 @@ def _get_known_namespaces() -> Tuple[
272
272
  "comtypes.persist",
273
273
  "comtypes.typeinfo",
274
274
  "comtypes.automation",
275
+ "comtypes.stream",
275
276
  "comtypes",
276
277
  "ctypes.wintypes",
277
278
  "ctypes",
@@ -1,21 +1,12 @@
1
1
  # This stub contains...
2
2
  # - symbols those what might occur recursive imports in runtime.
3
3
  # - utilities for type hints.
4
+ import ctypes
4
5
  import sys
5
- from typing import (
6
- Any,
7
- Callable,
8
- Generic,
9
- Iterator,
10
- List,
11
- NoReturn,
12
- Tuple,
13
- Type,
14
- TypeVar,
15
- Optional,
16
- overload,
17
- Union as _UnionT,
18
- )
6
+ from typing import Any as Any, ClassVar, Generic, NoReturn, TypeVar, overload
7
+ from typing import Optional, Union as _UnionT
8
+ from typing import List, Tuple as Tuple, Type
9
+ from typing import Callable, Iterator, Sequence
19
10
 
20
11
  if sys.version_info >= (3, 8):
21
12
  from typing import Protocol
@@ -32,14 +23,16 @@ else:
32
23
  from typing_extensions import Concatenate, ParamSpec, TypeAlias
33
24
  from typing_extensions import TypeGuard as TypeGuard
34
25
  if sys.version_info >= (3, 11):
35
- from typing import Self
26
+ from typing import Self as Self
36
27
  else:
37
- from typing_extensions import Self
28
+ from typing_extensions import Self as Self
38
29
 
39
30
  import comtypes
31
+ from comtypes import IUnknown as IUnknown, GUID as GUID
40
32
  from comtypes.automation import IDispatch as IDispatch, VARIANT as VARIANT
41
33
  from comtypes.server import IClassFactory as IClassFactory
42
34
  from comtypes.typeinfo import ITypeInfo as ITypeInfo
35
+ from comtypes._safearray import tagSAFEARRAY as tagSAFEARRAY
43
36
 
44
37
  Incomplete: TypeAlias = Any
45
38
  """The type symbol is used temporarily until the COM library parsers or
@@ -51,6 +44,35 @@ Hresult: TypeAlias = int
51
44
  arguments and with `HRESULT` as its return type in its COM method definition.
52
45
  """
53
46
 
47
+ _CT = TypeVar("_CT", bound=ctypes._CData)
48
+ _T_IUnknown = TypeVar("_T_IUnknown", bound=IUnknown)
49
+ _T_Struct = TypeVar("_T_Struct", bound=ctypes.Structure)
50
+
51
+ class LP_SAFEARRAY(ctypes._Pointer[tagSAFEARRAY], Generic[_CT]):
52
+ contents: tagSAFEARRAY
53
+ _itemtype_: ClassVar[_CT] # type: ignore
54
+ _vartype_: ClassVar[int]
55
+ _needsfree: ClassVar[bool]
56
+
57
+ @overload
58
+ @classmethod
59
+ def create(
60
+ cls: Type[LP_SAFEARRAY[ctypes._Pointer[_T_IUnknown]]],
61
+ value: Sequence[_T_IUnknown],
62
+ extra: ctypes._Pointer[GUID] = ...,
63
+ ) -> LP_SAFEARRAY[ctypes._Pointer[_T_IUnknown]]: ...
64
+ @overload
65
+ @classmethod
66
+ def create(cls, value: Sequence[_CT], extra: Any = ...) -> LP_SAFEARRAY[_CT]: ...
67
+ @overload
68
+ def unpack(
69
+ self: LP_SAFEARRAY[ctypes._Pointer[_T_IUnknown]],
70
+ ) -> Sequence[_T_IUnknown]: ...
71
+ @overload
72
+ def unpack(self: LP_SAFEARRAY[_T_Struct]) -> Sequence[_T_Struct]: ...
73
+ @overload
74
+ def unpack(self) -> Sequence[Any]: ...
75
+
54
76
  _T_coclass = TypeVar("_T_coclass", bound=comtypes.CoClass)
55
77
 
56
78
  class FirstComItfOf(Generic[_T_coclass]):
@@ -1,10 +1,17 @@
1
1
  import threading
2
2
  import array
3
+ from typing import TYPE_CHECKING
3
4
  import comtypes
4
5
  from ctypes import POINTER, Structure, byref, cast, c_long, memmove, pointer, sizeof
5
6
  from comtypes import _safearray, IUnknown, com_interface_registry
6
7
  from comtypes.patcher import Patch
7
8
 
9
+ if TYPE_CHECKING:
10
+ from typing import Type, TypeVar
11
+ from comtypes import hints # type: ignore
12
+
13
+ _CT = TypeVar("_CT", bound=comtypes._CData)
14
+
8
15
  _safearray_type_cache = {}
9
16
 
10
17
 
@@ -49,18 +56,18 @@ safearray_as_ndarray = _SafeArrayAsNdArrayContextManager()
49
56
 
50
57
  ################################################################
51
58
  # This is THE PUBLIC function: the gateway to the SAFEARRAY functionality.
52
- def _midlSAFEARRAY(itemtype):
59
+ def _midlSAFEARRAY(itemtype: "Type[_CT]") -> "Type[hints.LP_SAFEARRAY[_CT]]":
53
60
  """This function mimics the 'SAFEARRAY(aType)' IDL idiom. It
54
61
  returns a subtype of SAFEARRAY, instances will be built with a
55
62
  typecode VT_... corresponding to the aType, which must be one of
56
63
  the supported ctypes.
57
64
  """
58
65
  try:
59
- return POINTER(_safearray_type_cache[itemtype])
66
+ return POINTER(_safearray_type_cache[itemtype]) # type: ignore
60
67
  except KeyError:
61
68
  sa_type = _make_safearray_type(itemtype)
62
69
  _safearray_type_cache[itemtype] = sa_type
63
- return POINTER(sa_type)
70
+ return POINTER(sa_type) # type: ignore
64
71
 
65
72
 
66
73
  def _make_safearray_type(itemtype):
@@ -109,7 +116,7 @@ def _make_safearray_type(itemtype):
109
116
  _needsfree = False
110
117
 
111
118
  @classmethod
112
- def create(cls, value, extra=None):
119
+ def create(cls, value, extra=extra):
113
120
  """Create a POINTER(SAFEARRAY_...) instance of the correct
114
121
  type; value is an object containing the items to store.
115
122
 
@@ -0,0 +1,65 @@
1
+ from ctypes import Array, c_ubyte, c_ulong, HRESULT, POINTER, pointer
2
+ from typing import Tuple, TYPE_CHECKING
3
+
4
+ from comtypes import COMMETHOD, GUID, IUnknown
5
+
6
+
7
+ class ISequentialStream(IUnknown):
8
+ """Defines methods for the stream objects in sequence."""
9
+
10
+ _iid_ = GUID("{0C733A30-2A1C-11CE-ADE5-00AA0044773D}")
11
+ _idlflags_ = []
12
+
13
+ _methods_ = [
14
+ # Note that these functions are called `Read` and `Write` in Microsoft's documentation,
15
+ # see https://learn.microsoft.com/en-us/windows/win32/api/objidl/nn-objidl-isequentialstream.
16
+ # However, the comtypes code generation detects these as `RemoteRead` and `RemoteWrite`
17
+ # for very subtle reasons, see e.g. https://stackoverflow.com/q/19820999/. We will not
18
+ # rename these in this manual import for the sake of consistency.
19
+ COMMETHOD(
20
+ [],
21
+ HRESULT,
22
+ "RemoteRead",
23
+ # This call only works if `pv` is pre-allocated with `cb` bytes,
24
+ # which cannot be done by the high level function generated by metaclasses.
25
+ # Therefore, we override the high level function to implement this behaviour
26
+ # and then delegate the call the raw COM method.
27
+ (["out"], POINTER(c_ubyte), "pv"),
28
+ (["in"], c_ulong, "cb"),
29
+ (["out"], POINTER(c_ulong), "pcbRead"),
30
+ ),
31
+ COMMETHOD(
32
+ [],
33
+ HRESULT,
34
+ "RemoteWrite",
35
+ (["in"], POINTER(c_ubyte), "pv"),
36
+ (["in"], c_ulong, "cb"),
37
+ (["out"], POINTER(c_ulong), "pcbWritten"),
38
+ ),
39
+ ]
40
+
41
+ def RemoteRead(self, cb: int) -> Tuple["Array[c_ubyte]", int]:
42
+ """Reads a specified number of bytes from the stream object into memory
43
+ starting at the current seek pointer.
44
+ """
45
+ # Behaves as if `pv` is pre-allocated with `cb` bytes by the high level func.
46
+ pv = (c_ubyte * cb)()
47
+ pcb_read = pointer(c_ulong(0))
48
+ self.__com_RemoteRead(pv, c_ulong(cb), pcb_read) # type: ignore
49
+ # return both `out` parameters
50
+ return pv, pcb_read.contents.value
51
+
52
+ if TYPE_CHECKING:
53
+
54
+ def RemoteWrite(self, pv: "Array[c_ubyte]", cb: int) -> int:
55
+ """Writes a specified number of bytes into the stream object starting at
56
+ the current seek pointer.
57
+ """
58
+ ...
59
+
60
+
61
+ # fmt: off
62
+ __known_symbols__ = [
63
+ 'ISequentialStream',
64
+ ]
65
+ # fmt: on
@@ -71,6 +71,12 @@ class Test_GetModule(ut.TestCase):
71
71
  # the `_Pointer` interface, rather than importing `_Pointer` from `ctypes`.
72
72
  self.assertTrue(issubclass(mod._Pointer, comtypes.IUnknown))
73
73
 
74
+ def test_portabledeviceapi(self):
75
+ mod = comtypes.client.GetModule("portabledeviceapi.dll")
76
+ from comtypes.stream import ISequentialStream
77
+
78
+ self.assertTrue(issubclass(mod.IStream, ISequentialStream))
79
+
74
80
  def test_no_replacing_Patch_namespace(self):
75
81
  # NOTE: An object named `Patch` is defined in some dll.
76
82
  # Depending on how the namespace is defined in the static module,
@@ -117,6 +123,11 @@ class Test_KnownSymbols(ut.TestCase):
117
123
 
118
124
  self._doit(comtypes)
119
125
 
126
+ def test_symbols_in_comtypes_stream(self):
127
+ import comtypes.stream
128
+
129
+ self._doit(comtypes.stream)
130
+
120
131
  def test_symbols_in_comtypes_automation(self):
121
132
  import comtypes.automation
122
133
 
@@ -26,7 +26,7 @@ class Test_DispMethods(unittest.TestCase):
26
26
  def _create_dispifc(self) -> "ComtypesCppTestSrvLib.IDispRecordParamTest":
27
27
  # Explicitely ask for the dispinterface of the component.
28
28
  return CreateObject(
29
- "Comtypes.DispIfcParamTests",
29
+ "Comtypes.DispRecordParamTest",
30
30
  clsctx=CLSCTX_LOCAL_SERVER,
31
31
  interface=ComtypesCppTestSrvLib.IDispRecordParamTest,
32
32
  )
@@ -0,0 +1,89 @@
1
+ # coding: utf-8
2
+
3
+ from ctypes import byref, c_double, pointer
4
+ import unittest
5
+
6
+ import comtypes
7
+ import comtypes.safearray
8
+ from comtypes import CLSCTX_LOCAL_SERVER
9
+ from comtypes.client import CreateObject, GetModule
10
+
11
+ ComtypesCppTestSrvLib_GUID = "{07D2AEE5-1DF8-4D2C-953A-554ADFD25F99}"
12
+
13
+ try:
14
+ GetModule((ComtypesCppTestSrvLib_GUID, 1, 0, 0))
15
+ import comtypes.gen.ComtypesCppTestSrvLib as ComtypesCppTestSrvLib
16
+
17
+ IMPORT_FAILED = False
18
+ except (ImportError, OSError):
19
+ IMPORT_FAILED = True
20
+
21
+
22
+ @unittest.skipIf(IMPORT_FAILED, "This depends on the out of process COM-server.")
23
+ class Test_DispMethods(unittest.TestCase):
24
+ """Test dispmethods with safearray and safearray pointer parameters."""
25
+
26
+ UNPACKED_ZERO_VALS = tuple(0.0 for _ in range(10))
27
+ UNPACKED_CONSECUTIVE_VALS = tuple(float(i) for i in range(10))
28
+
29
+ def _create_dispifc(self) -> "ComtypesCppTestSrvLib.IDispSafearrayParamTest":
30
+ # Explicitely ask for the dispinterface of the component.
31
+ return CreateObject(
32
+ "Comtypes.DispSafearrayParamTest",
33
+ clsctx=CLSCTX_LOCAL_SERVER,
34
+ interface=ComtypesCppTestSrvLib.IDispSafearrayParamTest,
35
+ )
36
+
37
+ def _create_zero_array(self):
38
+ return comtypes.safearray._midlSAFEARRAY(c_double).create(
39
+ [c_double() for _ in range(10)]
40
+ )
41
+
42
+ def _create_consecutive_array(self):
43
+ return comtypes.safearray._midlSAFEARRAY(c_double).create(
44
+ [c_double(i) for i in range(10)]
45
+ )
46
+
47
+ def test_inout_byref(self):
48
+ dispifc = self._create_dispifc()
49
+ # Passing a safearray by reference to a method that has declared the parameter
50
+ # as [in, out] we expect modifications of the safearray on the server side to
51
+ # also change the safearray on the client side.
52
+ test_array = self._create_zero_array()
53
+ self.assertEqual(test_array.unpack(), self.UNPACKED_ZERO_VALS)
54
+ dispifc.InitArray(byref(test_array))
55
+ self.assertEqual(test_array.unpack(), self.UNPACKED_CONSECUTIVE_VALS)
56
+
57
+ def test_inout_pointer(self):
58
+ dispifc = self._create_dispifc()
59
+ # Passing a safearray pointer to a method that has declared the parameter
60
+ # as [in, out] we expect modifications of the safearray on the server side to
61
+ # also change the safearray on the client side.
62
+ test_array = self._create_zero_array()
63
+ self.assertEqual(test_array.unpack(), self.UNPACKED_ZERO_VALS)
64
+ dispifc.InitArray(pointer(test_array))
65
+ self.assertEqual(test_array.unpack(), self.UNPACKED_CONSECUTIVE_VALS)
66
+
67
+ def test_in_safearray(self):
68
+ # Passing a safearray to a method that has declared the parameter just as [in]
69
+ # we expect modifications of the safearray on the server side NOT to change
70
+ # the safearray on the client side.
71
+ # We also need to test if the safearray gets properly passed to the method on
72
+ # the server side. For this, the 'VerifyArray' method returns 'True' if
73
+ # the safearray items have values equal to the initialization values
74
+ # provided by 'InitArray'.
75
+ for sa, expected, unpacked_content in [
76
+ (self._create_consecutive_array(), True, self.UNPACKED_CONSECUTIVE_VALS),
77
+ # Also perform the inverted test. For this, create a safearray with zeros.
78
+ (self._create_zero_array(), False, self.UNPACKED_ZERO_VALS),
79
+ ]:
80
+ with self.subTest(expected=expected, unpacked_content=unpacked_content):
81
+ # Perform the check on initialization values.
82
+ self.assertEqual(self._create_dispifc().VerifyArray(sa), expected)
83
+ # Check if the safearray is unchanged although the method
84
+ # modifies the safearray on the server side.
85
+ self.assertEqual(sa.unpack(), unpacked_content)
86
+
87
+
88
+ if __name__ == "__main__":
89
+ unittest.main()
@@ -0,0 +1,53 @@
1
+ import unittest as ut
2
+
3
+ from ctypes import POINTER, byref, c_bool, c_ubyte
4
+ import comtypes
5
+ import comtypes.client
6
+
7
+ comtypes.client.GetModule("portabledeviceapi.dll")
8
+ from comtypes.gen.PortableDeviceApiLib import IStream
9
+
10
+
11
+ def _create_stream() -> IStream:
12
+ # Create an IStream
13
+ stream = POINTER(IStream)() # type: ignore
14
+ comtypes._ole32.CreateStreamOnHGlobal(None, c_bool(True), byref(stream))
15
+ return stream # type: ignore
16
+
17
+
18
+ class Test_RemoteWrite(ut.TestCase):
19
+ def test_RemoteWrite(self):
20
+ stream = _create_stream()
21
+ test_data = "Some data".encode("utf-8")
22
+ pv = (c_ubyte * len(test_data)).from_buffer(bytearray(test_data))
23
+
24
+ written = stream.RemoteWrite(pv, len(test_data))
25
+
26
+ # Verification
27
+ self.assertEqual(written, len(test_data))
28
+
29
+
30
+ class Test_RemoteRead(ut.TestCase):
31
+ def test_RemoteRead(self):
32
+ stream = _create_stream()
33
+ test_data = "Some data".encode("utf-8")
34
+ pv = (c_ubyte * len(test_data)).from_buffer(bytearray(test_data))
35
+ stream.RemoteWrite(pv, len(test_data))
36
+
37
+ # Make sure the data actually gets written before trying to read back
38
+ stream.Commit(0)
39
+ # Move the stream back to the beginning
40
+ STREAM_SEEK_SET = 0
41
+ stream.RemoteSeek(0, STREAM_SEEK_SET)
42
+
43
+ buffer_size = 1024
44
+
45
+ read_buffer, data_read = stream.RemoteRead(buffer_size)
46
+
47
+ # Verification
48
+ self.assertEqual(data_read, len(test_data))
49
+ self.assertEqual(bytearray(read_buffer)[0:data_read], test_data)
50
+
51
+
52
+ if __name__ == "__main__":
53
+ ut.main()
@@ -0,0 +1,100 @@
1
+ # coding: utf-8
2
+
3
+ from ctypes import c_int, pointer, POINTER
4
+ import unittest
5
+
6
+ import comtypes
7
+ import comtypes.safearray
8
+ from comtypes import CLSCTX_INPROC_SERVER, CLSCTX_LOCAL_SERVER
9
+ from comtypes.client import CreateObject, GetModule
10
+ import comtypes.typeinfo
11
+
12
+ GetModule("UIAutomationCore.dll")
13
+ from comtypes.gen.UIAutomationClient import CUIAutomation, IUIAutomation
14
+
15
+ ComtypesCppTestSrvLib_GUID = "{07D2AEE5-1DF8-4D2C-953A-554ADFD25F99}"
16
+
17
+ try:
18
+ GetModule((ComtypesCppTestSrvLib_GUID, 1, 0, 0))
19
+ from comtypes.gen.ComtypesCppTestSrvLib import StructRecordParamTest
20
+ from comtypes.gen.ComtypesCppTestSrvLib import IDispSafearrayParamTest
21
+
22
+ IMPORT_FAILED = False
23
+ except (ImportError, OSError):
24
+ IMPORT_FAILED = True
25
+
26
+
27
+ class Test_midlSAFEARRAY_create(unittest.TestCase):
28
+ def test_iunk(self):
29
+ extra = pointer(IUIAutomation._iid_)
30
+ iuia = CreateObject(
31
+ CUIAutomation().IPersist_GetClassID(),
32
+ interface=IUIAutomation,
33
+ clsctx=CLSCTX_INPROC_SERVER,
34
+ )
35
+ sa_type = comtypes.safearray._midlSAFEARRAY(POINTER(IUIAutomation))
36
+ for ptn, sa in [
37
+ ("with extra", sa_type.create([iuia], extra=extra)),
38
+ ("without extra", sa_type.create([iuia])),
39
+ ]:
40
+ with self.subTest(ptn=ptn):
41
+ (unpacked,) = sa.unpack()
42
+ self.assertIsInstance(unpacked, POINTER(IUIAutomation))
43
+
44
+ @unittest.skipIf(IMPORT_FAILED, "This depends on the out of process COM-server.")
45
+ def test_idisp(self):
46
+ extra = pointer(IDispSafearrayParamTest._iid_)
47
+ idisp = CreateObject(
48
+ "Comtypes.DispSafearrayParamTest",
49
+ clsctx=CLSCTX_LOCAL_SERVER,
50
+ interface=IDispSafearrayParamTest,
51
+ )
52
+ sa_type = comtypes.safearray._midlSAFEARRAY(POINTER(IDispSafearrayParamTest))
53
+ for ptn, sa in [
54
+ ("with extra", sa_type.create([idisp], extra=extra)),
55
+ ("without extra", sa_type.create([idisp])),
56
+ ]:
57
+ with self.subTest(ptn=ptn):
58
+ (unpacked,) = sa.unpack()
59
+ self.assertIsInstance(unpacked, POINTER(IDispSafearrayParamTest))
60
+
61
+ @unittest.skipIf(IMPORT_FAILED, "This depends on the out of process COM-server.")
62
+ def test_record(self):
63
+ extra = comtypes.typeinfo.GetRecordInfoFromGuids(
64
+ *StructRecordParamTest._recordinfo_
65
+ )
66
+ record = StructRecordParamTest()
67
+ record.question = "The meaning of life, the universe and everything?"
68
+ record.answer = 42
69
+ record.needs_clarification = True
70
+ sa_type = comtypes.safearray._midlSAFEARRAY(StructRecordParamTest)
71
+ for ptn, sa in [
72
+ ("with extra", sa_type.create([record], extra=extra)),
73
+ ("without extra", sa_type.create([record])),
74
+ ]:
75
+ with self.subTest(ptn=ptn):
76
+ (unpacked,) = sa.unpack()
77
+ self.assertIsInstance(unpacked, StructRecordParamTest)
78
+ self.assertEqual(
79
+ unpacked.question,
80
+ "The meaning of life, the universe and everything?",
81
+ )
82
+ self.assertEqual(unpacked.answer, 42)
83
+ self.assertEqual(unpacked.needs_clarification, True)
84
+
85
+ def test_ctype(self):
86
+ extra = None
87
+ cdata = c_int(1)
88
+ sa_type = comtypes.safearray._midlSAFEARRAY(c_int)
89
+ for ptn, sa in [
90
+ ("with extra", sa_type.create([cdata], extra=extra)),
91
+ ("without extra", sa_type.create([cdata])),
92
+ ]:
93
+ with self.subTest(ptn=ptn):
94
+ (unpacked,) = sa.unpack()
95
+ self.assertIsInstance(unpacked, int)
96
+ self.assertEqual(unpacked, 1)
97
+
98
+
99
+ if __name__ == "__main__":
100
+ unittest.main()