From 7afd5475447ba732e0913e7828646dbe48906912 Mon Sep 17 00:00:00 2001 From: junkmd Date: Wed, 17 Dec 2025 21:07:32 +0900 Subject: [PATCH 1/7] test: Add test for `GetRefTypeOfImplType` with pure dispatch interfaces. This test verifies the behavior of `ITypeInfo.GetRefTypeOfImplType` when called on a pure dispatch interface. It asserts that a `COMError` with `TYPE_E_ELEMENTNOTFOUND` is raised, which also serves as further validation for the recently corrected HRESULT constant. --- comtypes/test/test_typeinfo.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/comtypes/test/test_typeinfo.py b/comtypes/test/test_typeinfo.py index 7be16de9..41d532c3 100644 --- a/comtypes/test/test_typeinfo.py +++ b/comtypes/test/test_typeinfo.py @@ -97,6 +97,16 @@ def test_TypeInfo(self): self.assertEqual(c_ti, ti) self.assertEqual(IID_IFile, ti.GetTypeAttr().guid) + def test_pure_dispatch_ITypeInfo(self): + tlib = LoadTypeLibEx("msi.dll") + IID_Installer = GUID("{000C1090-0000-0000-C000-000000000046}") + ti = tlib.GetTypeInfoOfGuid(IID_Installer) + ta = ti.GetTypeAttr() + self.assertEqual(ta.typekind, TKIND_DISPATCH) + with self.assertRaises(COMError) as cm: + ti.GetRefTypeOfImplType(-1) + self.assertEqual(comtypes.hresult.TYPE_E_ELEMENTNOTFOUND, cm.exception.hresult) + class Test_GetModuleFileName(unittest.TestCase): @unittest.skipUnless( From 104d32b662570bb07e6763075210845e5a40424b Mon Sep 17 00:00:00 2001 From: junkmd Date: Wed, 17 Dec 2025 21:07:32 +0900 Subject: [PATCH 2/7] test: Add test for `GetRefTypeOfImplType` with custom interfaces. This adds another test for `ITypeInfo.GetRefTypeOfImplType`, this time using a custom interface. This expands test coverage and further validates that `COMError` with `TYPE_E_ELEMENTNOTFOUND` is correctly raised for invalid calls. --- comtypes/test/test_typeinfo.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/comtypes/test/test_typeinfo.py b/comtypes/test/test_typeinfo.py index 41d532c3..21ff05fc 100644 --- a/comtypes/test/test_typeinfo.py +++ b/comtypes/test/test_typeinfo.py @@ -107,6 +107,16 @@ def test_pure_dispatch_ITypeInfo(self): ti.GetRefTypeOfImplType(-1) self.assertEqual(comtypes.hresult.TYPE_E_ELEMENTNOTFOUND, cm.exception.hresult) + def test_custom_interface_ITypeInfo(self): + tlib = LoadTypeLibEx("UIAutomationCore.dll") + IID_IUIAutomation = GUID("{30CBE57D-D9D0-452A-AB13-7AC5AC4825EE}") + ti = tlib.GetTypeInfoOfGuid(IID_IUIAutomation) + ta = ti.GetTypeAttr() + self.assertEqual(ta.typekind, TKIND_INTERFACE) + with self.assertRaises(COMError) as cm: + ti.GetRefTypeOfImplType(-1) + self.assertEqual(comtypes.hresult.TYPE_E_ELEMENTNOTFOUND, cm.exception.hresult) + class Test_GetModuleFileName(unittest.TestCase): @unittest.skipUnless( From f3402b2871e7a1864a27718349c3345fae2a0e2d Mon Sep 17 00:00:00 2001 From: junkmd Date: Wed, 17 Dec 2025 21:07:32 +0900 Subject: [PATCH 3/7] test: Add test for `GetRefTypeOfImplType` with dual interfaces. --- comtypes/test/test_typeinfo.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/comtypes/test/test_typeinfo.py b/comtypes/test/test_typeinfo.py index 21ff05fc..ae2a314f 100644 --- a/comtypes/test/test_typeinfo.py +++ b/comtypes/test/test_typeinfo.py @@ -117,6 +117,18 @@ def test_custom_interface_ITypeInfo(self): ti.GetRefTypeOfImplType(-1) self.assertEqual(comtypes.hresult.TYPE_E_ELEMENTNOTFOUND, cm.exception.hresult) + def test_dual_interface_ITypeInfo(self): + tlib = LoadTypeLibEx("scrrun.dll") + IID_IDictionary = GUID("{42C642C1-97E1-11CF-978F-00A02463E06F}") + ti = tlib.GetTypeInfoOfGuid(IID_IDictionary) + ta = ti.GetTypeAttr() + self.assertEqual(ta.typekind, TKIND_DISPATCH) + refti = ti.GetRefTypeInfo(ti.GetRefTypeOfImplType(-1)) + refta = refti.GetTypeAttr() + self.assertEqual(IID_IDictionary, refti.GetTypeAttr().guid) + self.assertEqual(refta.typekind, TKIND_INTERFACE) + self.assertEqual(ti, refti.GetRefTypeInfo(refti.GetRefTypeOfImplType(-1))) + class Test_GetModuleFileName(unittest.TestCase): @unittest.skipUnless( From 272a9b06b41993a5df64e1050238fed883d367b8 Mon Sep 17 00:00:00 2001 From: junkmd Date: Wed, 17 Dec 2025 21:07:32 +0900 Subject: [PATCH 4/7] refactor: Use qualified `typeinfo` constants and add `TYPEFLAG_FDUAL` assertions. Replaced direct imports of `TKIND_DISPATCH` and `TKIND_INTERFACE` with qualified references (e.g., `typeinfo.TKIND_DISPATCH`) for consistency within `test_typeinfo.py`. Additionally, added assertions for `TYPEFLAG_FDUAL` in the tests for pure dispatch and dual interfaces to more thoroughly verify interface flags, especially for dual interfaces. --- comtypes/test/test_typeinfo.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/comtypes/test/test_typeinfo.py b/comtypes/test/test_typeinfo.py index ae2a314f..33001323 100644 --- a/comtypes/test/test_typeinfo.py +++ b/comtypes/test/test_typeinfo.py @@ -5,10 +5,8 @@ from ctypes.wintypes import MAX_PATH import comtypes.hresult -from comtypes import GUID, COMError +from comtypes import GUID, COMError, typeinfo from comtypes.typeinfo import ( - TKIND_DISPATCH, - TKIND_INTERFACE, GetModuleFileName, LoadRegTypeLib, LoadTypeLibEx, @@ -69,7 +67,7 @@ def test_TypeInfo(self): c_tlib, c_index = ti.GetContainingTypeLib() self.assert_tlibattr_equal(c_tlib, tlib) self.assertEqual(c_index, index) - if ta.typekind in (TKIND_INTERFACE, TKIND_DISPATCH): + if ta.typekind in (typeinfo.TKIND_INTERFACE, typeinfo.TKIND_DISPATCH): if ta.cImplTypes: href = ti.GetRefTypeOfImplType(0) base = ti.GetRefTypeInfo(href) @@ -102,31 +100,35 @@ def test_pure_dispatch_ITypeInfo(self): IID_Installer = GUID("{000C1090-0000-0000-C000-000000000046}") ti = tlib.GetTypeInfoOfGuid(IID_Installer) ta = ti.GetTypeAttr() - self.assertEqual(ta.typekind, TKIND_DISPATCH) + self.assertEqual(ta.typekind, typeinfo.TKIND_DISPATCH) with self.assertRaises(COMError) as cm: ti.GetRefTypeOfImplType(-1) self.assertEqual(comtypes.hresult.TYPE_E_ELEMENTNOTFOUND, cm.exception.hresult) + self.assertFalse(ti.GetTypeAttr().wTypeFlags & typeinfo.TYPEFLAG_FDUAL) def test_custom_interface_ITypeInfo(self): tlib = LoadTypeLibEx("UIAutomationCore.dll") IID_IUIAutomation = GUID("{30CBE57D-D9D0-452A-AB13-7AC5AC4825EE}") ti = tlib.GetTypeInfoOfGuid(IID_IUIAutomation) ta = ti.GetTypeAttr() - self.assertEqual(ta.typekind, TKIND_INTERFACE) + self.assertEqual(ta.typekind, typeinfo.TKIND_INTERFACE) with self.assertRaises(COMError) as cm: ti.GetRefTypeOfImplType(-1) self.assertEqual(comtypes.hresult.TYPE_E_ELEMENTNOTFOUND, cm.exception.hresult) + self.assertFalse(ti.GetTypeAttr().wTypeFlags & typeinfo.TYPEFLAG_FDUAL) def test_dual_interface_ITypeInfo(self): tlib = LoadTypeLibEx("scrrun.dll") IID_IDictionary = GUID("{42C642C1-97E1-11CF-978F-00A02463E06F}") ti = tlib.GetTypeInfoOfGuid(IID_IDictionary) ta = ti.GetTypeAttr() - self.assertEqual(ta.typekind, TKIND_DISPATCH) + self.assertEqual(ta.typekind, typeinfo.TKIND_DISPATCH) + self.assertTrue(ta.wTypeFlags & typeinfo.TYPEFLAG_FDUAL) refti = ti.GetRefTypeInfo(ti.GetRefTypeOfImplType(-1)) refta = refti.GetTypeAttr() self.assertEqual(IID_IDictionary, refti.GetTypeAttr().guid) - self.assertEqual(refta.typekind, TKIND_INTERFACE) + self.assertTrue(refta.wTypeFlags & typeinfo.TYPEFLAG_FDUAL) + self.assertEqual(refta.typekind, typeinfo.TKIND_INTERFACE) self.assertEqual(ti, refti.GetRefTypeInfo(refti.GetRefTypeOfImplType(-1))) From a9bca6285f850ffa00fa403b10e5187020e5730f Mon Sep 17 00:00:00 2001 From: junkmd Date: Wed, 17 Dec 2025 21:07:32 +0900 Subject: [PATCH 5/7] refactor: Consolidate `hresult` import in `test_typeinfo.py`. The `comtypes.hresult` import was replaced with a direct import from `comtypes`, and usages were updated accordingly. This change improves consistency with other imports in the module. --- comtypes/test/test_typeinfo.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/comtypes/test/test_typeinfo.py b/comtypes/test/test_typeinfo.py index 33001323..fa4a359e 100644 --- a/comtypes/test/test_typeinfo.py +++ b/comtypes/test/test_typeinfo.py @@ -4,8 +4,7 @@ import unittest from ctypes.wintypes import MAX_PATH -import comtypes.hresult -from comtypes import GUID, COMError, typeinfo +from comtypes import GUID, COMError, hresult, typeinfo from comtypes.typeinfo import ( GetModuleFileName, LoadRegTypeLib, @@ -85,7 +84,7 @@ def test_TypeInfo(self): guid_null = GUID() with self.assertRaises(COMError) as cm: tlib.GetTypeInfoOfGuid(guid_null) - self.assertEqual(comtypes.hresult.TYPE_E_ELEMENTNOTFOUND, cm.exception.hresult) + self.assertEqual(hresult.TYPE_E_ELEMENTNOTFOUND, cm.exception.hresult) IID_IFile = GUID("{C7C3F5A4-88A3-11D0-ABCB-00A0C90FFFC0}") ti = tlib.GetTypeInfoOfGuid(IID_IFile) @@ -103,7 +102,7 @@ def test_pure_dispatch_ITypeInfo(self): self.assertEqual(ta.typekind, typeinfo.TKIND_DISPATCH) with self.assertRaises(COMError) as cm: ti.GetRefTypeOfImplType(-1) - self.assertEqual(comtypes.hresult.TYPE_E_ELEMENTNOTFOUND, cm.exception.hresult) + self.assertEqual(hresult.TYPE_E_ELEMENTNOTFOUND, cm.exception.hresult) self.assertFalse(ti.GetTypeAttr().wTypeFlags & typeinfo.TYPEFLAG_FDUAL) def test_custom_interface_ITypeInfo(self): @@ -114,7 +113,7 @@ def test_custom_interface_ITypeInfo(self): self.assertEqual(ta.typekind, typeinfo.TKIND_INTERFACE) with self.assertRaises(COMError) as cm: ti.GetRefTypeOfImplType(-1) - self.assertEqual(comtypes.hresult.TYPE_E_ELEMENTNOTFOUND, cm.exception.hresult) + self.assertEqual(hresult.TYPE_E_ELEMENTNOTFOUND, cm.exception.hresult) self.assertFalse(ti.GetTypeAttr().wTypeFlags & typeinfo.TYPEFLAG_FDUAL) def test_dual_interface_ITypeInfo(self): From b962e061e4bde913a2a654ffd6500493b2532fc8 Mon Sep 17 00:00:00 2001 From: junkmd Date: Wed, 17 Dec 2025 21:07:32 +0900 Subject: [PATCH 6/7] refactor: Import `COMError` from `_ctypes` in `test_typeinfo.py`. To align with internal conventions, the import for `COMError` has been changed from `comtypes` to the more direct `_ctypes` module. --- comtypes/test/test_typeinfo.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/comtypes/test/test_typeinfo.py b/comtypes/test/test_typeinfo.py index fa4a359e..76f25bbb 100644 --- a/comtypes/test/test_typeinfo.py +++ b/comtypes/test/test_typeinfo.py @@ -2,9 +2,10 @@ import os import sys import unittest +from _ctypes import COMError from ctypes.wintypes import MAX_PATH -from comtypes import GUID, COMError, hresult, typeinfo +from comtypes import GUID, hresult, typeinfo from comtypes.typeinfo import ( GetModuleFileName, LoadRegTypeLib, From d1c6c45d0c55d5ca4c13db20e0b77fca5ef0871a Mon Sep 17 00:00:00 2001 From: junkmd Date: Wed, 17 Dec 2025 21:07:32 +0900 Subject: [PATCH 7/7] docs: Add comment with link to official documentation for `GetRefTypeOfImplType`. --- comtypes/tools/tlbparser.py | 1 + 1 file changed, 1 insertion(+) diff --git a/comtypes/tools/tlbparser.py b/comtypes/tools/tlbparser.py index ef400bb8..cad940d7 100644 --- a/comtypes/tools/tlbparser.py +++ b/comtypes/tools/tlbparser.py @@ -624,6 +624,7 @@ def parse_typeinfo(self, tinfo: typeinfo.ITypeInfo) -> Any: try: # GetRefTypeOfImplType(-1) returns the custom portion # of a dispinterface, if it is dual + # See https://learn.microsoft.com/en-us/windows/win32/api/oaidl/nf-oaidl-itypeinfo-getreftypeofimpltype#remarks href = tinfo.GetRefTypeOfImplType(-1) except COMError: # no dual interface