This documents how to quickly start implementing COM objects in Python. It is not a thorough discussion of the COM system, or of the concepts introduced by COM.
For more details information on Python and COM, please see the COM Tutorial given by Greg Stein and Mark Hammond at SPAM 6 (HTML format) or download the same tutorial in PowerPoint format.
For information on using external COM objects from Python, please see a Quick Start to Client side COM and Python
class HelloWorld:
def __init__(self):
self.softspace = 1
self.noCalls = 0
def Hello(self, who):
self.noCalls = self.noCalls + 1
# insert "softspace" number of spaces
return "Hello" + " " * self.softspace + who
This is obviously a very simple server. In particular, custom error handling would be needed for a production class server. In addition, there are some contrived properties just for demonstration purposes.
At this stage, Python and Unicode don’t really work well together. All strings which come from COM will actually be Unicode objects rather than string objects.
To make this code work in a COM environment, the last line of the "Hello" method must become:
return "Hello" + " " * self.softspace + str(who)
Note the conversion of the "who" to "str(who)". This forces the Unicode object into a native Python string object.
For details on how to debug COM Servers to find this sort of error, please see
This is not a complete list of names, simply a list of properties used by this sample.
Property Name |
Description |
_public_methods_ |
List of all method names exposed to remote COM clients |
_public_attrs_ |
List of all attribute names exposed to remote COM clients |
_readonly_attrs_ |
List of all attributes which can be accessed, but not set. |
We change the class header to become:
class HelloWorld:
_public_methods_ = ['Hello']
_public_attrs_ = ['softspace', 'noCalls']
_readonly_attrs_ = ['noCalls']
def __init__(self):
[Same from here…]
COM requires that all objects use a unique CLSID and be registered under a "user friendly" name. This documents the process.
Microsoft Visual C++ comes with various tools for generating CLSID's, which are quite suitable. Alternatively, the pythoncom module exports the function CreateGuid() to generate these identifiers.
>>> import pythoncom
>>> print pythoncom.CreateGuid()
{7CC9F362-486D-11D1-BB48-0000E838A65F}
Obviously the GUID that you get will be different than that displayed here.
The win32com package allows yet more annotations to be applied to a class, allowing registration to be effected with 2 lines in your source file. The registration annotations used by this sample are:
Property Name |
Description |
_reg_clsid_ |
The CLSID of the COM object |
_reg_progid_ |
The "program ID", or Name, of the COM Server. This is the name the user usually uses to instantiate the object |
_reg_desc_ |
The description of the COM Server. Used primarily for COM browsers. |
_reg_class_spec_ |
A string which represents how Python can create the class instance. The string is of format The portion up to the class name must be valid for Python to "import", and the class portion must be a valid attribute in the specified class. This is (will be!) optional in Python 1.5. |
Note there are quite a few other keys available. Also note that these annotations are not required - they just make registration simple. Helper functions in the module win32com.server.register
allow you to explicitly specify each of these attributes without attaching them to the class.
The header of our class now becomes:
class HelloWorld:
_reg_clsid_ = "{7CC9F362-486D-11D1-BB48-0000E838A65F}"
_reg_desc_ = "Python Test COM Server"
_reg_progid_ = "Python.TestServer"
# Next line assumes file is "testcomserver.py"
_reg_class_spec_ = "testcomserver.HelloWorld"
_public_methods_ = ['Hello']
[same from here]
The idiom that most Python COM Servers use is that they register themselves when run as a script (ie, when executed from the command line.) Thus the standard "if __name__=='__main___':
" technique works well.
win32com.server.register contains a number of helper functions. The easiest to use is "UseCommandLine
".
Registration becomes as simple as:
if __name__=='__main__':
# ni only for 1.4!
import ni, win32com.server.register
win32com.server.register.UseCommandLine(HelloWorld)
Running the script will register our test server.
For the purposes of this demonstration, we will test the class using Visual Basic. This code should run under any version of Visual Basic, including VBA found in Microsoft Office. Any COM compliant package could be used alternatively. VB has been used just to prove there is no "smoke and mirrors. For information on how to test the server using Python, please see the Quick Start to Client side COM documentation.
This is not a tutorial in VB. The code is just presented! Run it, and it will work!
When things go wrong in COM Servers, there is often nowhere useful for the Python traceback to go, even if such a traceback is generated.
Rather than discuss how it works, I will just present the procedure to debug your server:
To register a debug version of your class, run the script (as above) but pass in a "--debug
" parameter. Eg, for the server above, use the command line "testcomserver.py -debug
".
To see the debug output generated (and any print statements you may choose to add!) simply run the script "win32traceutil.py". You can do this simply by double-clicking on it from Windows Explorer.