[python-win32] Running a Windows Python service without pythonservice.exe?

Mark Hammond mhammond at skippinet.com.au
Tue May 11 08:22:28 CEST 2010


On 11/05/2010 12:50 PM, Bill Janssen wrote:
> Mark Hammond<skippy.hammond at gmail.com>  wrote:
>
>> That's correct.  Using python.exe as the host will involve having a
>> .py script which imports the servicemanager module then call
>> PrepareToHostSingle and instantiate the service class - or something
>> like that :)
>
> How definitive :-).  I'm already generating a python script for each
> service, so this could easily be incorporated, if I knew exactly what it
> was I have to do.
>
> 1.  Set up the sys.path and os.environ["Path"] properly.
>
> 2.  import servicemanager
>
> 3.  define my class
>
> 4.  call servicemanager.PrepareToHostSingle(my class name)
>
> Seem right?

Sounds about right - but reading pythonservice.cpp is really the 
definitive source to what needs to be done.  Sadly I can't find anything 
more specific, such as a sample.

>> Another alternative is to ship a slightly modified pythonxx.dll - it
>> has a feature where a certain string resource contains the basename of
>> the registry key used at runtime to load the pythonpath - eg, you will
>> find the resource has "2.6" for Python 2.6 builds.  Using a resource
>> editor (or even a script using pywin32) to change this to some custom
>> value will mean the pythonpath can be loaded from a private key in the
>> registry, meaning you still get isolation from other installed Python
>> versions.
>
> I could do that, I guess.  I'd like to be able to script all the
> preparations, so if it's a GUI step that would be a Bad Thing.  But a
> script using pywin32 would be great.  So, I need to know a couple of
> things:
>
> 1.  What's the name of this "certain string resource"?
>
> 2.  How would one write such a pywin32 script :-)?
>
> I wrote this script to answer question #1:
>
> -----------------------------------------------------------------
> import sys, os
>
> import win32api, win32con
>
> handle = win32api.LoadLibrary(sys.argv[1])
> for rname in win32api.EnumResourceNames(handle, win32con.RT_STRING):
>      rvalue = win32api.LoadResource(handle, win32con.RT_STRING, rname)
>      print rname, rvalue
> -----------------------------------------------------------------
>
> $ python resource.py python26.dll
> 63 ^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^C^@2^@.^@6^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@
> $
>
> So, the "name" is 63, and it's a 38-byte value with a lot of nul
> characters in it.  I'm unsure of just how to hack it with UpdateResource
> -- do I just center the replacement text and pad with nul characters?
> And what's the registry key this works against, anyway?  I'd have to
> update that as part of my installer, too.

I think the above loaded a string *table*.  The resource ID is 1000, and 
py2exe has some code to deal with updating this for a file.  It does:

         from py2exe.resources.StringTables import StringTable, RT_STRING
         from py2exe_util import add_resource, load_resource
         from py2exe.resources.VersionInfo import RT_VERSION

...
         # OK - do the strings.
         s = StringTable()
         # 1000 is the resource ID Python loads for its winver.
         s.add_string(1000, new_winver)
         for id, data in s.binary():
             add_resource(ensure_unicode(dll_name), data, RT_STRING, id, 
False)

While this could be done with pywin32 and the win32api.UpdateResource 
function, that would probably require some struct magic - the 
StringTable object in py2exe hides some of this from you.

HTH,

Mark


More information about the python-win32 mailing list