Pure Python COM package for Windows COM automation and interoperability
88
Framework for implementing COM servers in Python, including class factories, object registration, connection point support for events, and both in-process and local server architectures.
Foundation classes for implementing COM objects and coclasses with proper COM lifetime management.
class COMObject:
"""Base class for implementing COM objects in Python."""
def __init__(self):
"""Initialize COM object with reference counting."""
def QueryInterface(self, interface):
"""
Query for interface implementation.
Args:
interface (type): Interface class to query for
Returns:
Interface implementation or None
"""
def AddRef(self):
"""
Increment reference count.
Returns:
int: New reference count
"""
def Release(self):
"""
Decrement reference count.
Returns:
int: New reference count (0 if object destroyed)
"""
class CoClass(COMObject):
"""Base class for COM coclasses with metaclass support."""
_reg_clsid_: str # Class identifier for registration
_reg_progid_: str # Programmatic identifier
_reg_desc_: str # Description for registry
_reg_clsctx_: int # Class context flags
def __init__(self):
"""Initialize coclass with proper COM semantics."""Standard COM class factory interface for creating object instances.
class IClassFactory(IUnknown):
"""Standard interface for creating COM object instances."""
def CreateInstance(self, outer, interface):
"""
Create new instance of COM object.
Args:
outer (IUnknown, optional): Outer object for aggregation
interface (type): Interface to query for on new instance
Returns:
New COM object instance
Raises:
COMError: If creation fails or aggregation not supported
"""
def LockServer(self, lock):
"""
Lock server in memory to prevent unloading.
Args:
lock (bool): True to lock, False to unlock
"""Functions for registering COM objects in the Running Object Table and with the system.
def RegisterActiveObject(comobj, weak=True):
"""
Register COM object as active for client access.
Args:
comobj: COM object instance to register
weak (bool): Use weak reference to allow object cleanup
Returns:
int: Registration token for later revocation
"""
def RevokeActiveObject(token):
"""
Remove object from Running Object Table.
Args:
token (int): Registration token from RegisterActiveObject
"""Different server implementation patterns supported by comtypes.
# From comtypes.server.inprocserver module
def DllCanUnloadNow():
"""
Determine if DLL can be unloaded.
Returns:
HRESULT: S_OK if can unload, S_FALSE if still in use
"""
def DllGetClassObject(clsid, iid):
"""
Get class factory for specified class.
Args:
clsid (GUID): Class identifier
iid (GUID): Interface identifier (usually IClassFactory)
Returns:
Class factory instance
"""
# Note: DllRegisterServer and DllUnregisterServer are not implemented
# in comtypes. These functions would need to be implemented by the
# application developer for COM server registration.# From comtypes.server.localserver module
class LocalServer:
"""Framework for implementing local (out-of-process) COM servers."""
def run(self, classobjects):
"""
Start local server with registered class objects.
Args:
classobjects (dict): Mapping of CLSIDs to class factory objects
"""
def run_sta(self):
"""Run server in single-threaded apartment mode."""
def run_mta(self):
"""Run server in multi-threaded apartment mode."""
def Lock(self):
"""Increment server lock count."""
def Unlock(self):
"""Decrement server lock count."""Support for COM events and callbacks through connection point interfaces.
class IConnectionPointContainer(IUnknown):
"""Container interface for managing connection points."""
def EnumConnectionPoints(self):
"""
Get enumerator for all connection points.
Returns:
IEnumConnectionPoints: Connection point enumerator
"""
def FindConnectionPoint(self, iid):
"""
Find connection point for specific interface.
Args:
iid (GUID): Event interface identifier
Returns:
IConnectionPoint: Connection point for interface
"""
class IConnectionPoint(IUnknown):
"""Individual connection point for specific event interface."""
def GetConnectionInterface(self):
"""
Get interface ID for this connection point.
Returns:
GUID: Event interface identifier
"""
def GetConnectionPointContainer(self):
"""
Get parent connection point container.
Returns:
IConnectionPointContainer: Parent container
"""
def Advise(self, sink):
"""
Connect event sink to receive events.
Args:
sink: Object implementing event interface
Returns:
int: Connection cookie for later disconnection
"""
def Unadvise(self, cookie):
"""
Disconnect event sink.
Args:
cookie (int): Connection cookie from Advise
"""
def EnumConnections(self):
"""
Get enumerator for active connections.
Returns:
IEnumConnections: Active connection enumerator
"""Helper functions for COM server registration and unregistration.
# From comtypes.server.register module
def register(cls):
"""
Register COM class in system registry.
Args:
cls (type): CoClass to register (must have registration attributes)
"""
def unregister(cls):
"""
Remove COM class from system registry.
Args:
cls (type): CoClass to unregister
"""import comtypes
from comtypes.server import COMObject
class MyComObject(COMObject):
"""Simple COM object implementation."""
# Define supported interfaces
_com_interfaces_ = [comtypes.IUnknown]
def __init__(self):
super().__init__()
print("COM object created")
def my_method(self):
"""Custom method implementation."""
return "Hello from COM object"
# Create and use object
obj = MyComObject()
result = obj.my_method()
print(result)import comtypes
from comtypes.server import CoClass
from comtypes.GUID import GUID
# Define custom interface
class IMyInterface(comtypes.IUnknown):
_iid_ = GUID("{12345678-1234-5678-9ABC-123456789ABC}")
_methods_ = [
comtypes.STDMETHOD(comtypes.HRESULT, "DoSomething",
(['in'], comtypes.c_int, "value"))
]
class MyCoClass(CoClass):
"""COM coclass with registration information."""
# Registration metadata
_reg_clsid_ = "{87654321-4321-8765-CBA9-987654321CBA}"
_reg_progid_ = "MyApp.MyCoClass.1"
_reg_desc_ = "My COM CoClass"
_reg_clsctx_ = comtypes.CLSCTX_INPROC_SERVER
# Supported interfaces
_com_interfaces_ = [IMyInterface]
def DoSomething(self, value):
"""Implementation of interface method."""
print(f"DoSomething called with value: {value}")
return comtypes.S_OK
# Register the class (requires admin privileges)
from comtypes.server.register import register_class
register_class(MyCoClass)import comtypes
from comtypes.server import COMObject
from comtypes.connectionpoints import IConnectionPointContainer, IConnectionPoint
# Define event interface
class IMyEvents(comtypes.IUnknown):
_iid_ = GUID("{11111111-2222-3333-4444-555555555555}")
_methods_ = [
comtypes.COMMETHOD([], comtypes.HRESULT, "OnSomethingHappened",
(['in'], comtypes.BSTR, "message"))
]
class MyEventSource(COMObject):
"""COM object that fires events."""
_com_interfaces_ = [IConnectionPointContainer]
_outgoing_interfaces_ = [IMyEvents]
def __init__(self):
super().__init__()
self._connections = {}
def fire_event(self, message):
"""Fire event to all connected sinks."""
for sink in self._connections.values():
try:
sink.OnSomethingHappened(message)
except Exception as e:
print(f"Error firing event: {e}")
# Connection point implementation would go here
# (simplified for example)# myserver.py - In-process COM server
import comtypes
from comtypes.server.inprocserver import *
class MyInProcServer(CoClass):
_reg_clsid_ = "{AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE}"
_reg_progid_ = "MyServer.Application.1"
_reg_desc_ = "My In-Process COM Server"
_com_interfaces_ = [comtypes.IUnknown]
def get_message(self):
return "Hello from in-process server"
# Register exported classes
_reg_classes_ = [MyInProcServer]
# Build as DLL and register with:
# regsvr32 myserver.dll# localserver.py - Local COM server
import comtypes
from comtypes.server.localserver import LocalServer
class MyLocalServer(CoClass):
_reg_clsid_ = "{FFFFFFFF-EEEE-DDDD-CCCC-BBBBBBBBBBBB}"
_reg_progid_ = "MyLocalServer.Application.1"
_reg_desc_ = "My Local COM Server"
_com_interfaces_ = [comtypes.IUnknown]
def get_data(self):
return "Data from local server"
if __name__ == "__main__":
# Create and run local server
server = LocalServer()
server.register_class(MyLocalServer)
print("Starting local COM server...")
server.run() # Blocks until shutdownimport comtypes
from comtypes.server import IClassFactory, COMObject
class MyClassFactory(COMObject):
"""Custom class factory implementation."""
_com_interfaces_ = [IClassFactory]
def __init__(self, target_class):
super().__init__()
self.target_class = target_class
def CreateInstance(self, outer, interface):
"""Create new instance of target class."""
if outer is not None:
raise comtypes.COMError(comtypes.hresult.CLASS_E_NOAGGREGATION)
# Create instance
instance = self.target_class()
# Query for requested interface
return instance.QueryInterface(interface)
def LockServer(self, lock):
"""Lock/unlock server in memory."""
# Implementation depends on server type
passInstall with Tessl CLI
npx tessl i tessl/pypi-comtypesevals
scenario-1
scenario-2
scenario-3
scenario-4
scenario-5
scenario-6
scenario-7
scenario-8
scenario-9
scenario-10