Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions comtypes/test/monikers_helper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from ctypes import HRESULT, POINTER, OleDLL, c_wchar_p
from ctypes.wintypes import DWORD

from comtypes import GUID, IUnknown

# https://learn.microsoft.com/en-us/windows/win32/api/objidl/ne-objidl-mksys
MKSYS_ITEMMONIKER = 4

CLSID_AntiMoniker = GUID("{00000305-0000-0000-c000-000000000046}")
CLSID_ItemMoniker = GUID("{00000304-0000-0000-c000-000000000046}")

ROTFLAGS_ALLOWANYCLIENT = 1

LPOLESTR = LPCOLESTR = c_wchar_p

_ole32 = OleDLL("ole32")

_CreateItemMoniker = _ole32.CreateItemMoniker
_CreateItemMoniker.argtypes = [LPCOLESTR, LPCOLESTR, POINTER(POINTER(IUnknown))]
_CreateItemMoniker.restype = HRESULT

_CreateBindCtx = _ole32.CreateBindCtx
_CreateBindCtx.argtypes = [DWORD, POINTER(POINTER(IUnknown))]
_CreateBindCtx.restype = HRESULT

_GetRunningObjectTable = _ole32.GetRunningObjectTable
_GetRunningObjectTable.argtypes = [DWORD, POINTER(POINTER(IUnknown))]
_GetRunningObjectTable.restype = HRESULT

# Common COM Errors from Moniker/Binding Context operations
MK_E_UNAVAILABLE = -2147221021 # 0x800401E3
66 changes: 66 additions & 0 deletions comtypes/test/test_bctx.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import contextlib
import unittest
from _ctypes import COMError
from ctypes import POINTER, byref

from comtypes import GUID, hresult
from comtypes.client import CreateObject, GetModule
from comtypes.test.monikers_helper import (
ROTFLAGS_ALLOWANYCLIENT,
_CreateBindCtx,
_CreateItemMoniker,
_GetRunningObjectTable,
)

with contextlib.redirect_stdout(None): # supress warnings
GetModule("msvidctl.dll")
from comtypes.gen import MSVidCtlLib as msvidctl
from comtypes.gen.MSVidCtlLib import IBindCtx, IMoniker, IRunningObjectTable


def _create_item_moniker(delim: str, item: str) -> IMoniker:
mon = POINTER(IMoniker)()
_CreateItemMoniker(delim, item, byref(mon))
return mon # type: ignore


def _create_bctx() -> IBindCtx:
bctx = POINTER(IBindCtx)()
# The first parameter is reserved and must be 0.
_CreateBindCtx(0, byref(bctx))
return bctx # type: ignore


def _create_rot() -> IRunningObjectTable:
rot = POINTER(IRunningObjectTable)()
# The first parameter is reserved and must be 0.
_GetRunningObjectTable(0, byref(rot))
return rot # type: ignore


class Test_EnumObjectParam(unittest.TestCase):
def test_cannot_call(self):
bctx = _create_bctx()
with self.assertRaises(COMError) as cm:
# calling `EnumObjectParam` results in a return value of E_NOTIMPL.
# https://learn.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-ibindctx-enumobjectparam#notes-to-callers
bctx.EnumObjectParam()
self.assertEqual(cm.exception.hresult, hresult.E_NOTIMPL)


class Test_GetRunningObjectTable(unittest.TestCase):
def test_returns_rot(self):
vidctl = CreateObject(msvidctl.MSVidCtl, interface=msvidctl.IMSVidCtl)
item_id = str(GUID.create_new())
mon = _create_item_moniker("!", item_id)
bctx = _create_bctx()
# Before registering: should NOT be running
rot_from_bctx = bctx.GetRunningObjectTable()
self.assertIsInstance(rot_from_bctx, IRunningObjectTable)
rot_from_func = _create_rot()
dw_reg = rot_from_func.Register(ROTFLAGS_ALLOWANYCLIENT, vidctl, mon)
# After registering: should be running
self.assertEqual(rot_from_bctx.IsRunning(mon), hresult.S_OK)
rot_from_func.Revoke(dw_reg)
# After revoking: should NOT be running again
self.assertEqual(rot_from_bctx, rot_from_func)
56 changes: 20 additions & 36 deletions comtypes/test/test_monikers.py → comtypes/test/test_moniker.py
Original file line number Diff line number Diff line change
@@ -1,35 +1,24 @@
import contextlib
import unittest
from _ctypes import COMError
from ctypes import HRESULT, POINTER, OleDLL, byref, c_wchar_p
from ctypes.wintypes import DWORD
from ctypes import POINTER, byref

from comtypes import GUID, hresult
from comtypes.client import CreateObject, GetModule
from comtypes.test.monikers_helper import (
MKSYS_ITEMMONIKER,
ROTFLAGS_ALLOWANYCLIENT,
CLSID_AntiMoniker,
CLSID_ItemMoniker,
_CreateBindCtx,
_CreateItemMoniker,
_GetRunningObjectTable,
)

with contextlib.redirect_stdout(None): # supress warnings
GetModule("msvidctl.dll")
from comtypes.gen import MSVidCtlLib as msvidctl
from comtypes.gen.MSVidCtlLib import IBindCtx, IMoniker, IRunningObjectTable

MKSYS_ITEMMONIKER = 4
ROTFLAGS_ALLOWANYCLIENT = 1
LPOLESTR = LPCOLESTR = c_wchar_p

_ole32 = OleDLL("ole32")

_CreateItemMoniker = _ole32.CreateItemMoniker
_CreateItemMoniker.argtypes = [LPCOLESTR, LPCOLESTR, POINTER(POINTER(IMoniker))]
_CreateItemMoniker.restype = HRESULT

