comtypes 1.4.10__zip → 1.4.12__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 (151) hide show
  1. {comtypes-1.4.10 → comtypes-1.4.12}/CHANGES.txt +48 -0
  2. {comtypes-1.4.10/comtypes.egg-info → comtypes-1.4.12}/PKG-INFO +4 -3
  3. {comtypes-1.4.10 → comtypes-1.4.12}/README.md +1 -1
  4. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/__init__.py +11 -5
  5. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/_comobject.py +29 -31
  6. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/_memberspec.py +107 -81
  7. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/_meta.py +1 -1
  8. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/_npsupport.py +12 -17
  9. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/_post_coinit/_cominterface_meta_patcher.py +8 -10
  10. comtypes-1.4.12/comtypes/_post_coinit/activeobj.py +61 -0
  11. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/_post_coinit/misc.py +1 -23
  12. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/_post_coinit/unknwn.py +33 -26
  13. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/_vtbl.py +55 -58
  14. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/automation.py +19 -23
  15. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/client/__init__.py +2 -1
  16. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/client/_activeobj.py +8 -0
  17. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/client/_code_cache.py +10 -24
  18. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/client/_constants.py +1 -1
  19. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/client/_events.py +92 -54
  20. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/client/_generate.py +1 -3
  21. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/client/dynamic.py +3 -3
  22. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/client/lazybind.py +3 -3
  23. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/connectionpoints.py +37 -3
  24. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/errorinfo.py +54 -16
  25. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/hints.pyi +15 -2
  26. comtypes-1.4.12/comtypes/hresult.py +159 -0
  27. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/messageloop.py +15 -13
  28. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/patcher.py +2 -2
  29. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/persist.py +9 -2
  30. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/safearray.py +10 -10
  31. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/server/__init__.py +5 -37
  32. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/server/automation.py +2 -2
  33. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/server/connectionpoints.py +71 -70
  34. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/server/inprocserver.py +10 -7
  35. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/server/localserver.py +16 -22
  36. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/server/register.py +7 -7
  37. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/test_GUID.py +6 -7
  38. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/test_agilent.py +1 -1
  39. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/test_basic.py +6 -3
  40. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/test_client_dynamic.py +1 -1
  41. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/test_collections.py +6 -3
  42. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/test_comobject.py +19 -6
  43. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/test_comserver.py +32 -4
  44. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/test_createwrappers.py +1 -1
  45. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/test_dict.py +2 -1
  46. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/test_dispifc_records.py +0 -2
  47. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/test_dispifc_safearrays.py +0 -2
  48. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/test_dispinterface.py +1 -1
  49. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/test_dyndispatch.py +4 -2
  50. comtypes-1.4.12/comtypes/test/test_errorinfo.py +115 -0
  51. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/test_excel.py +1 -3
  52. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/test_getactiveobj.py +19 -2
  53. comtypes-1.4.12/comtypes/test/test_hresult.py +87 -0
  54. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/test_inout_args.py +9 -2
  55. comtypes-1.4.12/comtypes/test/test_messageloop.py +117 -0
  56. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/test_midl_safearray_create.py +0 -2
  57. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/test_msscript.py +1 -1
  58. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/test_npsupport.py +22 -11
  59. comtypes-1.4.12/comtypes/test/test_persist.py +71 -0
  60. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/test_recordinfo.py +0 -2
  61. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/test_safearray.py +2 -1
  62. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/test_server.py +6 -6
  63. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/test_server_register.py +2 -1
  64. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/test_storage.py +1 -1
  65. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/test_stream.py +22 -2
  66. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/test_typeinfo.py +19 -2
  67. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/test_urlhistory.py +1 -1
  68. comtypes-1.4.12/comtypes/test/test_util.py +227 -0
  69. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/test_variant.py +43 -25
  70. comtypes-1.4.12/comtypes/test/test_viewobject.py +78 -0
  71. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/test_w_getopt.py +4 -4
  72. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/test_word.py +1 -1
  73. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/tools/codegenerator/codegenerator.py +1 -1
  74. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/tools/codegenerator/comments.py +1 -1
  75. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/tools/codegenerator/heads.py +5 -5
  76. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/tools/codegenerator/helpers.py +7 -7
  77. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/tools/codegenerator/namespaces.py +3 -3
  78. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/tools/codegenerator/typeannotator.py +2 -2
  79. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/tools/tlbparser.py +8 -7
  80. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/tools/typedesc.py +14 -14
  81. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/tools/typedesc_base.py +19 -19
  82. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/typeinfo.py +14 -9
  83. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/util.py +38 -6
  84. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/viewobject.py +29 -5
  85. {comtypes-1.4.10 → comtypes-1.4.12/comtypes.egg-info}/PKG-INFO +4 -3
  86. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes.egg-info/SOURCES.txt +6 -0
  87. {comtypes-1.4.10 → comtypes-1.4.12}/pyproject.toml +13 -7
  88. comtypes-1.4.10/comtypes/hresult.py +0 -81
  89. comtypes-1.4.10/comtypes/test/test_persist.py +0 -38
  90. {comtypes-1.4.10 → comtypes-1.4.12}/LICENSE.txt +0 -0
  91. {comtypes-1.4.10 → comtypes-1.4.12}/MANIFEST.in +0 -0
  92. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/GUID.py +0 -0
  93. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/_post_coinit/__init__.py +0 -0
  94. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/_post_coinit/bstr.py +0 -0
  95. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/_post_coinit/instancemethod.py +0 -0
  96. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/_safearray.py +0 -0
  97. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/_tlib_version_checker.py +0 -0
  98. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/clear_cache.py +0 -0
  99. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/client/_create.py +0 -0
  100. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/client/_managing.py +0 -0
  101. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/git.py +0 -0
  102. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/logutil.py +0 -0
  103. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/server/w_getopt.py +0 -0
  104. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/shelllink.py +0 -0
  105. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/stream.py +0 -0
  106. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/TestComServer.idl +0 -0
  107. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/TestComServer.py +0 -0
  108. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/TestComServer.tlb +0 -0
  109. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/TestDispServer.idl +0 -0
  110. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/TestDispServer.py +0 -0
  111. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/TestDispServer.tlb +0 -0
  112. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/__init__.py +0 -0
  113. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/find_memleak.py +0 -0
  114. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/mylib.idl +0 -0
  115. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/mylib.tlb +0 -0
  116. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/mytypelib.idl +0 -0
  117. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/runtests.py +0 -0
  118. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/setup.py +0 -0
  119. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/test_BSTR.py +0 -0
  120. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/test_DISPPARAMS.py +0 -0
  121. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/test_QueryService.py +0 -0
  122. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/test_avmc.py +0 -0
  123. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/test_casesensitivity.py +0 -0
  124. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/test_clear_cache.py +0 -0
  125. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/test_client.py +0 -0
  126. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/test_client_regenerate_modules.py +0 -0
  127. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/test_findgendir.py +0 -0
  128. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/test_ie.py +0 -0
  129. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/test_ienum.py +0 -0
  130. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/test_imfattributes.py +0 -0
  131. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/test_jscript.js +0 -0
  132. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/test_monikers.py +0 -0
  133. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/test_outparam.py +0 -0
  134. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/test_pump_events.py +0 -0
  135. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/test_sapi.py +0 -0
  136. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/test_shelllink.py +0 -0
  137. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/test_showevents.py +0 -0
  138. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/test_subinterface.py +0 -0
  139. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/test_typeannotator.py +0 -0
  140. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/test_win32com_interop.py +0 -0
  141. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/test_wmi.py +0 -0
  142. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/test/urlhist.tlb +0 -0
  143. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/tools/__init__.py +0 -0
  144. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/tools/codegenerator/__init__.py +0 -0
  145. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/tools/codegenerator/modulenamer.py +0 -0
  146. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes/tools/codegenerator/packing.py +0 -0
  147. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes.egg-info/dependency_links.txt +0 -0
  148. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes.egg-info/entry_points.txt +0 -0
  149. {comtypes-1.4.10 → comtypes-1.4.12}/comtypes.egg-info/top_level.txt +0 -0
  150. {comtypes-1.4.10 → comtypes-1.4.12}/setup.cfg +0 -0
  151. {comtypes-1.4.10 → comtypes-1.4.12}/setup.py +0 -0
