Creating a Downloadable COM Control with Python

I've never really considered myself an expert at the Dark Side's tools, but I needed to make an object that could be downloaded into Internet Explorer and used from script the way that objects written in C++ and Visual Basic are. It was important to the project that the end-users not be required to install Python explicitly. So the Python interpreter had to be embedded into the object.

I couldn't find documentation on how to do that but all of the parts were out there to do it, thanks to a couple of Python heros, Mark Hammond and Gordon McMillan. Putting bits together through Google allowed me to solve my problem and avoid the curse of Visual Basic!

Overview

The first task is to write a COM control. There is documentation out there about that so I won't go into detail. For the purpose of testing, I'll use this Python Cookbook recipe as a starting point. Thanks Google and ActiveState! And thanks especially to Mark Hammond. His hard work made Python so powerful at manipulating the Windows environment.

But the script won't work as is. I needed to add "_reg_clsctx_" attributes. I don't know why this attribute lacks a useful default. I just know what I read. Where would we be without web mail archives? Here are the changes:

pycomCLSCTX_INPROC = 3
pycomCLSCTX_LOCAL_SERVER = 4

class StemmerFactory :
    _reg_clsctx_ = pycomCLSCTX_INPROC | pycomCLSCTX_LOCAL_SERVER
    _reg_clsid_ = "{602D10EB-426C-4D6F-A4DF-C05572EB780B}"
    ...

class Stemmer :
    _reg_clsctx_ = pycomCLSCTX_INPROC | pycomCLSCTX_LOCAL_SERVER
    _reg_clsid_ = "{B306454A-CAE6-4A74-ACAD-0BB11EF256DD}"
    ...

I believe that this states that the control can be used either "in-proc" or in its own separate exectuable. That probably has implications for global state. Unfortunately, the installer package won't warn you if you leave these out and it doesn't seem like you will get an error message. Your control just won't work. So be careful about this bit.

Next, I needed to compile this stuff into a binary executable. That's where Gordon McMillan's installer package comes in. So In installed installer and went through the following series of commands:

E:\temp\INSTAL~1>python Configure.py
I: computing EXE_dependencies
I: Finding TCL/TK...
I: testing for Zlib...
I: ... Zlib available
I: Testing for ability to set icons, version resources...
I: ... resource update available
I: Testing for Unicode support...
I: ... Unicode available
I: computing PYZ dependencies...

E:\temp\INSTAL~1>python MakeCOMServer.py stem.py
**********************************
Driver script .\drivestem.py created
Spec file .\drivestem.spec created

E:\temp\INSTAL~1>python Build.py drivestem.spec
checking Analysis
building Analysis because out0.toc non existent
building out0.toc
Analyzing: E:\temp\INSTAL~1\support\_mountzlib.py
Analyzing: E:\temp\INSTAL~1\support\useUnicode.py
Analyzing: E:\temp\INSTAL~1\drivestem.py
W: pythoncom is changing it's name to pythoncom22
W: pywintypes is changing it's name to PyWinTypes22
Warnings written to E:\temp\INSTAL~1\warndrivestem.txt
checking PYZ
rebuilding out1.toc because out1.pyz is missing
building out1.toc
checking PKG
rebuilding out3.toc because out3.pkg is missing
building out3.pkg
checking ELFEXE
rebuilding out2.toc because drivestem.exe missing
building out2.toc
checking PKG
rebuilding out5.toc because out5.pkg is missing
building out5.pkg
checking DLL
rebuilding out4.toc because drivestem.dll missing
building out4.toc
checking COLLECT
building out6.toc because out6.toc missing
building out6.toc

That creates a directory called "distdrivestem" (short for "distribution files for the driver file for the stem object).

E:\temp\INSTAL~1>cd distdrivestem

E:\temp\INSTAL~1\distdrivestem>dir
 Volume in drive E has no label.
 Volume Serial Number is 0000-5844

 Directory of E:\temp\INSTAL~1\distdrivestem

03/29/2003  06:20p                .
03/29/2003  06:20p                ..
03/29/2003  08:14p             512,568 drivestem.exe
04/15/2002  10:28a             843,859 python22.dll
03/29/2003  08:14p             512,568 drivestem.dll
04/15/2002  10:29a              24,668 win32trace.pyd
09/24/2002  02:11p              65,536 PyWinTypes22.dll
09/24/2002  02:11p             299,106 pythoncom22.dll
04/15/2002  10:29a              61,530 win32api.pyd
04/15/2002  10:28a              53,327 _sre.pyd
04/15/2002  10:28a             639,069 win32ui.pyd
04/15/2002  10:28a              61,519 zlib.pyd

E:\temp\INSTAL~1\distdrivestem>

Note that there are both EXE and DLL versions of the control. We don't need the exectuable for our purposes. Perhaps it would be just as good as the DLL for our purposes but it is a little bit more traditional to use DLLs for lightweight COM controls like this.

Installer has done its job at this point. You now have a binary executable that could be deployed just by dumping them in a system32 directory or something. But we want an object that can be used from Internet Explorer. Typically these are delivered as CAB files. So you need a program call "cabarc.exe" from the "Cabinet Software Development Kit".