_CreateBindCtx = _ole32.CreateBindCtx
_CreateBindCtx.argtypes = [DWORD, POINTER(POINTER(IBindCtx))]
_CreateBindCtx.restype = HRESULT

_GetRunningObjectTable = _ole32.GetRunningObjectTable
_GetRunningObjectTable.argtypes = [DWORD, POINTER(POINTER(IRunningObjectTable))]
_GetRunningObjectTable.restype = HRESULT


def _create_item_moniker(delim: str, item: str) -> IMoniker:
mon = POINTER(IMoniker)()
Expand All @@ -51,34 +40,29 @@ def _create_rot() -> IRunningObjectTable:
return rot # type: ignore


class Test_IMoniker(unittest.TestCase):
def test_IsSystemMoniker(self):
class Test_IsSystemMoniker_GetDisplayName_Inverse(unittest.TestCase):
def test_item(self):
item_id = str(GUID.create_new())
mon = _create_item_moniker("!", item_id)
self.assertEqual(mon.IsSystemMoniker(), MKSYS_ITEMMONIKER)


class Test_IBindCtx(unittest.TestCase):
def test_EnumObjectParam(self):
bctx = _create_bctx()
with self.assertRaises(COMError) as err_ctx:
# calling `EnumObjectParam` results in a return value of E_NOTIMPL.
# https://learn.microsoft.com/en-us/windows/win32/api/objidl/nf-objidl-ibindctx-enumobjectparam#notes-to-callers
bctx.EnumObjectParam()
self.assertEqual(err_ctx.exception.hresult, hresult.E_NOTIMPL)
self.assertEqual(mon.GetDisplayName(bctx, None), f"!{item_id}")
self.assertEqual(mon.GetClassID(), CLSID_ItemMoniker)
self.assertEqual(mon.Inverse().GetClassID(), CLSID_AntiMoniker)


class Test_IRunningObjectTable(unittest.TestCase):
def test_register_and_revoke_item_moniker(self):
class Test_IsRunning(unittest.TestCase):
def test_item(self):
vidctl = CreateObject(msvidctl.MSVidCtl, interface=msvidctl.IMSVidCtl)
item_id = str(GUID.create_new())
mon = _create_item_moniker("!", item_id)
rot = _create_rot()
bctx = _create_bctx()
# Before registering: should NOT be running
self.assertEqual(mon.IsRunning(bctx, None, None), hresult.S_FALSE)
dw_reg = rot.Register(ROTFLAGS_ALLOWANYCLIENT, vidctl, mon)
# After registering: should be running
self.assertEqual(mon.IsRunning(bctx, None, None), hresult.S_OK)
self.assertEqual(f"!{item_id}", mon.GetDisplayName(bctx, None))
self.assertEqual(rot.GetObject(mon).QueryInterface(msvidctl.IMSVidCtl), vidctl)
rot.Revoke(dw_reg)
# After revoking: should NOT be running again
self.assertEqual(mon.IsRunning(bctx, None, None), hresult.S_FALSE)
64 changes: 64 additions & 0 deletions comtypes/test/test_rot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import contextlib
import unittest
from _ctypes import COMError
from ctypes import POINTER, byref

from comtypes import GUID, hresult
from comtypes.client import CreateObject, GetModule
from comtypes.test.monikers_helper import (
MK_E_UNAVAILABLE,
ROTFLAGS_ALLOWANYCLIENT,
_CreateBindCtx,
_CreateItemMoniker,
_GetRunningObjectTable,
)

with contextlib.redirect_stdout(None): # supress warnings
GetModule("msvidctl.dll")
from comtypes.gen import MSVidCtlLib as msvidctl
from comtypes.gen.MSVidCtlLib import IBindCtx, IMoniker, IRunningObjectTable


def _create_item_moniker(delim: str, item: str) -> IMoniker:
mon = POINTER(IMoniker)()
_CreateItemMoniker(delim, item, byref(mon))
return mon # type: ignore


def _create_bctx() -> IBindCtx:
bctx = POINTER(IBindCtx)()
# The first parameter is reserved and must be 0.
_CreateBindCtx(0, byref(bctx))
return bctx # type: ignore


def _create_rot() -> IRunningObjectTable:
rot = POINTER(IRunningObjectTable)()
# The first parameter is reserved and must be 0.
_GetRunningObjectTable(0, byref(rot))
return rot # type: ignore


class Test_Register_Revoke_GetObject_IsRunning(unittest.TestCase):
def test_item(self):
vidctl = CreateObject(msvidctl.MSVidCtl, interface=msvidctl.IMSVidCtl)
item_id = str(GUID.create_new())
mon = _create_item_moniker("!", item_id)
rot = _create_rot()
bctx = _create_bctx()
# Before registering: should NOT be running
with self.assertRaises(COMError) as cm:
rot.GetObject(mon)
self.assertEqual(cm.exception.hresult, MK_E_UNAVAILABLE)
self.assertEqual(rot.IsRunning(mon), hresult.S_FALSE)
# After registering: should be running
dw_reg = rot.Register(ROTFLAGS_ALLOWANYCLIENT, vidctl, mon)
self.assertEqual(rot.IsRunning(mon), hresult.S_OK)
self.assertEqual(mon.IsRunning(bctx, None, None), hresult.S_OK)
self.assertEqual(rot.GetObject(mon).QueryInterface(msvidctl.IMSVidCtl), vidctl)
rot.Revoke(dw_reg)
# After revoking: should NOT be running again
self.assertEqual(rot.IsRunning(mon), hresult.S_FALSE)
with self.assertRaises(COMError) as cm:
rot.GetObject(mon)
self.assertEqual(cm.exception.hresult, MK_E_UNAVAILABLE)