@@ -0,0 +1,227 @@
1
+ import unittest
2
+ from ctypes import (
3
+ POINTER,
4
+ Structure,
5
+ Union,
6
+ addressof,
7
+ c_byte,
8
+ c_char,
9
+ c_double,
10
+ c_int,
11
+ c_void_p,
12
+ cast,
13
+ sizeof,
14
+ )
15
+
16
+ import comtypes.util
17
+ from comtypes import GUID, CoCreateInstance, IUnknown, shelllink
18
+
19
+
20
+ class ByrefAtTest(unittest.TestCase):
21
+ def test_ctypes(self):
22
+ for ctype, value in [
23
+ (c_int, 42),
24
+ (c_double, 3.14),
25
+ (c_char, b"A"),
26
+ ]:
27
+ with self.subTest(ctype=ctype, value=value):
28
+ obj = ctype(value)
29
+ # Test with zero offset - should point to the same location
30
+ ref = comtypes.util.byref_at(obj, 0)
31
+ ptr = cast(ref, POINTER(ctype))
32
+ # byref objects don't have contents, but we can cast them to pointers
33
+ self.assertEqual(addressof(ptr.contents), addressof(obj))
34
+ self.assertEqual(ptr.contents.value, value)
35
+
36
+ def test_array_offsets(self):
37
+ elms = [10, 20, 30, 40]
38
+ arr = (c_int * 4)(*elms) # Create an array
39
+ # Test accessing different elements via offset
40
+ for i, expected in enumerate(elms):
41
+ with self.subTest(index=i, expected=expected):
42
+ ref = comtypes.util.byref_at(arr, offset=sizeof(c_int) * i)
43
+ ptr = cast(ref, POINTER(c_int))
44
+ self.assertEqual(ptr.contents.value, expected)
45
+
46
+ def test_pointer_arithmetic(self):
47
+ # Test that byref_at behaves like C pointer arithmetic
48
+
49
+ class TestStruct(Structure):
50
+ _fields_ = [
51
+ ("field1", c_int),
52
+ ("field2", c_double),
53
+ ("field3", c_char),
54
+ ]
55
+
56
+ struct = TestStruct(123, 3.14, b"X")
57
+ for fname, ftype, expected in [
58
+ ("field1", c_int, 123),
59
+ ("field2", c_double, 3.14),
60
+ ("field3", c_char, b"X"),
61
+ ]:
62
+ with self.subTest(field=fname, type=ftype, expected=expected):
63
+ offset = getattr(TestStruct, fname).offset
64
+ ref = comtypes.util.byref_at(struct, offset)
65
+ ptr = cast(ref, POINTER(ftype))
66
+ self.assertEqual(ptr.contents.value, expected)
67
+
68
+ def test_com_interface(self):
69
+ CLSID_ShellLink = GUID("{00021401-0000-0000-C000-000000000046}")
70
+ sc = CoCreateInstance(CLSID_ShellLink, interface=shelllink.IShellLinkA)
71
+ ref = comtypes.util.byref_at(sc, 0)
72
+ ptr = cast(ref, POINTER(POINTER(IUnknown)))
73
+ self.assertEqual(addressof(ptr.contents), addressof(sc))
74
+
75
+ def test_large_offset(self):
76
+ # Create a large array to test with large offsets
77
+ arr = (c_int * 100)(*range(100))
78
+ # Test accessing element at index 50 (offset = 50 * sizeof(c_int))
79
+ offset = 50 * sizeof(c_int)
80
+ ref = comtypes.util.byref_at(arr, offset)
81
+ ptr = cast(ref, POINTER(c_int))
82
+ self.assertEqual(ptr.contents.value, 50)
83
+
84
+ def test_memory_safety(self):
85
+ for initial in [111, 222, 333, 444]:
86
+ with self.subTest(initial=initial):
87
+ obj = c_int(initial)
88
+ ref = comtypes.util.byref_at(obj, 0)
89
+ ptr = cast(ref, POINTER(c_int))
90
+ # Verify initial value
91
+ self.assertEqual(ptr.contents.value, initial)
92
+ # Modify original objects and verify references still work
93
+ obj.value = 333
94
+ # Verify reference still works after modification
95
+ self.assertEqual(ptr.contents.value, 333)
96
+
97
+
98
+ class CastFieldTest(unittest.TestCase):
99
+ def test_ctypes(self):
100
+ class TestStruct(Structure):
101
+ _fields_ = [
102
+ ("int_field", c_int),
103
+ ("double_field", c_double),
104
+ ("char_field", c_char),
105
+ ]
106
+
107
+ struct = TestStruct(42, 3.14, b"X")
108
+ for fname, ftype, expected in [
109
+ ("int_field", c_int, 42),
110
+ ("double_field", c_double, 3.14),
111
+ ("char_field", c_char, b"X"),
112
+ ]:
113
+ with self.subTest(fname=fname, ftype=ftype):
114
+ actual = comtypes.util.cast_field(struct, fname, ftype)
115
+ self.assertEqual(actual, expected)
116
+
117
+ def test_type_reinterpretation(self):
118
+ class TestStruct(Structure):
119
+ _fields_ = [
120
+ ("data", c_int),
121
+ ]
122
+
123
+ # Create struct with known bit pattern
124
+ struct = TestStruct(0x41424344) # ASCII "ABCD" in little-endian
125
+ # Cast the int field as a char array to see individual bytes
126
+ char_value = comtypes.util.cast_field(struct, "data", c_char)
127
+ # This should give us the first byte of the int
128
+ self.assertIsInstance(char_value, bytes)
129
+
130
+ def test_pointers(self):
131
+ class TestStruct(Structure):
132
+ _fields_ = [
133
+ ("ptr_field", c_void_p),
134
+ ("int_field", c_int),
135
+ ]
136
+
137
+ target_int = c_int(99)
138
+ struct = TestStruct(addressof(target_int), 123)
139
+ for fname, ftype, expected in [
140
+ ("ptr_field", c_void_p, addressof(target_int)),
141
+ ("int_field", c_int, 123),
142
+ ]:
143
+ with self.subTest(fname=fname, ftype=ftype, expected=expected):
144
+ actual_value = comtypes.util.cast_field(struct, fname, ftype)
145
+ self.assertEqual(actual_value, expected)
146
+
147
+ def test_nested_structures(self):
148
+ class InnerStruct(Structure):
149
+ _fields_ = [
150
+ ("inner_int", c_int),
151
+ ("inner_char", c_char),
152
+ ]
153
+
154
+ class OuterStruct(Structure):
155
+ _fields_ = [
156
+ ("outer_int", c_int),
157
+ ("inner", InnerStruct),
158
+ ]
159
+
160
+ inner = InnerStruct(456, b"Y")
161
+ outer = OuterStruct(789, inner)
162
+ # Cast the nested structure field
163
+ inner_value = comtypes.util.cast_field(outer, "inner", InnerStruct)
164
+ self.assertEqual(inner_value.inner_int, 456)
165
+ self.assertEqual(inner_value.inner_char, b"Y")
166
+ # Cast outer int field
167
+ outer_int = comtypes.util.cast_field(outer, "outer_int", c_int)
168
+ self.assertEqual(outer_int, 789)
169
+
170
+ def test_arrays(self):
171
+ class TestStruct(Structure):
172
+ _fields_ = [
173
+ ("int_array", c_int * 3),
174
+ ("single_int", c_int),
175
+ ]
176
+
177
+ arr = (c_int * 3)(10, 20, 30)
178
+ struct = TestStruct(arr, 40)
179
+ # Cast array field as array type
180
+ array_value = comtypes.util.cast_field(struct, "int_array", c_int * 3)
181
+ self.assertEqual(list(array_value), [10, 20, 30])
182
+ # Cast single int
183
+ int_value = comtypes.util.cast_field(struct, "single_int", c_int)
184
+ self.assertEqual(int_value, 40)
185
+
186
+ def test_union(self):
187
+ class TestUnion(Union):
188
+ _fields_ = [
189
+ ("as_int", c_int),
190
+ ("as_bytes", c_byte * 4),
191
+ ]
192
+
193
+ class TestStruct(Structure):
194
+ _fields_ = [
195
+ ("union_field", TestUnion),
196
+ ("regular_field", c_int),
197
+ ]
198
+
199
+ union_val = TestUnion()
200
+ union_val.as_int = 0x41424344 # "ABCD" in ASCII
201
+ struct = TestStruct(union_val, 999)
202
+ union_result = comtypes.util.cast_field(struct, "union_field", TestUnion)
203
+ self.assertEqual(union_result.as_int, 0x41424344)
204
+ int_result = comtypes.util.cast_field(struct, "regular_field", c_int)
205
+ self.assertEqual(int_result, 999)
206
+
207
+ def test_void_p(self):
208
+ class VTableLikeStruct(Structure):
209
+ _fields_ = [
210
+ ("QueryInterface", c_void_p),
211
+ ("AddRef", c_void_p),
212
+ ("Release", c_void_p),
213
+ ("custom_method", c_void_p),
214
+ ]
215
+
216
+ # Initialize with some dummy pointers
217
+ struct = VTableLikeStruct(0x1000, 0x2000, 0x3000, 0x4000)
218
+ # Test accessing different entries
219
+ for fname, expected in [
220
+ ("QueryInterface", 0x1000),
221
+ ("AddRef", 0x2000),
222
+ ("Release", 0x3000),
223
+ ("custom_method", 0x4000),
224
+ ]:
225
+ with self.subTest(fname=fname, expected=expected):
226
+ ptr_value = comtypes.util.cast_field(struct, fname, c_void_p)
227
+ self.assertEqual(ptr_value, expected)
@@ -66,7 +66,8 @@ class VariantTestCase(unittest.TestCase):
66
66
 
67
67
  missing = VARIANT.missing
68
68
  self.assertEqual(missing.vt, VT_ERROR)
69
- self.assertRaises(NotImplementedError, lambda: missing.value)
69
+ with self.assertRaises(NotImplementedError):
70
+ missing.value
70
71
 
71
72
  def test_com_refcounts(self):
72
73
  # typelib for oleaut32
@@ -114,33 +115,52 @@ class VariantTestCase(unittest.TestCase):
114
115
  self.assertEqual(result, values)
115
116
 
116
117
  def test_pythonobjects(self):
117
- if sys.version_info >= (3, 0):
118
- objects = [None, 42, 3.14, True, False, "abc", "abc", 7]
119
- else:
120
- objects = [None, 42, 3.14, True, False, "abc", "abc", 7]
118
+ objects = [None, 42, 3.14, True, False, "abc", "abc", 7]
121
119
  for x in objects:
122
- v = VARIANT(x)
123
- self.assertEqual(x, v.value)
120
+ with self.subTest(x=x):
121
+ v = VARIANT(x)
122
+ self.assertEqual(x, v.value)
124
123
 
125
124
  def test_integers(self):
126
125
  v = VARIANT()
127
126
 
128
- int_type = int if sys.version_info >= (3, 0) else (int, long)
129
-
130
- if hasattr(sys, "maxint"):
131
- # this test doesn't work in Python 3000
132
- v.value = sys.maxsize
133
- self.assertEqual(v.value, sys.maxsize)
134
- self.assertIsInstance(v.value, int_type)
135
-
136
- v.value += 1
137
- self.assertEqual(v.value, sys.maxsize + 1)
138
- self.assertIsInstance(v.value, int_type)
139
-
140
127
  v.value = 1
