0
# Server Development
1
2
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.
3
4
## Capabilities
5
6
### Base Server Classes
7
8
Foundation classes for implementing COM objects and coclasses with proper COM lifetime management.
9
10
```python { .api }
11
class COMObject:
12
"""Base class for implementing COM objects in Python."""
13
14
def __init__(self):
15
"""Initialize COM object with reference counting."""
16
17
def QueryInterface(self, interface):
18
"""
19
Query for interface implementation.
20
21
Args:
22
interface (type): Interface class to query for
23
24
Returns:
25
Interface implementation or None
26
"""
27
28
def AddRef(self):
29
"""
30
Increment reference count.
31
32
Returns:
33
int: New reference count
34
"""
35
36
def Release(self):
37
"""
38
Decrement reference count.
39
40
Returns:
41
int: New reference count (0 if object destroyed)
42
"""
43
44
class CoClass(COMObject):
45
"""Base class for COM coclasses with metaclass support."""
46
47
_reg_clsid_: str # Class identifier for registration
48
_reg_progid_: str # Programmatic identifier
49
_reg_desc_: str # Description for registry
50
_reg_clsctx_: int # Class context flags
51
52
def __init__(self):
53
"""Initialize coclass with proper COM semantics."""
54
```
55
56
### Class Factory
57
58
Standard COM class factory interface for creating object instances.
59
60
```python { .api }
61
class IClassFactory(IUnknown):
62
"""Standard interface for creating COM object instances."""
63
64
def CreateInstance(self, outer, interface):
65
"""
66
Create new instance of COM object.
67
68
Args:
69
outer (IUnknown, optional): Outer object for aggregation
70
interface (type): Interface to query for on new instance
71
72
Returns:
73
New COM object instance
74
75
Raises:
76
COMError: If creation fails or aggregation not supported
77
"""
78
79
def LockServer(self, lock):
80
"""
81
Lock server in memory to prevent unloading.
82
83
Args:
84
lock (bool): True to lock, False to unlock
85
"""
86
```
87
88
### Object Registration
89
90
Functions for registering COM objects in the Running Object Table and with the system.
91
92
```python { .api }
93
def RegisterActiveObject(comobj, weak=True):
94
"""
95
Register COM object as active for client access.
96
97
Args:
98
comobj: COM object instance to register
99
weak (bool): Use weak reference to allow object cleanup
100
101
Returns:
102
int: Registration token for later revocation
103
"""
104
105
def RevokeActiveObject(token):
106
"""
107
Remove object from Running Object Table.
108
109
Args:
110
token (int): Registration token from RegisterActiveObject
111
"""
112
```
113
114
### Server Types
115
116
Different server implementation patterns supported by comtypes.
117
118
#### In-Process Server
119
120
```python { .api }
121
# From comtypes.server.inprocserver module
122
123
def DllCanUnloadNow():
124
"""
125
Determine if DLL can be unloaded.
126
127
Returns:
128
HRESULT: S_OK if can unload, S_FALSE if still in use
129
"""
130
131
def DllGetClassObject(clsid, iid):
132
"""
133
Get class factory for specified class.
134
135
Args:
136
clsid (GUID): Class identifier
137
iid (GUID): Interface identifier (usually IClassFactory)
138
139
Returns:
140
Class factory instance
141
"""
142
143
# Note: DllRegisterServer and DllUnregisterServer are not implemented
144
# in comtypes. These functions would need to be implemented by the
145
# application developer for COM server registration.
146
```
147
148
#### Local Server
149
150
```python { .api }
151
# From comtypes.server.localserver module
152
153
class LocalServer:
154
"""Framework for implementing local (out-of-process) COM servers."""
155
156
def run(self, classobjects):
157
"""
158
Start local server with registered class objects.
159
160
Args:
161
classobjects (dict): Mapping of CLSIDs to class factory objects
162
"""
163
164
def run_sta(self):
165
"""Run server in single-threaded apartment mode."""
166
167
def run_mta(self):
168
"""Run server in multi-threaded apartment mode."""
169
170
def Lock(self):
171
"""Increment server lock count."""
172
173
def Unlock(self):
174
"""Decrement server lock count."""
175
```
176
177
### Connection Points
178
179
Support for COM events and callbacks through connection point interfaces.
180
181
```python { .api }
182
class IConnectionPointContainer(IUnknown):
183
"""Container interface for managing connection points."""
184
185
def EnumConnectionPoints(self):
186
"""
187
Get enumerator for all connection points.
188
189
Returns:
190
IEnumConnectionPoints: Connection point enumerator
191
"""
192
193
def FindConnectionPoint(self, iid):
194
"""
195
Find connection point for specific interface.
196
197
Args:
198
iid (GUID): Event interface identifier
199
200
Returns:
201
IConnectionPoint: Connection point for interface
202
"""
203
204
class IConnectionPoint(IUnknown):
205
"""Individual connection point for specific event interface."""
206
207
def GetConnectionInterface(self):
208
"""
209
Get interface ID for this connection point.
210
211
Returns:
212
GUID: Event interface identifier
213
"""
214
215
def GetConnectionPointContainer(self):
216
"""
217
Get parent connection point container.
218
219
Returns:
220
IConnectionPointContainer: Parent container
221
"""
222
223
def Advise(self, sink):
224
"""
225
Connect event sink to receive events.
226
227
Args:
228
sink: Object implementing event interface
229
230
Returns:
231
int: Connection cookie for later disconnection
232
"""
233
234
def Unadvise(self, cookie):
235
"""
236
Disconnect event sink.
237
238
Args:
239
cookie (int): Connection cookie from Advise
240
"""
241
242
def EnumConnections(self):
243
"""
244
Get enumerator for active connections.
245
246
Returns:
247
IEnumConnections: Active connection enumerator
248
"""
249
```
250
251
### Registration Utilities
252
253
Helper functions for COM server registration and unregistration.
254
255
```python { .api }
256
# From comtypes.server.register module
257
258
def register(cls):
259
"""
260
Register COM class in system registry.
261
262
Args:
263
cls (type): CoClass to register (must have registration attributes)
264
"""
265
266
def unregister(cls):
267
"""
268
Remove COM class from system registry.
269
270
Args:
271
cls (type): CoClass to unregister
272
"""
273
```
274
275
## Usage Examples
276
277
### Basic COM Object Implementation
278
279
```python
280
import comtypes
281
from comtypes.server import COMObject
282
283
class MyComObject(COMObject):
284
"""Simple COM object implementation."""
285
286
# Define supported interfaces
287
_com_interfaces_ = [comtypes.IUnknown]
288
289
def __init__(self):
290
super().__init__()
291
print("COM object created")
292
293
def my_method(self):
294
"""Custom method implementation."""
295
return "Hello from COM object"
296
297
# Create and use object
298
obj = MyComObject()
299
result = obj.my_method()
300
print(result)
301
```
302
303
### CoClass with Registration
304
305
```python
306
import comtypes
307
from comtypes.server import CoClass
308
from comtypes.GUID import GUID
309
310
# Define custom interface
311
class IMyInterface(comtypes.IUnknown):
312
_iid_ = GUID("{12345678-1234-5678-9ABC-123456789ABC}")
313
_methods_ = [
314
comtypes.STDMETHOD(comtypes.HRESULT, "DoSomething",
315
(['in'], comtypes.c_int, "value"))
316
]
317
318
class MyCoClass(CoClass):
319
"""COM coclass with registration information."""
320
321
# Registration metadata
322
_reg_clsid_ = "{87654321-4321-8765-CBA9-987654321CBA}"
323
_reg_progid_ = "MyApp.MyCoClass.1"
324
_reg_desc_ = "My COM CoClass"
325
_reg_clsctx_ = comtypes.CLSCTX_INPROC_SERVER
326
327
# Supported interfaces
328
_com_interfaces_ = [IMyInterface]
329
330
def DoSomething(self, value):
331
"""Implementation of interface method."""
332
print(f"DoSomething called with value: {value}")
333
return comtypes.S_OK
334
335
# Register the class (requires admin privileges)
336
from comtypes.server.register import register_class
337
register_class(MyCoClass)
338
```
339
340
### Event Source Implementation
341
342
```python
343
import comtypes
344
from comtypes.server import COMObject
345
from comtypes.connectionpoints import IConnectionPointContainer, IConnectionPoint
346
347
# Define event interface
348
class IMyEvents(comtypes.IUnknown):
349
_iid_ = GUID("{11111111-2222-3333-4444-555555555555}")
350
_methods_ = [
351
comtypes.COMMETHOD([], comtypes.HRESULT, "OnSomethingHappened",
352
(['in'], comtypes.BSTR, "message"))
353
]
354
355
class MyEventSource(COMObject):
356
"""COM object that fires events."""
357
358
_com_interfaces_ = [IConnectionPointContainer]
359
_outgoing_interfaces_ = [IMyEvents]
360
361
def __init__(self):
362
super().__init__()
363
self._connections = {}
364
365
def fire_event(self, message):
366
"""Fire event to all connected sinks."""
367
for sink in self._connections.values():
368
try:
369
sink.OnSomethingHappened(message)
370
except Exception as e:
371
print(f"Error firing event: {e}")
372
373
# Connection point implementation would go here
374
# (simplified for example)
375
```
376
377
### In-Process Server
378
379
```python
380
# myserver.py - In-process COM server
381
import comtypes
382
from comtypes.server.inprocserver import *
383
384
class MyInProcServer(CoClass):
385
_reg_clsid_ = "{AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE}"
386
_reg_progid_ = "MyServer.Application.1"
387
_reg_desc_ = "My In-Process COM Server"
388
389
_com_interfaces_ = [comtypes.IUnknown]
390
391
def get_message(self):
392
return "Hello from in-process server"
393
394
# Register exported classes
395
_reg_classes_ = [MyInProcServer]
396
397
# Build as DLL and register with:
398
# regsvr32 myserver.dll
399
```
400
401
### Local Server
402
403
```python
404
# localserver.py - Local COM server
405
import comtypes
406
from comtypes.server.localserver import LocalServer
407
408
class MyLocalServer(CoClass):
409
_reg_clsid_ = "{FFFFFFFF-EEEE-DDDD-CCCC-BBBBBBBBBBBB}"
410
_reg_progid_ = "MyLocalServer.Application.1"
411
_reg_desc_ = "My Local COM Server"
412
413
_com_interfaces_ = [comtypes.IUnknown]
414
415
def get_data(self):
416
return "Data from local server"
417
418
if __name__ == "__main__":
419
# Create and run local server
420
server = LocalServer()
421
server.register_class(MyLocalServer)
422
423
print("Starting local COM server...")
424
server.run() # Blocks until shutdown
425
```
426
427
### Class Factory Implementation
428
429
```python
430
import comtypes
431
from comtypes.server import IClassFactory, COMObject
432
433
class MyClassFactory(COMObject):
434
"""Custom class factory implementation."""
435
436
_com_interfaces_ = [IClassFactory]
437
438
def __init__(self, target_class):
439
super().__init__()
440
self.target_class = target_class
441
442
def CreateInstance(self, outer, interface):
443
"""Create new instance of target class."""
444
if outer is not None:
445
raise comtypes.COMError(comtypes.hresult.CLASS_E_NOAGGREGATION)
446
447
# Create instance
448
instance = self.target_class()
449
450
# Query for requested interface
451
return instance.QueryInterface(interface)
452
453
def LockServer(self, lock):
454
"""Lock/unlock server in memory."""
455
# Implementation depends on server type
456
pass
457
```