Skip to content

Conversation

the-snork
Copy link
Contributor

@the-snork the-snork commented Apr 15, 2025

In code generated by makepy, there was no chance to create struct instances, as using Record failed. Convenience constructors are generated now.

class TestStruct1:
	def __new__(cls, *args, **kwargs):
		return pythoncom.GetRecordFromGuids(CLSID, MajorVersion, MinorVersion, LCID, '{7A4CE6A7-7959-4E85-A3C0-B41442FF0F67}')
class TestStruct2:
	def __new__(cls, *args, **kwargs):
		return pythoncom.GetRecordFromGuids(CLSID, MajorVersion, MinorVersion, LCID, '{78F0EA07-B7CF-42EA-A251-A4C6269F76AF}')

In addition, functions using structs as out values could not be called, as the default (missing) value could not be converted to a struct instance. The change creates struct instances automatically in such cases.

	def GetOutStruct(self, ret=pythoncom.Missing):
		if ret == pythoncom.Missing:
			ret = pythoncom.GetRecordFromGuids(CLSID, MajorVersion, MinorVersion, LCID, IID('{7A4CE6A7-7959-4E85-A3C0-B41442FF0F67}'))
		return self._ApplyTypes_(1610743852, 1, (24, 0), ((16420, 2),), 'GetOutStruct', None,ret
			)

@the-snork
Copy link
Contributor Author

@mhammond - that looks like a flaky test, as I did not change anything in that area.

can s/b please verify?

@the-snork the-snork marked this pull request as draft April 16, 2025 08:46
@the-snork
Copy link
Contributor Author

unfortunately one more issue regarding same guids in different typelibs --- meh

@the-snork
Copy link
Contributor Author

activating again;

a problem exists for VT_RECORD without VT_BYREF; most probably that will not work through IDispatch -- at least I tried enough and don't want to continue on that

we will change our server to VT_BYREF...

@the-snork the-snork marked this pull request as ready for review April 16, 2025 13:36
@Avasam
Copy link
Collaborator

Avasam commented Apr 16, 2025

The datetime failure is indeed a flaky test (ref: #2203)

and desc[3]
and desc[3].__class__.__name__ == "PyIID"
):
newVal = f"pythoncom.GetRecordFromGuids(CLSID, MajorVersion, MinorVersion, LCID, {repr(desc[3])})"
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @geppi, do you have any thoughts on this pr?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the delay, I'm in the mountains over the long Easter weekend and can take a detailed look into this earliest on tuesday. My first thought is that I should probably just write some documentation about the functionality we recently introduced for COM Records with PR #2437.
However, I'm not sure where this documentation should live and what format would be required?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like in-code comments parsed by a tool called AutoDuck is used to generate helpfiles. Those helpfiles are then decompiled to extract the HTML and are hosted as a GitHub page:

In #2432 I'm trying to restore shipping the helpfiles (by adding them to the build commands without building pywin32 twice) to users for local no-internet documentation.
In #2577 I added a link to a mirror of AutoDuck's download which included documentation and examples on how to use it. Hopefully that should help with its usage.

@the-snork
Copy link
Contributor Author

@Avasam I wonder why the tests still fail, though the encoding changes are reverted

@geppi
Copy link
Collaborator

geppi commented Apr 22, 2025

The problem with this PR is that it doesn't create proper Python classes:

>>> struct_1 = TestStruct1()
>>> struct_2 = TestStruct2()
>>> type(struct_1) == type(struct_2)
    True

Ooops!

I've opened PR #2578 to add documentation for the COM Record support including the recent improvement of PR #2437.
I hope this does help to clarify the current implementation and what's possible with COM Records.

@the-snork
Copy link
Contributor Author

the-snork commented Apr 22, 2025

@geppi - unfortunately, the mechanism that you describe does not work with makepy generated code (see the unit test part in this pr)

meaning: this was the smallest possible change in my opinion; of course, a larger change is possible where proper Python records are used.

@geppi
Copy link
Collaborator

geppi commented Apr 22, 2025

I'm afraid I don't understand the problem.

In code generated by makepy, there was no chance to create struct instances, as using Record failed.

Could you please provide an example what fails?

Also if you follow the recipe to create subclasses of pythoncom.com_record for the convenience constructors, you should be good to go.

@the-snork
Copy link
Contributor Author

We are using code generated by makepy, so actually the generated code shall contain all necessary constructors (in my opinion).

Have a look at the IDL changes and the tests within this PR.

What actually does not work (without modification in build.py) is:

coclass.GetOutStruct()

The default argument results in a TypeError "Only com_record objects can be used as records", as it is a special marker and no record instance.

The other problem we experienced is not that easy to reproduce right now with that minimal test.

Consider this:

interf = module.IPyCOMTest(coclass)
interf.GetOutStruct(win32com.client.Record('TestStruct1', interf))

In this scenario, a file is generated by gencache (which is actually not necessary, since everything should be already present in the file that has been generated with makepy). In our production environment, it happened that this file could not be read afterwards and we ended up with an import error. As said, not reproducible within this small test right now.

@the-snork
Copy link
Contributor Author

the-snork commented Apr 23, 2025

I debugged that in our scenario:

win32com.client.Record
-->
gencache.EnsureDispatch(object) does not run into the if clause.

In the end, no Python file is generated and the import fails.

My temp directory contains the following files in gen_py\3.13:
__init__.py
dicts.dat (10 bytes long)

Nothing more.

@geppi --- how to proceed?

@geppi
Copy link
Collaborator

geppi commented Apr 23, 2025

I would suggest to fix the code that creates the classes for the records as a first step.

Copy link
Owner

@mhammond mhammond left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Formally marking as "request changes" as per the existing comments.

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.

4 participants