141
128
 
142
129
  self.assertEqual(v.value, 1)
143
- self.assertIsInstance(v.value, int_type)
130
+ self.assertIsInstance(v.value, int)
131
+
132
+ def test_vt_uix_range_boundaries(self):
133
+ MIN_VT_I4 = -(2**31)
134
+ MAX_VT_I4 = 2**31 - 1
135
+ MAX_VT_UI4 = 2**32 - 1
136
+ MIN_VT_I8 = -(2**63)
137
+ MAX_VT_I8 = 2**63 - 1
138
+ MAX_VT_UI8 = 2**64 - 1
139
+ for val, vt in [
140
+ (MIN_VT_I8, VT_I8),
141
+ (MIN_VT_I4 - 1, VT_I8),
142
+ (MIN_VT_I4, VT_I4),
143
+ (0, VT_I4),
144
+ (MAX_VT_I4, VT_I4),
145
+ (MAX_VT_I4 + 1, VT_UI4),
146
+ (MAX_VT_UI4, VT_UI4),
147
+ (MAX_VT_UI4 + 1, VT_I8),
148
+ (MAX_VT_I8, VT_I8),
149
+ (MAX_VT_I8 + 1, VT_UI8),
150
+ (MAX_VT_UI8, VT_UI8),
151
+ ]:
152
+ with self.subTest(val=val, vt=vt):
153
+ v = VARIANT()
154
+ v.value = val
155
+ self.assertEqual(v.value, val)
156
+ self.assertEqual(v.vt, vt)
157
+
158
+ def test_out_of_vt_uix_range(self):
159
+ MIN_VT_I8 = -(2**63)
160
+ MAX_VT_UI8 = 2**64 - 1
161
+ for val in [MIN_VT_I8 - 1, MAX_VT_UI8 + 1]:
162
+ with self.subTest(val=val), self.assertRaises(TypeError):
163
+ VARIANT().value = val
144
164
 
145
165
  def test_datetime(self):
146
166
  now = datetime.datetime.now()
@@ -303,13 +323,11 @@ def check_perf(rep=20000):
303
323
  by_var = byref(variable)
304
324
  ptr_var = pointer(variable)
305
325
 
306
- if sys.version_info >= (3, 0):
307
- import pickle
308
- else:
309
- import cPickle as pickle
326
+ import pickle
327
+
310
328
  try:
311
329
  previous = pickle.load(open("result.pickle", "rb"))
312
- except IOError:
330
+ except OSError:
313
331
  previous = {}
314
332
 
315
333
  results = {}
@@ -0,0 +1,78 @@
1
+ import contextlib
2
+ import unittest
3
+ from ctypes.wintypes import POINT, RECT, SIZEL
4
+
5
+ import comtypes.client
6
+ from comtypes import IUnknown
7
+ from comtypes.viewobject import (
8
+ DVASPECT_CONTENT,
9
+ IAdviseSink,
10
+ IViewObject,
11
+ IViewObject2,
12
+ IViewObjectEx,
13
+ )
14
+
15
+ with contextlib.redirect_stdout(None): # supress warnings
16
+ comtypes.client.GetModule("mshtml.tlb")
17
+
18
+ import comtypes.gen.MSHTML as mshtml
19
+
20
+
21
+ def create_html_document() -> IUnknown:
22
+ return comtypes.client.CreateObject(mshtml.HTMLDocument)
23
+
24
+
25
+ class Test_IViewObject(unittest.TestCase):
26
+ def test_Advise_GetAdvise(self):
27
+ vo = create_html_document().QueryInterface(IViewObject)
28
+ # Test that we can clear any existing advise connection.
29
+ vo.SetAdvise(DVASPECT_CONTENT, 0, None)
30
+ # Verify that no advise connection is present.
31
+ aspect, advf, sink = vo.GetAdvise()
32
+ self.assertIsInstance(aspect, int)
33
+ self.assertIsInstance(advf, int)
34
+ self.assertIsInstance(sink, IAdviseSink)
35
+ self.assertFalse(sink) # A NULL com pointer evaluates to False.
36
+
37
+ def test_Freeze_Unfreeze(self):
38
+ vo = create_html_document().QueryInterface(IViewObject)
39
+ cookie = vo.Freeze(DVASPECT_CONTENT, -1, None)
40
+ self.assertIsInstance(cookie, int)
41
+ vo.Unfreeze(cookie)
42
+
43
+
44
+ class Test_IViewObject2(unittest.TestCase):
45
+ def test_GetExtent(self):
46
+ vo = create_html_document().QueryInterface(IViewObject2)
47
+ size = vo.GetExtent(DVASPECT_CONTENT, -1, None)
48
+ self.assertTrue(size)
49
+ self.assertIsInstance(size, SIZEL)
50
+
51
+
52
+ class Test_IViewObjectEx(unittest.TestCase):
53
+ def test_GetRect(self):
54
+ vo = create_html_document().QueryInterface(IViewObjectEx)
55
+ rect = vo.GetRect(DVASPECT_CONTENT)
56
+ self.assertTrue(rect)
57
+ self.assertIsInstance(rect, RECT)
58
+
59
+ def test_GetViewStatus(self):
60
+ vo = create_html_document().QueryInterface(IViewObjectEx)
61
+ status = vo.GetViewStatus()
62
+ self.assertIsInstance(status, int)
63
+
64
+ def test_QueryHitPoint(self):
65
+ vo = create_html_document().QueryInterface(IViewObjectEx)
66
+ # It is assumed that the view is not transparent at the origin.
67
+ bounds = RECT(left=0, top=0, right=100, bottom=100)
68
+ loc = POINT(x=0, y=0)
69
+ hit = vo.QueryHitPoint(DVASPECT_CONTENT, bounds, loc, 0)
70
+ self.assertIsInstance(hit, int)
71
+
72
+ def test_QueryHitRect(self):
73
+ vo = create_html_document().QueryInterface(IViewObjectEx)
74
+ # It is assumed that the view is not transparent at the origin.
75
+ bounds = RECT(left=0, top=0, right=100, bottom=100)
76
+ loc = RECT(left=0, top=0, right=1, bottom=1)
77
+ hit = vo.QueryHitRect(DVASPECT_CONTENT, bounds, loc, 0)
78
+ self.assertIsInstance(hit, int)
@@ -20,10 +20,10 @@ class TestCase(unittest.TestCase):
20
20
 
21
21
  def test_3(self):
22
22
  # Invalid option
23
- self.assertRaises(
24
- GetoptError, w_getopt, "/TLIB hello.tlb hello.idl".split(), ["tlb:"]
25
- )
23
+ with self.assertRaises(GetoptError):
24
+ w_getopt("/TLIB hello.tlb hello.idl".split(), ["tlb:"])
26
25
 
27
26
  def test_4(self):
28
27
  # Missing argument
29
- self.assertRaises(GetoptError, w_getopt, "/TLB".split(), ["tlb:"])
28
+ with self.assertRaises(GetoptError):
29
+ w_getopt("/TLB".split(), ["tlb:"])
@@ -26,7 +26,7 @@ except (ImportError, OSError):
26
26
  ################################################################
27
27
 
28
28
 
29
- class _Sink(object):
29
+ class _Sink:
30
30
  def __init__(self):
31
31
  self.events = []
32
32
 
@@ -42,7 +42,7 @@ _InterfaceTypeDesc = _UnionT[
42
42
  ]
43
43
 
44
44
 
45
- class CodeGenerator(object):
45
+ class CodeGenerator:
46
46
  def __init__(self, known_symbols=None, known_interfaces=None) -> None:
47
47
  self.stream = io.StringIO()
48
48
  self.imports = namespaces.ImportedNamespaces()
