Distributing COM servers (Was: Re: How to distribute Python COM applications?)
Thomas Heller
thomas.heller at ion-tof.com
Mon May 21 03:28:14 EDT 2001
"Gordon McMillan" <gmcm at hypernet.com> wrote in message news:90A7E7E3Fgmcmhypernetcom at 199.171.54.194...
> hungjunglu at yahoo.com wrote in <mailman.990048145.9953.python-
> list at python.org>:
> [...]
> >So far I have succeeded in distributing Python COM client
> >applications.
> >
> >It's the Python COM server part that is complicated. I know py2exe or
> >Gordon installer are not enough, but besides that, more registry
> >tweaking and DLL handling are needed.
>
> Actually, it's more a problem with the arrangement of responsibilities.
>
> Your typical Python COM server defines a class and has some register /
> unregister logic under the "if __name__ == '__main__':" code. So it's both
> a script (when registering / unregistering) and a module (when attached
> through COM). If you just freeze your class, all you'll get is the register
> / unregister code, and it won't create the right entries.
>
> There *is* a script which runs (when you use out-of-process): it's
> win32com/server/localserver.py. As proof of concept, I hacked up
> localserver.py so that I got localserver.exe which could serve up my COM
> class. By manually tweaking the registry, I got it working (out-of-
> process). So I know this stuff is possible, it's just that generalizing and
> automating it is a considerable amount of work.
It's not very complicated, and you can achieve it _without_ hacking
localserver.py and without manually tweaking the registry.
Here are the tricks:
1. Detect if the script is running as py2exe-packed exe. py2exe
installs it's importers in the sys module as 'sys.importers'.
A similar trick should exist for Gordon's installer...
2. Set the 'frozen' attribute in the pythoncom module,
specify a _reg_class_spec_ attribute in the COM server class.
3. Run the 'localserver' module manually in the
'if __name__ == "__main__"' branch.
Attached is a simple COM server python script. If you play with it,
be sure to unregister and register it completely after switching
between the 'standard way' and when using the py2exe-packed way.
To register the Python script use:
'python testCOMserver.py --unregister' and then
'python testCOMserver.py --register'.
To build the executable:
'python setup.py py2exe'
To register the executable as COM server:
'cd dist\testCOMserver'
'testCOMserver.exe --unregister'
'testCOMserver.exe --register'
Thomas
------------------testCOMserver.py-----------------------
import sys
import pythoncom
if hasattr(sys, 'importers'):
# we are running as py2exe-packed executable
pythoncom.frozen = 1
class HelloWorld:
_reg_clsctx_ = pythoncom.CLSCTX_LOCAL_SERVER
if hasattr(sys, 'importers'):
# In the py2exe-packed version, specify the module.class
# to use. In the python script version, python is able
# to figure it out itself.
_reg_class_spec_ = "__main__.HelloWorld"
_reg_clsid_ = "{B83DD222-7750-413D-A9AD-01B37021B24B}"
_reg_desc_ = "Python Test COM Server"
_reg_progid_ = "Python.TestServer"
_public_methods_ = ['Hello']
_public_attrs_ = ['softspace', 'noCalls']
_readonly_attrs_ = ['noCalls']
def __init__(self):
self.softspace = 1
self.noCalls = 0
# __init__()
def Hello(self, who):
self.noCalls = self.noCalls + 1
# insert "softspace" number of spaces
return "Hello" + " " * self.softspace + str(who)
if __name__ == '__main__':
if hasattr(sys, 'importers'):
# running as packed executable.
if '--register' in sys.argv[1:] \
or '--unregister' in sys.argv[1:]:
# --register and --unregister work as usual
import win32com.server.register
win32com.server.register.UseCommandLine(HelloWorld)
else:
# start the server.
from win32com.server import localserver
localserver.main()
else:
import win32com.server.register
win32com.server.register.UseCommandLine(HelloWorld)
---------------------------------------------------------
This is the setup script you can use to build an executable
with py2exe:
----------------------setup.py---------------------------
from distutils.core import setup
import py2exe
setup(name='testCOMserver',
scripts=['testCOMserver.py'])
---------------------------------------------------------
More information about the Python-list
mailing list