Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

How to distribute Python COM applications?

47 views
Skip to first unread message

hungj...@yahoo.com

unread,
May 16, 2001, 5:21:42 PM5/16/01
to pytho...@cwi.nl
I have asked Mark Hammond, but no clear answers, yet. (He told me to
look into regsvr32.)

I am also starting to look at all installation aspects of Python COM.
(registry items, DLLs, etc.) If I succeed, I'll let people know.

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.

But meanwhile, if anyone already has experience in packaging and
distributing Python COM applications (that is, without the end-user
having to install ActiveState's Python or the win32all package
explicitly), it'll be great to have a few more pointer to make this
process easier. Any help is appreciated.

regards,

Hung Jung


Markus von Ehr

unread,
May 17, 2001, 1:20:26 PM5/17/01
to
Hi Hung,

I did a Standalone version of my program, using win32com
extensions. I use BeOpenPython2.0 and the extensions by Mark Hammond.
I use Gordon McMillans Installer 3j, be careful about the gencache
problem:

Gordon MacMillan told me a solution that finally worked:
In the frozen version I have a gen_py/ directory holding a file called:
__init__.py. My import section looks like this:

import win32com, os.path
win32com.__gen_path__ = os.path.abspath(ด.ด) + "\\gen_py"
import win32com.client.dynamic

Have fun,

Markus

Gordon McMillan

unread,
May 20, 2001, 10:07:36 PM5/20/01
to
hungj...@yahoo.com wrote in <mailman.990048145.9953.python-
li...@python.org>:

>I have asked Mark Hammond, but no clear answers, yet. (He told me to
>look into regsvr32.)
>
>I am also starting to look at all installation aspects of Python COM.
>(registry items, DLLs, etc.) If I succeed, I'll let people know.
>
>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.

[And I'm not sure that in-process is possible, mainly because with in-
process I don't think I have enough control over installation and search
paths.]

- Gordon

Thomas Heller

unread,
May 21, 2001, 3:26:06 AM5/21/01
to
"Gordon McMillan" <gm...@hypernet.com> wrote in message news:90A7E7E3Fgmc...@199.171.54.194...

> hungj...@yahoo.com wrote in <mailman.990048145.9953.python-
> li...@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'])
---------------------------------------------------------


Thomas Heller

unread,
May 21, 2001, 3:28:14 AM5/21/01
to
"Gordon McMillan" <gm...@hypernet.com> wrote in message news:90A7E7E3Fgmc...@199.171.54.194...
> hungj...@yahoo.com wrote in <mailman.990048145.9953.python-
> li...@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

Thomas Heller

unread,
May 21, 2001, 3:28:14 AM5/21/01
to
"Gordon McMillan" <gm...@hypernet.com> wrote in message news:90A7E7E3Fgmc...@199.171.54.194...
> hungj...@yahoo.com wrote in <mailman.990048145.9953.python-
> li...@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

Thomas Heller

unread,
May 21, 2001, 3:45:06 AM5/21/01
to
Sorry for the duplicate posts, it seems my news-software is broken.

Thomas

Francesco Franze

unread,
May 21, 2001, 10:00:49 AM5/21/01
to
Thomas Heller <thomas...@ion-tof.com> wrote:
> "Gordon McMillan" <gm...@hypernet.com> wrote in message news:90A7E7E3Fgmc...@199.171.54.194...
>> hungj...@yahoo.com wrote in <mailman.990048145.9953.python-
>> li...@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.
>>
> It's not very complicated, and you can achieve it _without_ hacking
> localserver.py and without manually tweaking the registry.
> Here are the tricks:


is there any trick to build an in proc python COM instead of a localserver?

bye

Thomas Heller

unread,
May 21, 2001, 10:11:54 AM5/21/01
to
> is there any trick to build an in proc python COM instead of a localserver?
>
No (at least not yet).

Also I'm not sure if it is a good idea to use a python inproc COM server
together with a python COM client...

Thomas


Gregory P. Smith

unread,
May 31, 2001, 3:11:37 PM5/31/01
to Gordon McMillan, pytho...@python.org
> >I am also starting to look at all installation aspects of Python COM.
> >(registry items, DLLs, etc.) If I succeed, I'll let people know.
> >
> >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 mostly took reading win32com and the likes, but creating a com
server as a standalone executable that can both register/unregister
itself -and- act as the com server executable worked. Just be sure to
force "pythoncom.frozen = 1" in your code before calling
"win32com.server.register.UseCommandLine(mycominterfaceobject)"

Them have the main code check for --register or --unregister command
line arguments to call that instead of
win32com.server.localserver.main() as the default. (and you can make
it runnable via non-com if applicable to your application by checking
for other parameters and not calling localserver.main() but whatever
other code you want to).

> [And I'm not sure that in-process is possible, mainly because with in-
> process I don't think I have enough control over installation and search
> paths.]

Hmm.. in process seemed to work fine for us, though that is not at all
what we wanted, we explicitly specified local server as its good to
not have one application's fatal error bring down the other.

--
Gregory P. Smith gnupg/pgp: http://electricrain.com/greg/keys/
C379 1F92 3703 52C9 87C4 BE58 6CDA DB87 105D 9163

0 new messages