@@ -3,7 +3,7 @@ import io
3
3
  from comtypes.tools import typedesc
4
4
 
5
5
 
6
- class ComInterfaceBodyImplCommentWriter(object):
6
+ class ComInterfaceBodyImplCommentWriter:
7
7
  def __init__(self, stream: io.StringIO):
8
8
  self.stream = stream
9
9
 
@@ -13,7 +13,7 @@ def _to_docstring(orig: str, depth: int = 1) -> str:
13
13
  return f'{indent}"""{repled}"""'
14
14
 
15
15
 
16
- class StructureHeadWriter(object):
16
+ class StructureHeadWriter:
17
17
  def __init__(self, stream: io.StringIO) -> None:
18
18
  self.stream = stream
19
19
 
@@ -67,7 +67,7 @@ class StructureHeadWriter(object):
67
67
  print(" pass", file=self.stream)
68
68
 
69
69
 
70
- class LibraryHeadWriter(object):
70
+ class LibraryHeadWriter:
71
71
  def __init__(self, stream: io.StringIO) -> None:
72
72
  self.stream = stream
73
73
 
@@ -93,7 +93,7 @@ class LibraryHeadWriter(object):
93
93
  )
94
94
 
95
95
 
96
- class CoClassHeadWriter(object):
96
+ class CoClassHeadWriter:
97
97
  def __init__(self, stream: io.StringIO, filename: Optional[str]) -> None:
98
98
  self.stream = stream
99
99
  self.filename = filename
@@ -117,7 +117,7 @@ class CoClassHeadWriter(object):
117
117
  )
118
118
 
119
119
 
120
- class ComInterfaceHeadWriter(object):
120
+ class ComInterfaceHeadWriter:
121
121
  def __init__(self, stream: io.StringIO) -> None:
122
122
  self.stream = stream
123
123
 
@@ -172,7 +172,7 @@ class ComInterfaceHeadWriter(object):
172
172
  print(annotations, file=self.stream)
173
173
 
174
174
 
175
- class DispInterfaceHeadWriter(object):
175
+ class DispInterfaceHeadWriter:
176
176
  def __init__(self, stream: io.StringIO) -> None:
177
177
  self.stream = stream
178
178
 
@@ -6,7 +6,7 @@ from comtypes.tools import typedesc
6
6
  from comtypes.tools.codegenerator.modulenamer import name_wrapper_module
7
7
 
8
8
 
9
- class lcid(object):
9
+ class lcid:
10
10
  def __repr__(self):
11
11
  return "_lcid"
12
12
 
@@ -14,7 +14,7 @@ class lcid(object):
14
14
  lcid = lcid()
15
15
 
16
16
 
17
- class dispid(object):
17
+ class dispid:
18
18
  def __init__(self, memid):
19
19
  self.memid = memid
20
20
 
@@ -22,7 +22,7 @@ class dispid(object):
22
22
  return f"dispid({self.memid})"
23
23
 
24
24
 
25
- class helpstring(object):
25
+ class helpstring:
26
26
  def __init__(self, text):
27
27
  self.text = text
28
28
 
@@ -100,7 +100,7 @@ def _to_arg_definition(
100
100
  return code
101
101
 
102
102
 
103
- class ComMethodGenerator(object):
103
+ class ComMethodGenerator:
104
104
  def __init__(self, m: typedesc.ComMethod, isdual: bool) -> None:
105
105
  self._m = m
106
106
  self._isdual = isdual
@@ -208,7 +208,7 @@ class ComMethodGenerator(object):
208
208
  yield (type_name, arg_name, idlflags, default)
209
209
 
210
210
 
211
- class DispMethodGenerator(object):
211
+ class DispMethodGenerator:
212
212
  def __init__(self, m: typedesc.DispMethod) -> None:
213
213
  self._m = m
214
214
  self.data: List[str] = []
@@ -262,7 +262,7 @@ class DispMethodGenerator(object):
262
262
  yield (type_name, arg_name, idlflags, default)
263
263
 
264
264
 
265
- class DispPropertyGenerator(object):
265
+ class DispPropertyGenerator:
266
266
  def __init__(self, m: typedesc.DispProperty) -> None:
267
267
  self._m = m
268
268
  self._to_type_name = TypeNamer()
@@ -290,7 +290,7 @@ class DispPropertyGenerator(object):
290
290
  return (idlflags, type_name, self._m.name)
291
291
 
292
292
 
293
- class TypeNamer(object):
293
+ class TypeNamer:
294
294
  def __call__(self, t: Any) -> str:
295
295
  # Return a string, containing an expression which can be used
296
296
  # to refer to the type. Assumes the 'from ctypes import *'
@@ -15,7 +15,7 @@ from typing import (
15
15
  from typing import Union as _UnionT
16
16
 
17
17
 
18
- class ImportedNamespaces(object):
18
+ class ImportedNamespaces:
19
19
  def __init__(self) -> None:
20
20
  self.data: Dict[str, Optional[str]] = {}
21
21
 
@@ -132,7 +132,7 @@ class ImportedNamespaces(object):
132
132
  return "\n".join(lines)
133
133
 
134
134
 
135
- class DeclaredNamespaces(object):
135
+ class DeclaredNamespaces:
136
136
  def __init__(self) -> None:
137
137
  self.data: Dict[Tuple[str, str], Optional[str]] = {}
138
138
 
@@ -168,7 +168,7 @@ class DeclaredNamespaces(object):
168
168
  return "\n".join(lines)
169
169
 
170
170
 
171
- class EnumerationNamespaces(object):
171
+ class EnumerationNamespaces:
172
172
  def __init__(self) -> None:
173
173
  self.data: Dict[str, List[Tuple[str, int]]] = {}
174
174
 
@@ -276,7 +276,7 @@ class ComMethodsAnnotator(_MethodsAnnotator[typedesc.ComMethod]):
276
276
  return ComMethodAnnotator(m)
277
277
 
278
278
 
279
- class ComInterfaceMembersAnnotator(object):
279
+ class ComInterfaceMembersAnnotator:
280
280
  def __init__(self, itf: typedesc.ComInterface):
281
281
  self.itf = itf
282
282
 
@@ -316,7 +316,7 @@ class DispMethodsAnnotator(_MethodsAnnotator[typedesc.DispMethod]):
316
316
  return DispMethodAnnotator(m)
317
317
 
318
318
 
319
- class DispInterfaceMembersAnnotator(object):
319
+ class DispInterfaceMembersAnnotator:
320
320
  def __init__(self, itf: typedesc.DispInterface):
321
321
  self.itf = itf
322
322
 
@@ -1,10 +1,11 @@
1
1
  import os
2
2
  import sys
3
+ from _ctypes import COMError
3
4
  from ctypes import alignment, c_void_p, sizeof, windll
5
+ from ctypes.wintypes import MAX_PATH
4
6
  from typing import Any, Dict, List, Optional, Tuple
5
7
 
6
- from comtypes import BSTR, COMError, automation, typeinfo
7
- from comtypes.client._code_cache import _get_module_filename
8
+ from comtypes import automation, typeinfo
8
9
  from comtypes.tools import typedesc
9
10
 
10
11
  # Is the process 64-bit?
@@ -107,7 +108,7 @@ COMTYPES = {
107
108
  ################################################################
108
109
 
109
110
 
110
- class Parser(object):
111
+ class Parser:
111
112
  tlib: typeinfo.ITypeLib
112
113
  items: Dict[str, Any]
113
114
 
@@ -750,7 +751,7 @@ def get_tlib_filename(tlib: typeinfo.ITypeLib) -> Optional[str]:
750
751
  # workaround Windows 7 bug in QueryPathOfRegTypeLib returning relative path
751
752
  try:
752
753
  dll = windll.LoadLibrary(full_filename)
753
- full_filename = _get_module_filename(dll._handle)
754
+ full_filename = typeinfo.GetModuleFileName(dll._handle, MAX_PATH)
754
755
  del dll
755
756
  except OSError:
756
757
  return None
@@ -759,9 +760,9 @@ def get_tlib_filename(tlib: typeinfo.ITypeLib) -> Optional[str]:
759
760
 
760
761
  def _py2exe_hint():
761
762
  # If the tlbparser is frozen, we need to include these
762
- import comtypes.automation
763
- import comtypes.persist
764
- import comtypes.typeinfo
763
+ import comtypes.automation # noqa
764
+ import comtypes.persist # noqa
765
+ import comtypes.typeinfo # noqa
765
766
 
766
767
 
767
768
  # -eof-