comtypes
comtypes copied to clipboard
Problems that arise when remote functions are defined in interfaces related to structured storage.
Some of methods in the interfaces generated by GetModule are based on remote-side information, which makes them uncallable from the local side.
See also #604.
IStorage
OpenStream and RemoteOpenStream
cbReserved1 is not needed when calling from the local side. If we specify cbReserved1 as 0 and call from the local side, a COMError with the error code STG_E_INVALIDPOINTER (-2147287031, 0x80030009) will be raised.
EnumElements and RemoteEnumElements
cbReserved2 is not needed when calling from the local side. If we specify cbReserved2 as 0 and call from the local side, a COMError with the error code STG_E_INVALIDPOINTER (-2147287031, 0x80030009) will be raised.
IEnumSTATSTG
Next and RemoteNext
Because RemoteNext is defined instead of Next, __iter__, __next__, and __getitem__ are not implemented in the interface, so it does NOT become an iterator or index-accessible object.
Appendix
CopyTo and RemoteCopyTo of IStorage and CopyTo and RemoteCopyTo of IStream have the same parameters on both the remote side and the local side, so it is possible to call the method even if it is defined based on the information from RemoteCopyTo.
Reproducers
We can reproduce the COMError by adding these tests to test_storage.Test_IStorage.
def test_RemoteOpenStream(self):
storage = self._create_docfile()
created_stream = storage.CreateStream("example", self.CREATE_STM_FLAG, 0, 0)
test_data = "Some data".encode("utf-8")
pv = (c_ubyte * len(test_data)).from_buffer(bytearray(test_data))
created_stream.RemoteWrite(pv, len(test_data))
created_stream.Commit(STGC_DEFAULT)
del created_stream
storage.RemoteOpenStream("example", 0, None, self.OPEN_STM_FLAG, 0) # error
def test_RemoteEnumElements(self):
storage = self._create_docfile()
storage.RemoteEnumElements(0, 0, None, 0) # error
======================================================================
ERROR: test_RemoteEnumElements (test_storage.Test_IStorage)
----------------------------------------------------------------------
Traceback (most recent call last):
File "D:\a\comtypes\comtypes\comtypes\test\test_storage.py", line 141, in test_RemoteEnumElements
storage.RemoteEnumElements(0, 0, None, 0) # error
_ctypes.COMError: (-2147287031, 'Invalid pointer error.', (None, None, None, 0, None))
======================================================================
ERROR: test_RemoteOpenStream (test_storage.Test_IStorage)
----------------------------------------------------------------------
Traceback (most recent call last):
File "D:\a\comtypes\comtypes\comtypes\test\test_storage.py", line 137, in test_RemoteOpenStream
storage.RemoteOpenStream("example", 0, None, self.OPEN_STM_FLAG, 0) # error
_ctypes.COMError: (-2147287031, 'Invalid pointer error.', (None, None, None, 0, None))
Since the return value of RemoteEnumElements cannot be obtained, it is not possible to test whether IEnumSTATSTG works as an iterator. However, by looking at the generated wrapper module, it can be confirmed that __iter__ is not present.
class IEnumSTATSTG(comtypes.gen._00020430_0000_0000_C000_000000000046_0_2_0.IUnknown):
_case_insensitive_ = True
_iid_ = GUID('{0000000D-0000-0000-C000-000000000046}')
_idlflags_ = []
if TYPE_CHECKING: # commembers
def RemoteNext(self, celt: hints.Incomplete) -> hints.Tuple[hints.Incomplete, hints.Incomplete]: ...
def Skip(self, celt: hints.Incomplete) -> hints.Hresult: ...
def Reset(self) -> hints.Hresult: ...
def Clone(self) -> 'IEnumSTATSTG': ...
IEnumSTATSTG._methods_ = [
COMMETHOD(
[],
HRESULT,
'RemoteNext',
(['in'], c_ulong, 'celt'),
(['out'], POINTER(tagSTATSTG), 'rgelt'),
(['out'], POINTER(c_ulong), 'pceltFetched')
),
COMMETHOD(
[],
HRESULT,
'Skip',
(['in'], c_ulong, 'celt')
),
COMMETHOD([], HRESULT, 'Reset'),
COMMETHOD(
[],
HRESULT,
'Clone',
(['out'], POINTER(POINTER(IEnumSTATSTG)), 'ppenum')
),
]