comtypes 1.4.11__zip → 1.4.13__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.11 → comtypes-1.4.13}/CHANGES.txt +33 -0
  2. {comtypes-1.4.11/comtypes.egg-info → comtypes-1.4.13}/PKG-INFO +5 -5
  3. {comtypes-1.4.11 → comtypes-1.4.13}/README.md +3 -3
  4. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/__init__.py +8 -2
  5. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/_comobject.py +6 -6
  6. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/_memberspec.py +7 -7
  7. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/_meta.py +7 -3
  8. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/_npsupport.py +12 -17
  9. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/_post_coinit/_cominterface_meta_patcher.py +5 -5
  10. comtypes-1.4.13/comtypes/_post_coinit/activeobj.py +61 -0
  11. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/_post_coinit/misc.py +1 -23
  12. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/_post_coinit/unknwn.py +10 -8
  13. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/_vtbl.py +3 -3
  14. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/automation.py +10 -13
  15. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/client/__init__.py +2 -1
  16. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/client/_activeobj.py +8 -0
  17. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/client/_code_cache.py +1 -1
  18. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/client/_constants.py +1 -1
  19. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/client/_events.py +6 -6
  20. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/client/_generate.py +1 -1
  21. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/client/dynamic.py +3 -3
  22. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/client/lazybind.py +3 -3
  23. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/errorinfo.py +1 -1
  24. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/hresult.py +68 -0
  25. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/messageloop.py +1 -1
  26. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/patcher.py +2 -2
  27. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/persist.py +9 -2
  28. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/safearray.py +10 -10
  29. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/server/__init__.py +5 -37
  30. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/server/automation.py +2 -2
  31. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/server/connectionpoints.py +3 -3
  32. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/server/inprocserver.py +2 -2
  33. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/server/localserver.py +3 -3
  34. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/server/register.py +5 -5
  35. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_agilent.py +1 -1
  36. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_client_dynamic.py +1 -1
  37. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_comserver.py +15 -2
  38. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_createwrappers.py +1 -1
  39. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_dispifc_records.py +0 -2
  40. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_dispifc_safearrays.py +0 -2
  41. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_dispinterface.py +1 -1
  42. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_excel.py +2 -5
  43. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_getactiveobj.py +19 -2
  44. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_hresult.py +39 -0
  45. comtypes-1.4.13/comtypes/test/test_messageloop.py +117 -0
  46. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_midl_safearray_create.py +0 -2
  47. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_msscript.py +1 -1
  48. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_npsupport.py +22 -11
  49. comtypes-1.4.13/comtypes/test/test_persist.py +71 -0
  50. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_recordinfo.py +0 -2
  51. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_server.py +6 -6
  52. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_storage.py +1 -1
  53. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_stream.py +22 -2
  54. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_urlhistory.py +1 -1
  55. comtypes-1.4.13/comtypes/test/test_util.py +227 -0
  56. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_variant.py +41 -24
  57. comtypes-1.4.13/comtypes/test/test_viewobject.py +78 -0
  58. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_word.py +1 -1
  59. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/tools/codegenerator/codegenerator.py +1 -1
  60. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/tools/codegenerator/comments.py +1 -1
  61. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/tools/codegenerator/heads.py +5 -5
  62. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/tools/codegenerator/helpers.py +7 -7
  63. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/tools/codegenerator/namespaces.py +3 -3
  64. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/tools/codegenerator/typeannotator.py +2 -2
  65. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/tools/tlbparser.py +1 -1
  66. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/tools/typedesc.py +14 -14
  67. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/tools/typedesc_base.py +19 -19
  68. comtypes-1.4.13/comtypes/util.py +189 -0
  69. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/viewobject.py +29 -5
  70. {comtypes-1.4.11 → comtypes-1.4.13/comtypes.egg-info}/PKG-INFO +5 -5
  71. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes.egg-info/SOURCES.txt +4 -0
  72. {comtypes-1.4.11 → comtypes-1.4.13}/pyproject.toml +12 -1
  73. {comtypes-1.4.11 → comtypes-1.4.13}/setup.cfg +1 -1
  74. comtypes-1.4.11/comtypes/test/test_persist.py +0 -38
  75. comtypes-1.4.11/comtypes/util.py +0 -107
  76. {comtypes-1.4.11 → comtypes-1.4.13}/LICENSE.txt +0 -0
  77. {comtypes-1.4.11 → comtypes-1.4.13}/MANIFEST.in +0 -0
  78. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/GUID.py +0 -0
  79. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/_post_coinit/__init__.py +0 -0
  80. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/_post_coinit/bstr.py +0 -0
  81. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/_post_coinit/instancemethod.py +0 -0
  82. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/_safearray.py +0 -0
  83. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/_tlib_version_checker.py +0 -0
  84. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/clear_cache.py +0 -0
  85. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/client/_create.py +0 -0
  86. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/client/_managing.py +0 -0
  87. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/connectionpoints.py +0 -0
  88. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/git.py +0 -0
  89. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/hints.pyi +0 -0
  90. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/logutil.py +0 -0
  91. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/server/w_getopt.py +0 -0
  92. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/shelllink.py +0 -0
  93. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/stream.py +0 -0
  94. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/TestComServer.idl +0 -0
  95. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/TestComServer.py +0 -0
  96. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/TestComServer.tlb +0 -0
  97. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/TestDispServer.idl +0 -0
  98. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/TestDispServer.py +0 -0
  99. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/TestDispServer.tlb +0 -0
  100. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/__init__.py +0 -0
  101. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/find_memleak.py +0 -0
  102. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/mylib.idl +0 -0
  103. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/mylib.tlb +0 -0
  104. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/mytypelib.idl +0 -0
  105. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/runtests.py +0 -0
  106. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/setup.py +0 -0
  107. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_BSTR.py +0 -0
  108. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_DISPPARAMS.py +0 -0
  109. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_GUID.py +0 -0
  110. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_QueryService.py +0 -0
  111. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_avmc.py +0 -0
  112. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_basic.py +0 -0
  113. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_casesensitivity.py +0 -0
  114. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_clear_cache.py +0 -0
  115. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_client.py +0 -0
  116. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_client_regenerate_modules.py +0 -0
  117. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_collections.py +0 -0
  118. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_comobject.py +0 -0
  119. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_dict.py +0 -0
  120. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_dyndispatch.py +0 -0
  121. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_errorinfo.py +0 -0
  122. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_findgendir.py +0 -0
  123. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_ie.py +0 -0
  124. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_ienum.py +0 -0
  125. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_imfattributes.py +0 -0
  126. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_inout_args.py +0 -0
  127. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_jscript.js +0 -0
  128. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_monikers.py +0 -0
  129. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_outparam.py +0 -0
  130. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_pump_events.py +0 -0
  131. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_safearray.py +0 -0
  132. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_sapi.py +0 -0
  133. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_server_register.py +0 -0
  134. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_shelllink.py +0 -0
  135. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_showevents.py +0 -0
  136. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_subinterface.py +0 -0
  137. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_typeannotator.py +0 -0
  138. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_typeinfo.py +0 -0
  139. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_w_getopt.py +0 -0
  140. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_win32com_interop.py +0 -0
  141. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/test_wmi.py +0 -0
  142. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/test/urlhist.tlb +0 -0
  143. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/tools/__init__.py +0 -0
  144. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/tools/codegenerator/__init__.py +0 -0
  145. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/tools/codegenerator/modulenamer.py +0 -0
  146. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/tools/codegenerator/packing.py +0 -0
  147. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes/typeinfo.py +0 -0
  148. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes.egg-info/dependency_links.txt +0 -0
  149. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes.egg-info/entry_points.txt +0 -0
  150. {comtypes-1.4.11 → comtypes-1.4.13}/comtypes.egg-info/top_level.txt +0 -0
  151. {comtypes-1.4.11 → comtypes-1.4.13}/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)
@@ -115,33 +115,52 @@ class VariantTestCase(unittest.TestCase):
115
115
  self.assertEqual(result, values)
116
116
 
117
117
  def test_pythonobjects(self):
118
- if sys.version_info >= (3, 0):
119
- objects = [None, 42, 3.14, True, False, "abc", "abc", 7]
120
- else:
121
- objects = [None, 42, 3.14, True, False, "abc", "abc", 7]
118
+ objects = [None, 42, 3.14, True, False, "abc", "abc", 7]
122
119
  for x in objects:
123
- v = VARIANT(x)
124
- self.assertEqual(x, v.value)
120
+ with self.subTest(x=x):
121
+ v = VARIANT(x)
122
+ self.assertEqual(x, v.value)
125
123
 
126
124
  def test_integers(self):
127
125
  v = VARIANT()
128
126
 
129
- int_type = int if sys.version_info >= (3, 0) else (int, long)
130
-
131
- if hasattr(sys, "maxint"):
132
- # this test doesn't work in Python 3000
133
- v.value = sys.maxsize
134
- self.assertEqual(v.value, sys.maxsize)
135
- self.assertIsInstance(v.value, int_type)
136
-
137
- v.value += 1
138
- self.assertEqual(v.value, sys.maxsize + 1)
139
- self.assertIsInstance(v.value, int_type)
140
-
141
127
  v.value = 1
142
128
 
143
129
  self.assertEqual(v.value, 1)
144
- 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
145
164
 
146
165
  def test_datetime(self):
147
166
  now = datetime.datetime.now()
