You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
95 lines
3.2 KiB
95 lines
3.2 KiB
import unittest
|
|
|
|
from ctypes import PyDLL, py_object, c_void_p, byref, POINTER
|
|
from ctypes.wintypes import BOOL
|
|
|
|
from comtypes import IUnknown
|
|
from comtypes.client import CreateObject
|
|
from comtypes.automation import IDispatch
|
|
from comtypes.test import requires
|
|
|
|
requires("pythoncom")
|
|
import pythoncom
|
|
import win32com.client
|
|
|
|
# We use the PyCom_PyObjectFromIUnknown function in pythoncom25.dll to
|
|
# convert a comtypes COM pointer into a pythoncom COM pointer.
|
|
# Fortunately this function is exported by the dll...
|
|
#
|
|
# This is the C prototype; we must pass 'True' as third argument:
|
|
#
|
|
# PyObject *PyCom_PyObjectFromIUnknown(IUnknown *punk, REFIID riid, BOOL bAddRef)
|
|
|
|
_PyCom_PyObjectFromIUnknown = PyDLL(pythoncom.__file__).PyCom_PyObjectFromIUnknown
|
|
_PyCom_PyObjectFromIUnknown.restype = py_object
|
|
_PyCom_PyObjectFromIUnknown.argtypes = (POINTER(IUnknown), c_void_p, BOOL)
|
|
|
|
def comtypes2pywin(ptr, interface=None):
|
|
"""Convert a comtypes pointer 'ptr' into a pythoncom
|
|
PyI<interface> object.
|
|
|
|
'interface' specifies the interface we want; it must be a comtypes
|
|
interface class. The interface must be implemented by the object;
|
|
and the interface must be known to pythoncom.
|
|
|
|
If 'interface' is specified, comtypes.IUnknown is used.
|
|
"""
|
|
if interface is None:
|
|
interface = IUnknown
|
|
return _PyCom_PyObjectFromIUnknown(ptr, byref(interface._iid_), True)
|
|
|
|
################################################################
|
|
|
|
def comtypes_get_refcount(ptr):
|
|
"""Helper function for testing: return the COM reference count of
|
|
a comtypes COM object"""
|
|
ptr.AddRef()
|
|
return ptr.Release()
|
|
|
|
from comtypes import COMObject
|
|
|
|
class MyComObject(COMObject):
|
|
"""A completely trivial COM object implementing IDispatch. Calling
|
|
any methods will return the error code E_NOTIMPL (except the
|
|
IUnknown methods; they are implemented in the base class."""
|
|
_com_interfaces_ = [IDispatch]
|
|
|
|
################################################################
|
|
|
|
class Test(unittest.TestCase):
|
|
def tearDown(self):
|
|
if hasattr(self, "ie"):
|
|
self.ie.Quit()
|
|
del self.ie
|
|
|
|
def test_mycomobject(self):
|
|
o = MyComObject()
|
|
p = comtypes2pywin(o, IDispatch)
|
|
disp = win32com.client.Dispatch(p)
|
|
self.assertEqual(repr(disp), "<COMObject <unknown>>")
|
|
|
|
def test_ie(self):
|
|
# Convert a comtypes COM interface pointer into a win32com COM
|
|
# pointer.
|
|
ie = self.ie = CreateObject("InternetExplorer.Application")
|
|
# The COM refcount of the created object is 1:
|
|
self.assertEqual(comtypes_get_refcount(ie), 1)
|
|
# IE starts invisible:
|
|
self.assertEqual(ie.Visible, False)
|
|
|
|
# Create a pythoncom PyIDispatch object from it:
|
|
p = comtypes2pywin(ie, interface=IDispatch)
|
|
self.assertEqual(comtypes_get_refcount(ie), 2)
|
|
|
|
# Make it usable...
|
|
disp = win32com.client.Dispatch(p)
|
|
self.assertEqual(comtypes_get_refcount(ie), 2)
|
|
self.assertEqual(disp.Visible, False)
|
|
|
|
# Cleanup and make sure that the COM refcounts are correct
|
|
del p, disp
|
|
self.assertEqual(comtypes_get_refcount(ie), 1)
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|