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

Problems that arise when remote functions are defined in interfaces related to structured storage. #607

Open
junkmd opened this issue Aug 26, 2024 · 1 comment

Comments

@junkmd
Copy link
Collaborator

junkmd commented Aug 26, 2024

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.

@junkmd
Copy link
Collaborator Author

junkmd commented Aug 26, 2024

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')
    ),
]

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

No branches or pull requests

1 participant