GeezerVisonThe World Wide Web, restored to 800 pixels of glory. |
| Home|About|Gaming cabinet|Archives|How it works|Starter sites |
GeezerVison is showing github.com — Add tests to verify the behavior of basic COM methods. · Issue #126384 · python/cpython Closed Labels testsTests in the Lib/test dirTests in the Lib/test dirtopic-ctypestype-featureA feature request or enhancementA feature request or enhancement DescriptionFeature or enhancementProposal:I am one of the maintainers of In the past, I reported in gh-124520 that projects dependent on I am currently researching whether there are any effective ways to proactively prevent such regressions beyond what I attempted in gh-125783. I noticed that the I think that simple tests like the one below, which implements a very basic COM interface and calls its methods, might help prevent regressions. import sys import unittest def setUpModule(): if sys.platform != "win32": raise unittest.SkipTest("Win32 only") import ctypes import gc from ctypes import HRESULT, POINTER, byref from ctypes.wintypes import BYTE, DWORD, HGLOBAL, WORD ole32 = ctypes.oledll.ole32 oleaut32 = ctypes.oledll.oleaut32 def CLSIDFromString(name): guid = GUID() ole32.CLSIDFromString(name, byref(guid)) return guid class GUID(ctypes.Structure): _fields_ = [ ("Data1", DWORD), ("Data2", WORD), ("Data3", WORD), ("Data4", BYTE * 8), ] PyInstanceMethod_New = ctypes.pythonapi.PyInstanceMethod_New PyInstanceMethod_New.argtypes = [ctypes.py_object] PyInstanceMethod_New.restype = ctypes.py_object PyInstanceMethod_Type = type(PyInstanceMethod_New(id)) class COM_METHOD: def __init__(self, index, restype, *argtypes): self.index = index self.proto = ctypes.WINFUNCTYPE(restype, *argtypes) def __set_name__(self, owner, name): self.mth = PyInstanceMethod_Type(self.proto(self.index, name)) def __call__(self, *args, **kwargs): return self.mth(*args, **kwargs) def __get__(self, instance, owner): if instance is None: return self return self.mth.__get__(instance) class IUnknown(ctypes.c_void_p): IID = CLSIDFromString("{00000000-0000-0000-C000-000000000046}") QueryInterface = COM_METHOD(0, HRESULT, POINTER(GUID), POINTER(ctypes.c_void_p)) AddRef = COM_METHOD(1, ctypes.c_long) Release = COM_METHOD(2, ctypes.c_long) class ICreateTypeLib(IUnknown): IID = CLSIDFromString("{00020406-0000-0000-C000-000000000046}") # `CreateTypeInfo` and more methods should be implemented class ICreateTypeLib2(ICreateTypeLib): IID = CLSIDFromString("{0002040F-0000-0000-C000-000000000046}") # `DeleteTypeInfo` and more methods should be implemented class ISequentialStream(IUnknown): IID = CLSIDFromString("{0C733A30-2A1C-11CE-ADE5-00AA0044773D}") # `Read` and `Write` methods should be implemented class IStream(ISequentialStream): IID = CLSIDFromString("{0000000C-0000-0000-C000-000000000046}") # `Seek` and more methods should be implemented CreateTypeLib2 = oleaut32.CreateTypeLib2 CreateTypeLib2.argtypes = (ctypes.c_int, ctypes.c_wchar_p, POINTER(ICreateTypeLib2)) CreateStreamOnHGlobal = ole32.CreateStreamOnHGlobal CreateStreamOnHGlobal.argtypes = (HGLOBAL, ctypes.c_bool, POINTER(IStream)) COINIT_APARTMENTTHREADED = 0x2 S_OK = 0 E_NOINTERFACE = -2147467262 class Test(unittest.TestCase): def setUp(self): ole32.CoInitializeEx(None, COINIT_APARTMENTTHREADED) def tearDown(self): ole32.CoUninitialize() gc.collect() def test_create_typelib_2(self): pctlib = ICreateTypeLib2() hr = CreateTypeLib2(0, "sample.tlb", pctlib) self.assertEqual(S_OK, hr) self.assertEqual(2, pctlib.AddRef()) self.assertEqual(3, pctlib.AddRef()) self.assertEqual(2, pctlib.Release()) self.assertEqual(1, pctlib.Release()) self.assertEqual(0, pctlib.Release()) def test_stream(self): pstm = IStream() hr = CreateStreamOnHGlobal(None, True, pstm) self.assertEqual(S_OK, hr) self.assertEqual(2, pstm.AddRef()) self.assertEqual(3, pstm.AddRef()) self.assertEqual(2, pstm.Release()) self.assertEqual(1, pstm.Release()) self.assertEqual(0, pstm.Release()) def test_query_interface(self): pctlib2 = ICreateTypeLib2() CreateTypeLib2(0, "sample.tlb", pctlib2) pctlib = ICreateTypeLib() hr1 = pctlib2.QueryInterface(byref(ICreateTypeLib.IID), byref(pctlib)) self.assertEqual(S_OK, hr1) self.assertEqual(1, pctlib.Release()) punk = IUnknown() hr2 = pctlib.QueryInterface(byref(IUnknown.IID), byref(punk)) self.assertEqual(S_OK, hr2) self.assertEqual(1, punk.Release()) pstm = IStream() with self.assertRaises(WindowsError) as e: # Why not `COMError`? punk.QueryInterface(byref(IStream.IID), byref(pstm)) self.assertEqual(E_NOINTERFACE, e.exception.winerror) self.assertEqual(0, punk.Release())
I welcome any feedback. Has this already been discussed elsewhere?No response given Links to previous discussion of this feature:No response Linked PRsActivity
MetadataMetadataAssigneesLabelstestsTests in the Lib/test dirTests in the Lib/test dirtopic-ctypestype-featureA feature request or enhancementA feature request or enhancement ProjectsMilestoneRelationshipsDevelopmentIssue actions |
| You are visitor 01402503 — GeezerVison does not store the pages you look up. Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required. |