Pure Python COM package for Windows COM automation and interoperability
88
Helper functions, type conversion utilities, SafeArray support, specialized interfaces for persistence and shell integration, error handling, and type library processing tools.
Low-level utilities for memory manipulation and type conversion in COM operations.
def byref_at(obj, offset):
"""
Create ctypes reference at memory offset.
Args:
obj: ctypes object
offset (int): Byte offset from object start
Returns:
ctypes reference pointing to offset location
"""
def cast_field(struct, fieldname, fieldtype):
"""
Cast structure field to different type.
Args:
struct: ctypes structure instance
fieldname (str): Name of field to cast
fieldtype (type): Target type for casting
Returns:
Field value cast to new type
"""Support for COM SafeArrays with automatic conversion to NumPy arrays when available.
def _midlSAFEARRAY(itemtype):
"""
Create SAFEARRAY type for specified item type.
Args:
itemtype (type): Element type for array (e.g., c_int, c_double)
Returns:
SAFEARRAY type class for creating arrays of itemtype
"""
def safearray_as_ndarray(sa):
"""
Context manager for accessing SafeArray as NumPy array.
Args:
sa: SafeArray instance
Returns:
Context manager yielding NumPy array view
Usage:
with safearray_as_ndarray(safe_array) as np_array:
# Work with NumPy array
result = np_array.sum()
"""Enhanced error handling with detailed COM error information.
class IErrorInfo(IUnknown):
"""Interface for retrieving rich error information."""
def GetGUID(self):
"""
Get GUID of interface that defined the error.
Returns:
GUID: Interface identifier
"""
def GetSource(self):
"""
Get source of error (application name).
Returns:
str: Error source description
"""
def GetDescription(self):
"""
Get textual description of error.
Returns:
str: Error description
"""
def GetHelpFile(self):
"""
Get path to help file with error information.
Returns:
str: Help file path
"""
def GetHelpContext(self):
"""
Get help context ID for error.
Returns:
int: Help context identifier
"""
class ICreateErrorInfo(IUnknown):
"""Interface for creating error information objects."""
def SetGUID(self, guid):
"""Set interface GUID for error."""
def SetSource(self, source):
"""Set error source description."""
def SetDescription(self, description):
"""Set error description text."""
def SetHelpFile(self, helpfile):
"""Set help file path."""
def SetHelpContext(self, context):
"""Set help context ID."""Comprehensive HRESULT error code definitions and utility functions.
# Success codes
S_OK: int # 0 - Success
S_FALSE: int # 1 - Success but false result
# General error codes
E_UNEXPECTED: int # Unexpected failure
E_NOTIMPL: int # Not implemented
E_NOINTERFACE: int # Interface not supported
E_POINTER: int # Invalid pointer
E_FAIL: int # Unspecified failure
E_INVALIDARG: int # Invalid argument
E_OUTOFMEMORY: int # Out of memory
# COM-specific errors
CLASS_E_NOAGGREGATION: int # Class doesn't support aggregation
CLASS_E_CLASSNOTAVAILABLE: int # Class not available
CO_E_CLASSSTRING: int # Invalid class string
# Connection point errors
CONNECT_E_CANNOTCONNECT: int # Cannot establish connection
CONNECT_E_ADVISELIMIT: int # Connection limit reached
CONNECT_E_NOCONNECTION: int # Connection doesn't exist
# Type library errors
TYPE_E_ELEMENTNOTFOUND: int # Element not found
TYPE_E_REGISTRYACCESS: int # Registry access error
TYPE_E_CANTLOADLIBRARY: int # Cannot load type library
# Dispatch errors
DISP_E_BADPARAMCOUNT: int # Wrong parameter count
DISP_E_TYPEMISMATCH: int # Type mismatch
DISP_E_UNKNOWNNAME: int # Unknown name
DISP_E_PARAMNOTOPTIONAL: int # Parameter not optional
# Utility functions
def MAKE_HRESULT(sev, fac, code):
"""
Construct HRESULT from severity, facility, and code.
Args:
sev (int): Severity (0=success, 1=error)
fac (int): Facility code
code (int): Error code
Returns:
int: Constructed HRESULT value
"""
def HRESULT_FROM_WIN32(x):
"""
Convert Win32 error code to HRESULT.
Args:
x (int): Win32 error code
Returns:
int: Equivalent HRESULT value
"""Interfaces for object persistence and property management.
class IPersist(IUnknown):
"""Base interface for persistent objects."""
def GetClassID(self):
"""
Get class identifier for persistent object.
Returns:
GUID: Class identifier
"""
class IPropertyBag(IUnknown):
"""Interface for property bag persistence."""
def Read(self, propname, var, errorlog=None):
"""
Read property value from bag.
Args:
propname (str): Property name
var (VARIANT): Variable to receive value
errorlog (IErrorLog, optional): Error logging interface
"""
def Write(self, propname, var):
"""
Write property value to bag.
Args:
propname (str): Property name
var (VARIANT): Property value
"""
class IPersistPropertyBag(IPersist):
"""Interface for property bag persistence."""
def InitNew(self):
"""Initialize object to default state."""
def Load(self, propertybag, errorlog=None):
"""
Load object state from property bag.
Args:
propertybag (IPropertyBag): Property bag interface
errorlog (IErrorLog, optional): Error logging interface
"""
def Save(self, propertybag, cleardirty, saveallproperties):
"""
Save object state to property bag.
Args:
propertybag (IPropertyBag): Property bag interface
cleardirty (bool): Clear dirty flag after save
saveallproperties (bool): Save all properties or only dirty ones
"""Interfaces for Windows shell integration and shell link manipulation.
class IShellLinkW(IUnknown):
"""Unicode shell link interface for shortcut manipulation."""
def GetPath(self, flags=0):
"""
Get target path of shell link.
Args:
flags (int): Path retrieval flags
Returns:
str: Target path
"""
def SetPath(self, path):
"""
Set target path of shell link.
Args:
path (str): Target path
"""
def GetIDList(self):
"""
Get target as item ID list.
Returns:
ITEMIDLIST: Target item identifier list
"""
def SetIDList(self, pidl):
"""
Set target from item ID list.
Args:
pidl (ITEMIDLIST): Target item identifier list
"""
def GetDescription(self):
"""
Get shell link description.
Returns:
str: Description text
"""
def SetDescription(self, description):
"""
Set shell link description.
Args:
description (str): Description text
"""
def GetWorkingDirectory(self):
"""
Get working directory.
Returns:
str: Working directory path
"""
def SetWorkingDirectory(self, path):
"""
Set working directory.
Args:
path (str): Working directory path
"""
def GetArguments(self):
"""
Get command line arguments.
Returns:
str: Command line arguments
"""
def SetArguments(self, args):
"""
Set command line arguments.
Args:
args (str): Command line arguments
"""
class ShellLink(CoClass):
"""Shell link COM class for creating and manipulating shortcuts."""
_reg_clsid_ = "{00021401-0000-0000-C000-000000000046}"
_com_interfaces_ = [IShellLinkW]Interfaces for stream-based I/O operations.
class ISequentialStream(IUnknown):
"""Interface for sequential stream I/O operations."""
def RemoteRead(self, cb):
"""
Read data from stream (remote version).
Args:
cb (int): Maximum bytes to read
Returns:
bytes: Data read from stream
"""
def RemoteWrite(self, pv):
"""
Write data to stream (remote version).
Args:
pv (bytes): Data to write
Returns:
int: Number of bytes written
"""Tools for processing COM type libraries and generating Python bindings.
def PTR(typ):
"""
Create pointer type descriptor for type library processing.
Args:
typ (type): Base type to create pointer for
Returns:
Pointer type descriptor
"""
def get_tlib_filename(tlib):
"""
Get filename for type library.
Args:
tlib: Type library reference (path, ProgID, or ITypeLib)
Returns:
str: Type library filename
"""
class Parser:
"""Type library parser for generating Python bindings."""
def __init__(self, tlib):
"""
Create parser for type library.
Args:
tlib: Type library to parse
"""
def generate_code(self):
"""
Generate Python code from type library.
Returns:
str: Generated Python code
"""Support for Windows message processing in COM applications.
def run():
"""
Run Windows message loop.
Blocks until WM_QUIT message received.
"""
def insert_filter(filter_func):
"""
Insert message filter into message loop.
Args:
filter_func: Function to filter messages
Should return True to suppress message
"""
def remove_filter(filter_func):
"""
Remove message filter from message loop.
Args:
filter_func: Filter function to remove
"""Utilities for debugging COM operations and logging COM activity.
# Logger instance for comtypes package
logger: logging.Logger
"""Package logger for COM operations and debugging."""
class NullHandler(logging.Handler):
"""Logging handler that discards all messages."""
def emit(self, record):
"""Discard log record."""
passUtilities for checking type library versions and compatibility.
def _check_version(actual, required):
"""
Check if type library version meets requirements.
Args:
actual (tuple): Actual version as (major, minor)
required (tuple): Required version as (major, minor)
Returns:
bool: True if version is compatible
"""import comtypes
from comtypes.safearray import _midlSAFEARRAY, safearray_as_ndarray
from ctypes import c_double
import numpy as np
# Create SafeArray type for doubles
DoubleArray = _midlSAFEARRAY(c_double)
# Create SafeArray with data
data = [1.0, 2.0, 3.0, 4.0, 5.0]
safe_array = DoubleArray.from_param(data)
# Access as NumPy array (if NumPy available)
with safearray_as_ndarray(safe_array) as np_array:
print(f"Sum: {np_array.sum()}")
print(f"Mean: {np_array.mean()}")import comtypes.client
from comtypes.shelllink import ShellLink, IShellLinkW
# Create shell link
link = comtypes.client.CreateObject(ShellLink, interface=IShellLinkW)
# Configure shortcut
link.SetPath(r"C:\Program Files\MyApp\myapp.exe")
link.SetDescription("My Application Shortcut")
link.SetWorkingDirectory(r"C:\Program Files\MyApp")
link.SetArguments("/startup")
# Save shortcut (would need IPersistFile interface)
# This is simplified - actual saving requires additional stepsimport comtypes
from comtypes.hresult import *
try:
# Some COM operation that might fail
obj = comtypes.client.CreateObject("NonExistent.Application")
except comtypes.COMError as e:
if e.hresult == CLASS_E_CLASSNOTAVAILABLE:
print("COM class not registered")
elif e.hresult == E_NOINTERFACE:
print("Interface not supported")
else:
print(f"COM error: 0x{e.hresult:08X}")import ctypes
from comtypes.util import byref_at, cast_field
# Create structure
class MyStruct(ctypes.Structure):
_fields_ = [
("field1", ctypes.c_int),
("field2", ctypes.c_double),
("field3", ctypes.c_char * 10)
]
s = MyStruct(42, 3.14, b"hello")
# Get reference to field at offset
field2_ref = byref_at(s, MyStruct.field2.offset)
# Cast field to different type
field_as_bytes = cast_field(s, "field3", ctypes.POINTER(ctypes.c_ubyte))import comtypes
from comtypes.persist import IPropertyBag, IPersistPropertyBag
class MyPropertyBag:
"""Simple property bag implementation."""
def __init__(self):
self.properties = {}
def Read(self, name, var, errorlog=None):
if name in self.properties:
var.value = self.properties[name]
else:
raise comtypes.COMError(E_INVALIDARG)
def Write(self, name, var):
self.properties[name] = var.value
# Usage with persistent object
bag = MyPropertyBag()
# Save object properties to bag
# Load object properties from bagInstall 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