Open bytesized opened 1 week ago
Hi, @bytesized.
Indeed, those who are familiar with COM and are used to explicitly releasing COM interface pointers that are no longer in use might find this package's implementation weird.
The originator of this package likely aimed to make it easier for users to work with the COM framework by using atexit
and __del__
to trigger cleanup operations, so that users would not need to manually release COM pointers that are no longer in use.
Through the functionality of metaclasses, when an instance of an IUnknown
Python object is destroyed and __del__
is called, Release
is automatically triggered.
https://github.com/enthought/comtypes/blob/3e3977d868e21b2b1f17c55c53434349b846ffc8/comtypes/_post_coinit/unknwn.py#L371-L386
Additionally, it's worth mentioning that when the _shutdown
callback function registered with atexit
is invoked, comtypes
not only calls the Release
method on each COM interface pointer but also calls CoUninitialize
.
https://github.com/enthought/comtypes/blob/3e3977d868e21b2b1f17c55c53434349b846ffc8/comtypes/__init__.py#L180
https://github.com/enthought/comtypes/blob/3e3977d868e21b2b1f17c55c53434349b846ffc8/comtypes/_post_coinit/unknwn.py#L25-L47
https://github.com/enthought/comtypes/blob/3e3977d868e21b2b1f17c55c53434349b846ffc8/comtypes/_post_coinit/unknwn.py#L54-L66
It is true that there is no documentation indicating that users generally do not need to manually call Release
, CoInitialize
at startup, or CoUninitialize
at shutdown.
We welcome PRs to add explanations about these behaviors, so please feel free to contribute.
In the past, changes were made in #215 to define _shutdown
as a private function, allowing cleanup operations to be unregister
ed from atexit
.
By temporarily modifying IUnknown._com_shutting_down
manually, it is also possible to prevent Release
from being called when __del__
is invoked.
However, I should mention that if alternative cleanup operations are not performed or the modified class attributes are not restored, it will be necessary to manually and properly release the COM pointers present in the running Python interpreter.
Coming from
C++
COM, where very simple COM usage looks likeit was highly confusing to try out this library for the first time and do something like this
I tried looking through the documentation for
CreateObject
and using the search bar to look for "Release" and a few similar search terms, but couldn't find anything related.This feels weird since
AddRef
andRelease
are standard COM methods and are made available to the interface consumer. They just don't quite seem to work as expected. Normally, things are handed to you (byCoCreateInstance
, for example) alreadyAddRef
ed. So you have toRelease
them, plus an additionalRelease
for every additionalAddRef
. But this implementation does not match this; it's strictly oneRelease
perAddRef
.It seems like if this COM library is going to differ from the usual COM conventions, the documentation should at least mention it.