@@ -304,13 +323,11 @@ def check_perf(rep=20000):
304
323
  by_var = byref(variable)
305
324
  ptr_var = pointer(variable)
306
325
 
307
- if sys.version_info >= (3, 0):
308
- import pickle
309
- else:
310
- import cPickle as pickle
326
+ import pickle
327
+
311
328
  try:
312
329
  previous = pickle.load(open("result.pickle", "rb"))
313
- except IOError:
330
+ except OSError:
314
331
  previous = {}
315
332
 
316
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)
@@ -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
 
@@ -108,7 +108,7 @@ COMTYPES = {
108
108
  ################################################################
109
109
 
110
110
 
111
- class Parser(object):
111
+ class Parser:
112
112
  tlib: typeinfo.ITypeLib
113
113
  items: Dict[str, Any]
114
114
 
@@ -10,7 +10,7 @@ from comtypes.tools.typedesc_base import *
10
10
  from comtypes.typeinfo import TLIBATTR, ITypeLib
11
11
 
12
12
 
13
- class TypeLib(object):
13
+ class TypeLib:
14
14
  def __init__(
15
15
  self, name: str, guid: str, major: int, minor: int, doc: Optional[str] = None
16
16
  ) -> None:
@@ -24,7 +24,7 @@ class TypeLib(object):
24
24
  return f"<TypeLib({self.name}: {self.guid}, {self.major}, {self.minor})>"
25
25
 
26
26
 
27
- class Constant(object):
27
+ class Constant:
28
28
  def __init__(
29
29
  self,
30
30
  name: str,
@@ -38,7 +38,7 @@ class Constant(object):
38
38
  self.doc = doc
39
39
 
40
40
 
41
- class External(object):
41
+ class External:
42
42
  def __init__(
43
43
  self,
44
44
  tlib: ITypeLib,
@@ -61,13 +61,13 @@ class External(object):
61
61
  return self
62
62
 
63
63
 
64
- class SAFEARRAYType(object):
64
+ class SAFEARRAYType:
65
65
  def __init__(self, typ: Any) -> None:
66
66
  self.typ = typ
67
67
  self.align = self.size = ctypes.sizeof(ctypes.c_void_p) * 8
68
68
 
69
69
 
70
- class ComMethod(object):
70
+ class ComMethod:
71
71
  # custom COM method, parsed from typelib
72
72
  def __init__(
73
73
  self,
@@ -92,7 +92,7 @@ class ComMethod(object):
92
92
  self.arguments.append((typ, name, idlflags, default))
93
93
 
94
94
 
95
- class DispMethod(object):
95
+ class DispMethod:
96
96
  # dispatchable COM method, parsed from typelib
97
97
  def __init__(
98
98
  self,
@@ -117,7 +117,7 @@ class DispMethod(object):
117
117
  self.arguments.append((typ, name, idlflags, default))
118
118
 
119
119
 
120
- class DispProperty(object):
120
+ class DispProperty:
121
121
  # dispatchable COM property, parsed from typelib
122
122
  def __init__(
123
123
  self, dispid: int, name: str, typ: Any, idlflags: List[str], doc: Optional[Any]
@@ -129,17 +129,17 @@ class DispProperty(object):
129
129
  self.doc = doc
130
130
 
131
131
 
132
- class DispInterfaceHead(object):
132
+ class DispInterfaceHead:
133
133
  def __init__(self, itf: "DispInterface") -> None:
134
134
  self.itf = itf
135
135
 
136
136
 
137
- class DispInterfaceBody(object):
137
+ class DispInterfaceBody:
138
138
  def __init__(self, itf: "DispInterface") -> None:
139
139
  self.itf = itf
140
140
 
141
141
 
142
- class DispInterface(object):
142
+ class DispInterface:
143
143
  def __init__(
144
144
  self,
145
145
  name: str,
@@ -167,17 +167,17 @@ class DispInterface(object):
167
167
  return self.itf_head
168
168
 
169
169
 
170
- class ComInterfaceHead(object):
170
+ class ComInterfaceHead:
171
171
  def __init__(self, itf: "ComInterface") -> None:
172
172
  self.itf = itf
173
173
 
174
174
 
175
- class ComInterfaceBody(object):
175
+ class ComInterfaceBody:
176
176
  def __init__(self, itf: "ComInterface") -> None:
177
177
  self.itf = itf
178
178
 
179
179
 
180
- class ComInterface(object):
180
+ class ComInterface:
181
181
  def __init__(
182
182
  self,
183
183
  name: str,
@@ -209,7 +209,7 @@ _ImplTypeFlags = int
209
209
  _Interface = _UnionT[ComInterface, DispInterface]
210
210
 
211
211
 
212
- class CoClass(object):
212
+ class CoClass:
213
213
  def __init__(
214
214
  self,
215
215
  name: str,