|
9 | 9 | raise unittest.SkipTest("Windows-specific test")
|
10 | 10 |
|
11 | 11 |
|
12 |
| -from _ctypes import COMError |
| 12 | +from _ctypes import COMError, CopyComPointer |
13 | 13 | from ctypes import HRESULT
|
14 | 14 |
|
15 | 15 |
|
@@ -184,5 +184,44 @@ class IPersist(IUnknown):
|
184 | 184 | self.assertEqual(0, ppst.Release())
|
185 | 185 |
|
186 | 186 |
|
| 187 | +class CopyComPointerTests(unittest.TestCase): |
| 188 | + def setUp(self): |
| 189 | + ole32.CoInitializeEx(None, COINIT_APARTMENTTHREADED) |
| 190 | + |
| 191 | + def tearDown(self): |
| 192 | + ole32.CoUninitialize() |
| 193 | + gc.collect() |
| 194 | + |
| 195 | + def test_copy_com_pointer(self): |
| 196 | + class IUnknown(c_void_p): |
| 197 | + QueryInterface = proto_query_interface(None, IID_IUnknown) |
| 198 | + AddRef = proto_add_ref() |
| 199 | + Release = proto_release() |
| 200 | + |
| 201 | + class IPersist(IUnknown): |
| 202 | + GetClassID = proto_get_class_id(((OUT, "pClassID"),), IID_IPersist) |
| 203 | + |
| 204 | + src = create_shelllink_persist(IPersist) |
| 205 | + dst = IPersist() |
| 206 | + |
| 207 | + self.assertIsNone(dst.value) |
| 208 | + with self.assertRaises(ValueError): |
| 209 | + dst.GetClassID() # NULL COM pointer access |
| 210 | + |
| 211 | + hr = CopyComPointer(src, byref(dst)) |
| 212 | + |
| 213 | + self.assertEqual(S_OK, hr) |
| 214 | + self.assertEqual(dst.value, src.value) |
| 215 | + |
| 216 | + clsid = dst.GetClassID() |
| 217 | + self.assertEqual(TRUE, is_equal_guid(CLSID_ShellLink, clsid)) |
| 218 | + |
| 219 | + # The refcount of a COM pointer created by `CoCreateInstance` is 1. |
| 220 | + # `CopyComPointer` calls `AddRef` internally (thus, +1 to the refcount). |
| 221 | + # Here, the refcount is decremented from 2 to 1. |
| 222 | + self.assertEqual(1, dst.Release()) |
| 223 | + self.assertEqual(0, src.Release()) |
| 224 | + |
| 225 | + |
187 | 226 | if __name__ == '__main__':
|
188 | 227 | unittest.main()
|
0 commit comments