Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement the creation of SAFEARRAY(VT_RECORD) from a sequence of COM Records #2317

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

geppi
Copy link

@geppi geppi commented Jul 25, 2024

and the possibility to use instances of this type as COM Record fields.

This PR addresses the following issue.
Given a COM interface that defines a COM Record of the following type in the IDL-file:

     typedef [uuid(xxxxx)]
     struct tagT_RECORD_A {
         SAFEARRAY(T_RECORD_B) array_of_records;
         <some-more-simple-type-fields>
     } T_RECORD_A

where the T_RECORD_B is another COM Record type with fields of just simple types,
there is currently no way to assign the required SAFEARRAY instance to the array_of_records field of a T_RECORD_A instance.

The following code successfully creates all record instances.

     import pythoncom
     import win32.client
     from win32com.client import gencache, Record

     mod = gencache.EnsureModule('{XXXXX}', X, Y, Z)
     comp = win32com.client.Dispatch("SomeProgID", clsctx=pythoncom.CLSCTX_LOCAL_SERVER)
     rec_a = Record("T_RECORD_A", comp)
     rec_b_1 = Record("T_RECORD_B", comp)
     rec_b_3 = Record("T_RECORD_B", comp)

However, assigning to the array_of_records field of the T_RECORD_A instance raises an exception:

     rec_a.array_of_records = [rec_b_1, rec_b_2]
         com_error: (-2147024809,  'The parameter is incorrect.', None, None)

This happens because the code is currently creating a SAFEARRAY(VT_VARIANT) with VARIANT elements of type VT_RECORD while the COM-server expects a SAFEARRAY(VT_RECORD), i.e. COM Record elements.

The modifications of the code implement the required logic to create a SAFEARRAY(VT_RECORD) and assign this as the value to a Record field.

To retrieve the value of such a Record field, the existing code of the getattro method in PyRecord.cpp was fixed.
I'm wondering if the code in the else block starting at line 500:

    else if (V_VT(&vret) == (VT_BYREF | VT_ARRAY | VT_RECORD)) {

was ever tested or used because I cannot see how it could have worked.

of COM Records and the possibility to use instances of this type
as COM Record fields.
@geppi
Copy link
Author

geppi commented Jul 26, 2024

To progress this PR I have the same questions as in #2310 (comment)

@geppi
Copy link
Author

geppi commented Jul 31, 2024

Now that I have managed to compile the C++ PyComTest server-dll with Visual Studio 2022 as stated in #2310 (comment) I will try to implement a similar test case for this PR, if this makes sense.

@geppi
Copy link
Author

geppi commented Aug 1, 2024

I've added the method VerifyArrayOfStructs to the IPyCOMTest interface to implement a unittest for this PR.
Normally a COM interface should not be modified as soon as it is published. However, since this is a test interface purely internal to this project, it is not really published and I do not see a problem in extending the existing interface. If absolutely desired the new method could of course be moved into a new interface but this would also require an additional component to implement the method.

The test case has been added to testPyComTest.py and is limited to the Generated case.
In CI the test is not triggered with the current github actions workflow definition.
However, I did run the test locally and it passes.

If the changes of commit 78be16b are reverted, the test fails.

@Avasam Avasam requested a review from mhammond August 2, 2024 03:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant