From 716719dba286a49b1690ec76f9076f2c5d9a8afc Mon Sep 17 00:00:00 2001 From: Thomas Geppert Date: Sat, 29 Jun 2024 09:10:09 +0200 Subject: [PATCH] Change the default value of the 'extra' parameter in the 'create' method of tagSAFEARRAY subtypes. (#576) * Changed the default value of the 'extra' parameter in the 'create' method of tagSAFEARRAY subtypes which are generated by '_midlSAFEARRAY' to the setting for 'extra' identified in the '_make_safearray_type' method. The 'extra' value required for the creation of SAFEARRAYs with VT_RECORD, VT_DISPATCH or VT_UNKNOWN elements is already identified at the time when the associated tagSAFEARRAY subtype is created in the '_make_safearray_type' method. Using this value by default for the 'extra' parameter when creating an instance of the type does avoid performing the same identification process again in user code. * Added a unittest for the changed default value of the 'extra' parameter in the 'create' method of tagSAFEARRAY subtypes. * Changed the dispatch interface test to use the 'IDispSafearrayParamTest' interface of the C++ COM test server instead of the 'IDictionary' interface of the Microsoft Script Runtime. * Removed unused import of 'ctypes.byref'. Added values for the 'answer' and 'needs_clarification' fields of the 'StructRecordParamTest' structure and included them in the assertion testing. --- comtypes/safearray.py | 2 +- comtypes/test/test_midl_safearray_create.py | 100 ++++++++++++++++++++ source/CppTestSrv/SERVER.IDL | 2 + 3 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 comtypes/test/test_midl_safearray_create.py diff --git a/comtypes/safearray.py b/comtypes/safearray.py index 3e6582d5..44e21598 100644 --- a/comtypes/safearray.py +++ b/comtypes/safearray.py @@ -109,7 +109,7 @@ class _(object): _needsfree = False @classmethod - def create(cls, value, extra=None): + def create(cls, value, extra=extra): """Create a POINTER(SAFEARRAY_...) instance of the correct type; value is an object containing the items to store. diff --git a/comtypes/test/test_midl_safearray_create.py b/comtypes/test/test_midl_safearray_create.py new file mode 100644 index 00000000..d632b5e7 --- /dev/null +++ b/comtypes/test/test_midl_safearray_create.py @@ -0,0 +1,100 @@ +# coding: utf-8 + +from ctypes import c_int, pointer, POINTER +import unittest + +import comtypes +import comtypes.safearray +from comtypes import CLSCTX_INPROC_SERVER, CLSCTX_LOCAL_SERVER +from comtypes.client import CreateObject, GetModule +import comtypes.typeinfo + +GetModule("UIAutomationCore.dll") +from comtypes.gen.UIAutomationClient import CUIAutomation, IUIAutomation + +ComtypesCppTestSrvLib_GUID = "{07D2AEE5-1DF8-4D2C-953A-554ADFD25F99}" + +try: + GetModule((ComtypesCppTestSrvLib_GUID, 1, 0, 0)) + from comtypes.gen.ComtypesCppTestSrvLib import StructRecordParamTest + from comtypes.gen.ComtypesCppTestSrvLib import IDispSafearrayParamTest + + IMPORT_FAILED = False +except (ImportError, OSError): + IMPORT_FAILED = True + + +class Test_midlSAFEARRAY_create(unittest.TestCase): + def test_iunk(self): + extra = pointer(IUIAutomation._iid_) + iuia = CreateObject( + CUIAutomation().IPersist_GetClassID(), + interface=IUIAutomation, + clsctx=CLSCTX_INPROC_SERVER, + ) + sa_type = comtypes.safearray._midlSAFEARRAY(POINTER(IUIAutomation)) + for ptn, sa in [ + ("with extra", sa_type.create([iuia], extra=extra)), + ("without extra", sa_type.create([iuia])), + ]: + with self.subTest(ptn=ptn): + (unpacked,) = sa.unpack() + self.assertIsInstance(unpacked, POINTER(IUIAutomation)) + + @unittest.skipIf(IMPORT_FAILED, "This depends on the out of process COM-server.") + def test_idisp(self): + extra = pointer(IDispSafearrayParamTest._iid_) + idisp = CreateObject( + "Comtypes.DispSafearrayParamTest", + clsctx=CLSCTX_LOCAL_SERVER, + interface=IDispSafearrayParamTest, + ) + sa_type = comtypes.safearray._midlSAFEARRAY(POINTER(IDispSafearrayParamTest)) + for ptn, sa in [ + ("with extra", sa_type.create([idisp], extra=extra)), + ("without extra", sa_type.create([idisp])), + ]: + with self.subTest(ptn=ptn): + (unpacked,) = sa.unpack() + self.assertIsInstance(unpacked, POINTER(IDispSafearrayParamTest)) + + @unittest.skipIf(IMPORT_FAILED, "This depends on the out of process COM-server.") + def test_record(self): + extra = comtypes.typeinfo.GetRecordInfoFromGuids( + *StructRecordParamTest._recordinfo_ + ) + record = StructRecordParamTest() + record.question = "The meaning of life, the universe and everything?" + record.answer = 42 + record.needs_clarification = True + sa_type = comtypes.safearray._midlSAFEARRAY(StructRecordParamTest) + for ptn, sa in [ + ("with extra", sa_type.create([record], extra=extra)), + ("without extra", sa_type.create([record])), + ]: + with self.subTest(ptn=ptn): + (unpacked,) = sa.unpack() + self.assertIsInstance(unpacked, StructRecordParamTest) + self.assertEqual( + unpacked.question, + "The meaning of life, the universe and everything?", + ) + self.assertEqual(unpacked.answer, 42) + self.assertEqual(unpacked.needs_clarification, True) + + def test_ctype(self): + extra = None + cdata = c_int(1) + sa_type = comtypes.safearray._midlSAFEARRAY(c_int) + for ptn, sa in [ + ("with extra", sa_type.create([cdata], extra=extra)), + ("without extra", sa_type.create([cdata])), + ]: + with self.subTest(ptn=ptn): + (unpacked,) = sa.unpack() + self.assertIsInstance(unpacked, int) + self.assertEqual(unpacked, 1) + + +if __name__ == "__main__": + unittest.main() diff --git a/source/CppTestSrv/SERVER.IDL b/source/CppTestSrv/SERVER.IDL index 6b3df39c..9917ce57 100644 --- a/source/CppTestSrv/SERVER.IDL +++ b/source/CppTestSrv/SERVER.IDL @@ -7,6 +7,8 @@ import "oaidl.idl" ; +// Simple structure used for tests related to IRecordInfo or GetRecordInfoFromGuids functionality. +// If a new test would require other fields do NOT modify this structure but add a new structure instead. typedef [uuid(00FABB0F-5691-41A6-B7C1-11606671F8E5)] struct StructRecordParamTest { BSTR question ;