[python-win32] Re: how to load 2 python COM DLLs in single app?
Niki Spahiev
niki at vintech.bg
Thu Nov 25 16:42:56 CET 2004
SUCCESS!
Renaming scheme works for me (TM) and i can load 2 Inprocess COM servers.
Attached patch is for py2exe 0.54
Option --unique=MN turns on renaming. MN are any 2 characters valid for
filename.
No debug-python support (_d.pyd).
Thomas will you include it in py2exe?
Niki Spahiev
-------------- next part --------------
--- C:\Python23\Lib\site-packages\py2exe\build_exe.pyw Fri Oct 22 17:32:32 2004
+++ C:\Python23\Lib\site-packages\py2exe\build_exe.py Thu Nov 25 17:33:51 2004
@@ -69,6 +69,19 @@
del __load
"""
+BOOT_UNIQUE = """
+def __load(name,ext):
+ import imp, sys
+ dirname = sys.prefix
+ path = dirname + '/' + name + ext
+ mod = imp.load_dynamic(name, path)
+## mod.frozen = 1
+__load('zlib','%(UN)s.pyd')
+__load('pywintypes','%(UN)s.dll')
+__load('pythoncom','%(UN)s.dll')
+del __load
+"""
+
# A very loosely defined "target". We assume either a "script" or "modules"
# attribute. Some attributes will be target specific.
class Target:
@@ -139,7 +152,10 @@
"create a compressed zipfile"),
("xref", 'x',
- "create and show a module crosss reference")
+ "create and show a module crosss reference"),
+
+ ("unique", 'u',
+ "patch all DLLs to be unique"),
]
boolean_options = ["compressed", "xref"]
@@ -156,6 +172,7 @@
self.dist_dir = None
self.dll_excludes = None
self.typelibs = None
+ self.unique = ''
def finalize_options (self):
self.optimize = int(self.optimize)
@@ -359,7 +376,10 @@
# magic which relies on this exact filename.
# So we do it via a custom loader - see create_loader()
dst = os.path.join(self.lib_dir, os.path.basename(item.__file__))
- self.copy_file(src, dst)
+ dst = patch_filename(dst, self.unique)
+ where,copied = self.copy_file(src, dst)
+ if copied:
+ patch_python_dll_import(where, self.unique)
self.lib_files.append(dst)
# create the shared zipfile containing all Python modules
@@ -384,7 +404,10 @@
dst = os.path.join(self.exe_dir, base)
else:
dst = os.path.join(self.lib_dir, base)
- self.copy_file(dll, dst)
+ dst = patch_filename(dst, self.unique)
+ where,copied = self.copy_file(dll, dst)
+ if copied:
+ patch_python_dll_import(where, self.unique)
self.lib_files.append(dst)
for target in self.distribution.isapi:
@@ -577,6 +600,7 @@
old_force = self.force
self.force = True
self.copy_file(src, exe_path)
+ patch_python_dll_import(exe_path, self.unique)
self.force = old_force
# Make sure the file is writeable...
@@ -602,6 +626,10 @@
code_object = compile(open(script, "U").read() + "\n",
os.path.basename(script), "exec")
code_objects.append(code_object)
+ if self.unique:
+ code_object = compile(BOOT_UNIQUE % dict(UN=self.unique),
+ "boot_unique", "exec")
+ code_objects.insert(0,code_object)
code_bytes = marshal.dumps(code_objects)
if self.distribution.zipfile is None:
@@ -881,6 +909,7 @@
print "creating python loader for extension '%s'" % item.__name__
fname = os.path.basename(item.__file__)
+ fname = patch_filename(fname, self.unique)
source = LOADER % fname
if not self.dry_run:
open(pathname, "w").write(source)
@@ -1307,3 +1336,45 @@
if verbose:
print grok_environment_error(
exc, "error removing %s: " % directory)
+
+def patch_filename(fn, AB):
+ base = os.path.basename(fn).lower()
+ if not AB or base.startswith('tcl') or base.startswith('tk'):
+ return fn
+ pv = '%d%d' % sys.version_info[:2]
+ fn, ext = os.path.splitext( fn )
+ if fn.endswith( pv ):
+ fn = fn[:-2]
+ fn += AB+ext
+ return fn
+
+def patch_python_dll_import(dll_name, AB):
+ base = os.path.basename(dll_name).lower()
+ if not AB or base.startswith('tcl') or base.startswith('tk'):
+ return
+ pv = '%d%d' % sys.version_info[:2]
+ # We preserve the times on the file, so the dependency tracker works.
+ st = os.stat(dll_name)
+ os.chmod(dll_name, stat.S_IREAD | stat.S_IWRITE)
+ f = open(dll_name, "r+b")
+ bytes = f.read()
+ for import_name in (python_dll, 'pywintypes%s.dll'%pv,
+ 'pythoncom%s.dll'%pv, 'pythoncom%s%s%s.dll\0'):
+ pos = bytes.find( import_name )
+ if pos < 0:
+ if import_name == python_dll:
+ raise RuntimeError(import_name+' not in '+dll_name)
+ continue
+ dup = bytes.find(import_name, pos+1)
+ if dup >= 0 and pv in import_name:
+ raise RuntimeError('multi '+import_name)
+ if pv in import_name:
+ r = import_name.replace( pv, AB )
+ else:
+ r = import_name.replace( '%s%s%s', AB )
+ f.seek( pos, 0 )
+ f.write( r )
+ f.close()
+
+ # restore the time.
+ os.utime(dll_name, (st[stat.ST_ATIME], st[stat.ST_MTIME]))
More information about the Python-win32
mailing list