Ticket #39: pyinstaller-trunk-r690-py26-win-tweaks-20090728.patch
| File pyinstaller-trunk-r690-py26-win-tweaks-20090728.patch, 60.5 KB (added by openticket, 14 months ago) |
|---|
-
application.config
1 <?xml version="1.0" encoding="UTF-8" standalone="yes"?> 2 <configuration> 3 <windows> 4 <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> 5 <assemblyIdentity processorArchitecture="X86" name="Microsoft.Windows.mysampleApp" type="win32" version="1.0.0.0"/> 6 <publisherPolicy apply="no"/> 7 <dependentAssembly> 8 <assemblyIdentity type="win32" processorArchitecture="x86" name="Microsoft.Windows.SampleAssembly" publicKeyToken="0000000000000000"/> 9 <bindingRedirect oldVersion="2.0.0.0" newVersion="2.0.1.0"/> 10 </dependentAssembly> 11 </assemblyBinding> 12 </windows> 13 </configuration> 14 No newline at end of file -
application.manifest
1 <?xml version="1.0" encoding="UTF-8" standalone="yes"?> 2 <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> 3 <assemblyIdentity type="win32" 4 name="myOrganization.myDivision.mySampleApp" 5 version="6.0.0.0" 6 processorArchitecture="x86" 7 publicKeyToken="0000000000000000" 8 /> 9 <dependency> 10 <dependentAssembly> 11 <assemblyIdentity type="win32" 12 name="Proseware.Research.SampleAssembly" 13 version="6.0.0.0" 14 processorArchitecture="X86" 15 publicKeyToken="0000000000000000" 16 language="*" 17 /> 18 </dependentAssembly> 19 </dependency> 20 </assembly> 21 No newline at end of file -
apptemplate.manifest
1 <?xml version="1.0" encoding="UTF-8" standalone="yes"?> 2 <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> 3 <assemblyIdentity 4 version="0.0.0.0" 5 processorArchitecture="x86" 6 name="myOrganization.myDivision.mySampleApp" 7 type="win32" 8 /> 9 <description>Description</description> 10 <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"> 11 <security> 12 <requestedPrivileges> 13 <requestedExecutionLevel level="asInvoker" uiAccess="false" /> 14 </requestedPrivileges> 15 </security> 16 </trustInfo> 17 <dependency> 18 <dependentAssembly> 19 <assemblyIdentity 20 type="win32" 21 name="Microsoft.Windows.Common-Controls" 22 version="6.0.0.0" 23 processorArchitecture="x86" 24 publicKeyToken="6595b64144ccf1df" 25 language="*" 26 /> 27 </dependentAssembly> 28 </dependency> 29 <dependency> 30 <dependentAssembly> 31 <assemblyIdentity 32 type="win32" 33 name="Microsoft.VC90.CRT" 34 version="9.0.21022.8" 35 processorArchitecture="x86" 36 publicKeyToken="1fc8b3b9a1e18e3b" 37 /> 38 </dependentAssembly> 39 </dependency> 40 </assembly> 41 No newline at end of file -
assembly.manifest
1 <?xml version="1.0" encoding="UTF-8" standalone="yes"?> 2 <assembly xmlns="urn:schemas-microsoft-com:asm.v1" 3 manifestVersion="1.0"> 4 <assemblyIdentity type="win32" name="Microsoft.Tools.SampleAssembly" version="6.0.0.0" processorArchitecture="x86" publicKeyToken="0000000000000000"/> 5 <file name="sampleu.dll" hash="3eab067f82504bf271ed38112a4ccdf46094eb5a" hashalg="SHA1"> 6 <comClass description="Font Property Page" clsid="{0BE35200-8F91-11CE-9DE3-00AA004BB851}"/> 7 <comClass description="Color Property Page" clsid="{0BE35201-8F91-11CE-9DE3-00AA004BB851}"/> 8 <comClass description="Picture Property Page" clsid="{0BE35202-8F91-11CE-9DE3-00AA004BB851}"/> 9 </file> 10 <file name="bar.dll" hash="ac72753e5bb20446d88a48c8f0aaae769a962338" hashalg="SHA1"/> 11 <file name="foo.dll" hash="a7312a1f6cfb46433001e0540458de60adcd5ec5" hashalg="SHA1"> 12 <comClass description="Registrar Class" clsid="{44EC053A-400F-11D0-9DCD-00A0C90391D3}" progid="ATL.Registrar"/> 13 <comInterfaceProxyStub iid="{B6EA2051-048A-11D1-82B9-00C04FB9942E}" name=" IAxWinAmbientDispatch " tlbid="{34EC053A-400F-11D0-9DCD-00A0C90391D3}"/> 14 <typelib tlbid="{44EC0535-400F-11D0-9DCD-00A0C90391D3}" version="1.0" helpdir=""/> 15 </file> 16 <file name="sampledll.dll" hash="ba62960ceb15073d2598379307aad84f3a73dfcb" hashalg="SHA1"/> 17 <windowClass>ToolbarWindow32</windowClass> 18 <windowClass>ComboBoxEx32</windowClass> 19 <windowClass>sample_trackbar32</windowClass> 20 <windowClass>sample_updown32</windowClass> 21 </assembly> 22 No newline at end of file -
bindepend.py
43 43 iswin = sys.platform[:3] == 'win' 44 44 cygwin = sys.platform == 'cygwin' 45 45 46 if iswin: 47 import __builtin__ 48 __builtin__.__dict__["silent"] = False # True suppresses all messages from the assembly dependency code 49 from manifest import RT_MANIFEST, GetManifestResources, ManifestFromXML 50 try: 51 import resource 52 except ImportError, detail: 53 resource = None 54 46 55 excludes = { 47 56 'KERNEL32.DLL':1, 48 57 'ADVAPI.DLL':1, … … 78 87 'PSAPI.DLL':1, 79 88 'MSVCP80.DLL':1, 80 89 'MSVCR80.DLL':1, 90 'MSVCP90.DLL':1, 91 'MSVCR90.DLL':1, 92 'IERTUTIL.DLL':1, 93 'POWRPROF.DLL':1, 94 'SHLWAPI.DLL':1, 95 'URLMON.DLL':1, 81 96 # regex excludes 82 97 # don't include in the bundle the libc and the tls stuff 83 98 r'^/usr/lib/tls':1, … … 87 102 r'/usr/lib/libGL.*':1, 88 103 # 89 104 '^/System/Library/Frameworks':1, 105 # MS assembly excludes 106 'Microsoft.Windows.Common-Controls':1, 90 107 } 91 108 92 109 excludesRe = re.compile('|'.join(excludes.keys()), re.I) … … 283 300 for lib, npth in selectImports(pth, platform, xtrapath): 284 301 if seen.get(string.upper(lib),0): 285 302 continue 303 if iswin: 304 for ftocnm, fn in selectAssemblies(npth): 305 lTOC.append((ftocnm, fn, 'BINARY')) 286 306 lTOC.append((lib, npth, 'BINARY')) 287 307 288 308 return lTOC 289 309 310 def getAssemblies(pth): 311 """Return the dependent assemblies of a binary.""" 312 # check for manifest file 313 manifestnm = pth + ".manifest" 314 if os.path.isfile(manifestnm): 315 fd = open(manifestnm, "rb") 316 res = {RT_MANIFEST: {1: {0: fd.read()}}} 317 fd.close() 318 elif not resource: 319 # resource access unavailable (needs pywin32) 320 if not silent: 321 print "W:", pth 322 print "W: Cannot check for assembly dependencies - resource access" 323 print "W: unavailable. To enable resource access, please install" 324 print "W: http://sourceforge.net/projects/pywin32/" 325 return [] 326 else: 327 # check the binary for embedded manifest 328 res = GetManifestResources(pth) 329 rv = [] 330 if RT_MANIFEST in res and len(res[RT_MANIFEST]): 331 for name in res[RT_MANIFEST]: 332 for language in res[RT_MANIFEST][name]: 333 # check the manifest for dependent assemblies 334 try: 335 manifest = ManifestFromXML(res[RT_MANIFEST][name][language]) 336 except Exception, exc: 337 if not silent: 338 print "E: Could not parse manifest resource of" 339 print "E:", pth 340 print "E:", exc 341 pass 342 else: 343 if manifest.dependentAssemblies and not silent: 344 print "I: Dependent assemblies of %s:" % pth 345 print "I:", ", ".join([assembly.getid() 346 for assembly in 347 manifest.dependentAssemblies]) 348 rv.extend(manifest.dependentAssemblies) 349 return rv 350 351 def selectAssemblies(pth): 352 """Return a binary's dependent assemblies files that should be included. 353 354 Return a list of pairs (name, fullpath) 355 """ 356 rv = [] 357 for assembly in getAssemblies(pth): 358 if assembly.optional or \ 359 excludesRe.search(assembly.name) or \ 360 seen.get(assembly.getid().upper(),0): 361 if assembly.optional and not ( 362 excludesRe.search(assembly.name) or 363 seen.get(assembly.getid().upper(),0)) and not silent: 364 print "I: Skipping search for optional assembly", assembly.name 365 continue 366 files = assembly.find_files() 367 if files: 368 seen[assembly.getid().upper()] = 1 369 for fn in files: 370 fname, fext = os.path.splitext(fn) 371 if fext.lower() == ".manifest": 372 ftocnm = assembly.name + fext 373 else: 374 ftocnm = os.path.basename(fn) 375 ftocnm, fn = [item.encode(sys.getfilesystemencoding()) 376 for item in 377 (os.path.join(assembly.name, ftocnm), fn)] 378 if not seen.get(fn.upper(),0): 379 if not silent: 380 print "I: Adding", ftocnm 381 seen[fn.upper()] = 1 382 rv.append((ftocnm, fn)) 383 else: 384 #print "I: skipping", ftocnm, "part of assembly", assembly.name, "dependency of", pth 385 pass 386 elif not silent: 387 print "E: Assembly", assembly.getid(), "not found" 388 return rv 389 290 390 def selectImports(pth, platform=sys.platform, xtrapath=None): 291 391 """Return the dependencies of a binary that should be included. 292 392 … … 302 402 iswin = platform[:3] == 'win' 303 403 for lib in dlls: 304 404 if not iswin and not cygwin: 305 # plain win case405 # all other platforms 306 406 npth = lib 307 407 dir, lib = os.path.split(lib) 308 408 if excludes.get(dir,0): 309 409 continue 310 410 else: 311 # all other platforms411 # plain win case 312 412 npth = getfullnameof(lib, xtrapath) 313 413 314 # now npth is a candidate lib 414 # now npth is a candidate lib if found 315 415 # check again for excludes but with regex FIXME: split the list 316 if excludesRe.search(npth): 317 if 'libpython' not in npth and 'Python.framework' not in npth: 416 candidatelib = npth if npth else lib 417 if excludesRe.search(candidatelib): 418 if 'libpython' not in candidatelib and 'Python.framework' not in candidatelib: 318 419 # skip libs not containing (libpython or Python.framework) 319 420 #print "I: skipping %20s <- %s" % (npth, pth) 320 421 continue … … 324 425 325 426 if npth: 326 427 rv.append((lib, npth)) 327 el se:428 elif not seen.get(lib.upper(),0): 328 429 print "E: lib not found:", lib, "dependency of", pth 329 430 330 431 return rv … … 388 489 """Forwards to the correct getImports implementation for the platform. 389 490 """ 390 491 if platform[:3] == 'win' or platform == 'cygwin': 391 return _getImports_pe(pth) 492 try: 493 return _getImports_pe(pth) 494 except Exception, exception: 495 # Assemblies can pull in files which aren't necessarily PE, 496 # but are still needed by the assembly. Any additional binary 497 # dependencies should already have been handled by 498 # selectAssemblies in that case, so just warn, return an empty 499 # list and continue. 500 if not silent: 501 print 'I: Cannot get binary dependencies for non-PE file:' 502 print 'I:', pth 503 return [] 392 504 elif platform == 'darwin': 393 505 return _getImports_otool(pth) 394 506 else: … … 471 583 help='Target platform, required for cross-bundling (default: current platform)') 472 584 473 585 opts, args = parser.parse_args() 586 __builtin__.__dict__["silent"] = True # Suppress all messages from the assembly dependency code 474 587 import glob 475 588 for a in args: 476 589 for fn in glob.glob(a): 477 print fn, getImports(fn, opts.target_platform) 590 imports = getImports(fn, opts.target_platform) 591 if opts.target_platform == "win32": 592 imports.extend([a.getid() for a in getAssemblies(fn)]) 593 print fn, imports -
Build.py
627 627 self.name = kws.get('name',None) 628 628 self.icon = kws.get('icon',None) 629 629 self.versrsrc = kws.get('version',None) 630 self.manifest = kws.get('manifest',None) 631 self.resources = kws.get('resources',[]) 630 632 self.strip = kws.get('strip',None) 631 633 self.upx = kws.get('upx',None) 632 634 self.crypt = kws.get('crypt', 0) … … 660 662 ('debug', _check_guts_eq), 661 663 ('icon', _check_guts_eq), 662 664 ('versrsrc', _check_guts_eq), 665 ('manifest', _check_guts_eq), 666 ('resources', _check_guts_eq), 663 667 ('strip', _check_guts_eq), 664 668 ('upx', _check_guts_eq), 665 669 ('crypt', _check_guts_eq), … … 679 683 if not data: 680 684 return True 681 685 682 icon, versrsrc = data[3:5]683 if (icon or versrsrc ) and not config['hasRsrcUpdate']:686 icon, versrsrc, manifest, resources = data[3:7] 687 if (icon or versrsrc or manifest or resources) and not config['hasRsrcUpdate']: 684 688 # todo: really ignore :-) 685 print "ignoring icon and versionresources = platform not capable"689 print "ignoring icon, version, manifest and resources = platform not capable" 686 690 687 691 mtm = data[-1] 688 692 crypt = data[-2] … … 722 726 exe = os.path.join(HOMEPATH, exe) 723 727 if target_iswin or cygwin: 724 728 exe = exe + '.exe' 725 if config['hasRsrcUpdate']: 729 if config['hasRsrcUpdate'] and (self.icon or self.versrsrc or 730 self.manifest or self.resources): 731 tmpnm = tempfile.mktemp() 732 shutil.copy2(exe, tmpnm) 733 os.chmod(tmpnm, 0755) 726 734 if self.icon: 727 tmpnm = tempfile.mktemp()728 shutil.copy2(exe, tmpnm)729 os.chmod(tmpnm, 0755)730 735 icon.CopyIcons(tmpnm, self.icon) 731 trash.append(tmpnm)732 exe = tmpnm733 736 if self.versrsrc: 734 tmpnm = tempfile.mktemp()735 shutil.copy2(exe, tmpnm)736 os.chmod(tmpnm, 0755)737 737 versionInfo.SetVersion(tmpnm, self.versrsrc) 738 trash.append(tmpnm) 739 exe = tmpnm 738 if self.manifest: 739 manifest.UpdateManifestResourcesFromXMLFile(tmpnm, self.manifest, [1]) 740 for res in self.resources: 741 res = res.split(",") 742 for i in range(len(res[1:])): 743 try: 744 res[i + 1] = int(res[i + 1]) 745 except ValueError: 746 pass 747 resfile = res[0] 748 restype = res[1] if len(res) > 1 else None 749 resname = res[2] if len(res) > 2 else None 750 reslang = res[3] if len(res) > 3 else None 751 try: 752 resource.UpdateResourcesFromResFile(tmpnm, resfile, 753 [restype or "*"], 754 [resname or "*"], 755 [reslang or "*"]) 756 except resource.pywintypes.error, exc: 757 if exc.args[0] != resource.ERROR_BAD_EXE_FORMAT: 758 print "E:", str(exc) 759 continue 760 if not restype or not resname: 761 print "E: resource type and/or name not specified" 762 continue 763 if "*" in (restype, resname): 764 print ("E: no wildcards allowed for resource type " 765 "and name when source file does not contain " 766 "resources") 767 continue 768 try: 769 resource.UpdateResourcesFromDataFile(tmpnm, 770 resfile, 771 restype, 772 [resname], 773 [reslang or 0]) 774 except resource.pywintypes.error, exc: 775 print "E:", str(exc) 776 trash.append(tmpnm) 777 exe = tmpnm 740 778 exe = checkCache(exe, self.strip, self.upx and config['hasUPX']) 741 779 self.copy(exe, outf) 742 780 if self.append_pkg: … … 749 787 os.chmod(self.name, 0755) 750 788 _save_data(self.out, 751 789 (self.name, self.console, self.debug, self.icon, 752 self.versrsrc, self. strip, self.upx, self.crypt, mtime(self.name)))790 self.versrsrc, self.manifest, self.resources, self.strip, self.upx, self.crypt, mtime(self.name))) 753 791 for item in trash: 754 792 os.remove(item) 755 793 return 1 … … 773 811 os.chmod(self.name, 0755) 774 812 _save_data(self.out, 775 813 (self.name, self.console, self.debug, self.icon, 776 self.versrsrc, self. strip, self.upx, mtime(self.name)))814 self.versrsrc, self.manifest, self.resources, self.strip, self.upx, mtime(self.name))) 777 815 return 1 778 816 779 817 … … 1106 1144 1107 1145 def main(specfile, configfilename): 1108 1146 global target_platform, target_iswin, config 1109 global icon, versionInfo 1147 global icon, versionInfo, resource, manifest 1110 1148 1111 1149 try: 1112 1150 config = _load_data(configfilename) … … 1130 1168 sys.exit(1) 1131 1169 1132 1170 if config['hasRsrcUpdate']: 1133 import icon, versionInfo 1171 import icon, versionInfo, resource, manifest 1134 1172 1135 1173 if config['hasUPX']: 1136 1174 setupUPXFlags() … … 1146 1184 parser.add_option('-C', '--configfile', 1147 1185 default=os.path.join(HOMEPATH, 'config.dat'), 1148 1186 help='Name of generated configfile (default: %default)') 1187 parser.add_option('-o', '--buildpath', 1188 default=None, 1189 help='Buildpath') 1149 1190 opts, args = parser.parse_args() 1150 1191 if len(args) != 1: 1151 1192 parser.error('Requires exactly one .spec-file') -
Makespec.py
135 135 136 136 def main(scripts, configfile=None, name=None, tk=0, freeze=0, console=1, debug=0, 137 137 strip=0, upx=0, comserver=0, ascii=0, workdir=None, 138 pathex=[], version_file=None, icon_file=None, crypt=None):138 pathex=[], version_file=None, icon_file=None, manifest_file=None, resources=[], crypt=None): 139 139 140 140 try: 141 141 config = eval(open(configfile, 'r').read()) … … 168 168 exe_options = "%s, version='%s'" % (exe_options, quote_win_filepath(version_file)) 169 169 if icon_file: 170 170 exe_options = "%s, icon='%s'" % (exe_options, quote_win_filepath(icon_file)) 171 if manifest_file: 172 exe_options = "%s, manifest='%s'" % (exe_options, quote_win_filepath(manifest_file)) 173 if resources: 174 for i in range(len(resources)): 175 resources[i] = quote_win_filepath(resources[i]) 176 exe_options = "%s, resources=%s" % (exe_options, repr(resources)) 171 177 if not ascii and config['hasUnicode']: 172 178 scripts.insert(0, os.path.join(HOME, 'support', 'useUnicode.py')) 173 179 for i in range(len(scripts)): … … 278 284 dest="version_file", metavar="FILE", 279 285 help="add a version resource from FILE to the exe " 280 286 "(Windows only)") 281 g.add_option("- -icon", type="string", dest="icon_file",287 g.add_option("-i", "--icon", type="string", dest="icon_file", 282 288 metavar="FILE.ICO or FILE.EXE,ID", 283 289 help="If FILE is an .ico file, add the icon to the final " 284 290 "executable. Otherwise, the syntax 'file.exe,id' to " 285 291 "extract the icon with the specified id " 286 292 "from file.exe and add it to the final executable") 293 g.add_option("-m", "--manifest", type="string", 294 dest="manifest_file", metavar="FILE", 295 help="add manifest FILE to the exe " 296 "(Windows only)") 297 g.add_option("-r", "--resource", type="string", default=[], dest="resources", 298 metavar="FILE[,TYPE[,NAME[,LANGUAGE]]]", action="append", 299 help="add/update resource of the given type, name and language " 300 "from FILE to the final executable. FILE can be a " 301 "data file or an exe/dll. For data files, atleast " 302 "TYPE and NAME need to be specified, LANGUAGE defaults " 303 "to 0 or may be specified as wildcard * to update all " 304 "resources of the given TYPE and NAME. For exe/dll " 305 "files, all resources from FILE will be added/updated " 306 "to the final executable if TYPE, NAME and LANGUAGE " 307 "are omitted or specified as wildcard *." 308 "Multiple resources are allowed, using this option " 309 "multiple times.") 287 310 288 311 opts,args = p.parse_args() 289 312 -
manifest.py
1 #!/usr/bin/env python 2 3 """ 4 manifest.py 2009-03 Florian Hoech 5 6 Provides the following functionality: 7 * Create, parse and write MS Windows Manifest files 8 * Find files which are part of an assembly, by looking for shared and 9 private assemblies 10 * Update manifest resources in dll/exe files 11 12 Implemented: 13 * Shared and private assemblies support 14 * Publisher configuration support (.policy files) 15 * application configuration support (.config files) 16 17 Not implemented: 18 * Manifest validation (only very basic sanity checks are currently in place) 19 * comClass, typelib, comInterfaceProxyStub, windowClass subelements of the 20 file element 21 * comInterfaceExternalProxyStub, windowClass subelements of the assembly 22 element 23 24 Reference: 25 About Isolated Applications and Side-by-side Assemblies 26 http://msdn.microsoft.com/en-us/library/aa374029(VS.85).aspx 27 """ 28 import __builtin__ 29 if not "silent" in __builtin__.__dict__: 30 __builtin__.__dict__["silent"] = False # True suppresses all messages from the assembly dependency code 31 try: 32 import hashlib 33 except ImportError, detail: 34 hashlib = None 35 if not silent: 36 print 'I: ... file hash calculation unavailable -', detail 37 import os.path 38 from glob import glob 39 from xml.dom import Node, minidom 40 from xml.dom.minidom import Document, Element 41 42 Document.aChild = Document.appendChild 43 Document.cE = Document.createElement 44 Document.cT = Document.createTextNode 45 Document.getEById = Document.getElementById 46 Document.getEByTN = Document.getElementsByTagName 47 Element.aChild = Element.appendChild 48 Element.getA = Element.getAttribute 49 Element.getEByTN = Element.getElementsByTagName 50 Element.remA = Element.removeAttribute 51 Element.setA = Element.setAttribute 52 53 try: 54 import resource 55 except ImportError, detail: 56 resource = None 57 if not silent: 58 print "W:", detail 59 print "W: Cannot check for assembly dependencies - resource access " 60 print "W: unavailable. To enable resource access, please install " 61 print "W: http://sourceforge.net/projects/pywin32/" 62 63 RT_MANIFEST = 24 64 65 def getChildElementsByTagName(self, tagName): 66 """ Return child elements of type tagName if found, else [] """ 67 result = [] 68 for child in self.childNodes: 69 if isinstance(child, Element): 70 if child.tagName == tagName: 71 result.append(child) 72 return result 73 74 def getFirstChildElementByTagName(self, tagName): 75 """ Return the first element of type tagName if found, else None """ 76 for child in self.childNodes: 77 if isinstance(child, Element): 78 if child.tagName == tagName: 79 return child 80 return None 81 82 Document.getCEByTN = getChildElementsByTagName 83 Document.getFCEByTN = getFirstChildElementByTagName 84 Element.getCEByTN = getChildElementsByTagName 85 Element.getFCEByTN = getFirstChildElementByTagName 86 87 def find_files(files, searchpath): 88 rfiles = [] 89 for file_ in files: 90 fn = file_.find(searchpath) 91 if fn: 92 rfiles.append(fn) 93 else: 94 # if any of our files does not exist, 95 # the assembly is incomplete 96 return [] 97 return rfiles 98 99 100 class _Dummy: 101 pass 102 103 104 class File(resource.File if resource else _Dummy): 105 106 """ A file referenced by an assembly inside a manifest. """ 107 108 def __init__(self, filename="", hashalg=None, hash=None, comClasses=None, 109 typelibs=None, comInterfaceProxyStubs=None, 110 windowClasses=None): 111 if resource: 112 resource.File.__init__(self, filename) 113 else: 114 self.filename = filename 115 self.name = os.path.basename(filename) 116 self.hashalg = hashalg.upper() if hashalg else None 117 if os.path.isfile(filename) and hashalg and hashlib: 118 self.calc_hash() 119 else: 120 self.hash = hash 121 self.comClasses = comClasses or [] # TO-DO: implement 122 self.typelibs = typelibs or [] # TO-DO: implement 123 self.comInterfaceProxyStubs = comInterfaceProxyStubs or [] # TO-DO: implement 124 self.windowClasses = windowClasses or [] # TO-DO: implement 125 126 def calc_hash(self, hashalg=None): 127 """ Calculate the hash of the file. Will be called automatically from 128 the constructor if the file exists and hashalg is given, but may 129 also be called manually e.g. to update the hash if the file has 130 changed. """ 131 fd = open(self.filename, "rb") 132 buf = fd.read() 133 fd.close() 134 if hashalg: 135 self.hashalg = hashalg.upper() 136 self.hash = getattr(hashlib, self.hashalg.lower())(buf).hexdigest() 137 138 def find(self, searchpath): 139 if not silent: 140 print "I: Searching for file", self.name 141 fn = os.path.join(searchpath, self.name) 142 if os.path.isfile(fn): 143 if not silent: 144 print "I: Found file", fn 145 return fn 146 else: 147 if not silent: 148 print "W: No such file", fn 149 return None 150 151 class InvalidManifestError(Exception): 152 pass 153 154 155 class Manifest(): 156 157 def __init__(self, manifestVersion=None, noInheritable=False, 158 noInherit=False, type_=None, name=None, language=None, 159 processorArchitecture=None, version=None, 160 publicKeyToken=None, description=None, 161 requestedExecutionLevel=None, uiAccess=None, 162 dependentAssemblies=None, files=None, 163 comInterfaceExternalProxyStubs=None): 164 """ Manifest constructor. 165 166 To build a basic manifest for your application: 167 mf = Manifest(type='win32', name='YourAppName', language='*', 168 processorArchitecture='x86', version=[1, 0, 0, 0]) 169 170 To write the XML to a manifest file: 171 mf.writexml("YourAppName.exe.manifest") 172 or 173 mf.writeprettyxml("YourAppName.exe.manifest") 174 """ 175 self.filename = None 176 self.optional = None 177 self.manifestType = "assembly" 178 self.manifestVersion = manifestVersion or [1, 0] 179 self.noInheritable = noInheritable 180 self.noInherit = noInherit 181 self.type = type_ 182 self.name = name 183 self.language = language 184 self.processorArchitecture = processorArchitecture 185 self.version = version 186 self.publicKeyToken = publicKeyToken 187 # public key token 188 # "A 16-character hexadecimal string that represents the last 8 bytes 189 # of the SHA-1 hash of the public key under which the assembly is 190 # signed. The public key used to sign the catalog must be 2048 bits 191 # or greater. Required for all shared side-by-side assemblies." 192 # http://msdn.microsoft.com/en-us/library/aa375692(VS.85).aspx 193 self.applyPublisherPolicy = None 194 self.description = None 195 self.requestedExecutionLevel = requestedExecutionLevel 196 self.uiAccess = uiAccess 197 self.dependentAssemblies = dependentAssemblies or [] 198 self.bindingRedirects = [] 199 self.files = files or [] 200 self.comInterfaceExternalProxyStubs = comInterfaceExternalProxyStubs or [] # TO-DO: implement 201 202 def add_dependent_assembly(self, manifestVersion=None, noInheritable=False, 203 noInherit=False, type_=None, name=None, language=None, 204 processorArchitecture=None, version=None, 205 publicKeyToken=None, description=None, 206 requestedExecutionLevel=None, uiAccess=None, 207 dependentAssemblies=None, files=None, 208 comInterfaceExternalProxyStubs=None): 209 """ Shortcut for: 210 manifest.dependentAssemblies.append(Manifest(*args, *kwargs)) """ 211 self.dependentAssemblies.append(Manifest(manifestVersion, 212 noInheritable, noInherit, type_, name, 213 language, processorArchitecture, 214 version, publicKeyToken, description, 215 requestedExecutionLevel, uiAccess, 216 dependentAssemblies, files, 217 comInterfaceExternalProxyStubs)) 218 219 def add_file(self, name="", hashalg="", hash="", comClasses=None, 220 typelibs=None, comInterfaceProxyStubs=None, 221 windowClasses=None): 222 """ Shortcut for: 223 manifest.files.append(File(*args, *kwargs)) """ 224 self.files.append(File(name, hashalg, hash, comClasses, 225 typelibs, comInterfaceProxyStubs, windowClasses)) 226 227 def find_files(self): 228 """ Search shared and private assemblies and return a list of all 229 related files if found. If any files are not found, return an empty 230 list.""" 231 if None in (self.processorArchitecture, self.name, self.publicKeyToken, 232 self.version): 233 if not silent: 234 print "W: Assembly metadata incomplete - file search not possible" 235 return [] 236 if not silent: 237 print "I: Searching for files of assembly %s..." % self.getid() 238 files = [] 239 # search winsxs 240 winsxs = os.path.join(os.getenv('SystemRoot'), 'WinSxS') 241 if os.path.isdir(winsxs): 242 manifests = os.path.join(winsxs, "Manifests") 243 if os.path.isdir(manifests): 244 for manifestpth in glob(os.path.join(manifests, 245 self.getid() + "_*.manifest")): 246 assemblynm = os.path.basename(os.path.splitext(manifestpth)[0]) 247 if not os.path.isfile(manifestpth): 248 if not silent: 249 print "W: No such file", manifestpth 250 continue 251 if not silent: 252 print "I: Found manifest", manifestpth 253 assemblydir = os.path.join(winsxs, assemblynm) 254 if not os.path.isdir(assemblydir): 255 if not silent: 256 print "W: No such dir", assemblydir 257 continue 258 try: 259 manifest = ManifestFromXMLFile(manifestpth) 260 except Exception, exc: 261 if not silent: 262 print "E: Could not parse manifest", manifestpth 263 print "E:", exc 264 pass 265 else: 266 rfiles = find_files(self.files or manifest.files, assemblydir) 267 if rfiles: 268 files.append(manifestpth) 269 files.extend(rfiles) 270 return files 271 break 272 elif not silent: 273 print "W: No such dir", manifests 274 elif not silent: 275 print "W: No such dir", winsxs 276 # search for private assemblies 277 if not self.filename: 278 return [] 279 dirnm = os.path.dirname(self.filename) 280 # if embedded in a dll the assembly may have the same name as the 281 # dll, so we need to make sure we don't search for *.dll.dll 282 assemblynm, ext = os.path.splitext(self.name) 283 if ext.lower() == ".dll": 284 # discard the extension 285 pass 286 else: 287 assemblynm = self.name 288 for path in [os.path.join(dirnm, self.language or "*"), 289 os.path.join(dirnm, self.language or "*", assemblynm), 290 dirnm, 291 os.path.join(dirnm, assemblynm)]: 292 for ext in (".dll", ".manifest"): 293 # private assemblies can have the manifest either as 294 # separate file or embedded in a DLL 295 manifestpth = os.path.join(path, assemblynm + ext) 296 if not os.path.isfile(manifestpth): 297 if not silent: 298 print "W: No such file", manifestpth 299 continue 300 if not silent: 301 print "I: Found manifest", manifestpth 302 try: 303 if ext == ".dll": 304 manifest = ManifestFromResFile(manifestpth, [1]) 305 else: 306 manifest = ManifestFromXMLFile(manifestpth) 307 except Exception, exc: 308 if not silent: 309 print "E: Could not parse manifest", manifestpth 310 print "E:", exc 311 pass 312 else: 313 rfiles = find_files(self.files or manifest.files, path) 314 if not rfiles: 315 return [] 316 files.append(manifestpth) 317 files.extend(rfiles) 318 break 319 if not os.path.isfile(manifestpth): 320 for file_ in self.files: 321 fn = os.path.join(path, file_.name) 322 if os.path.exists(fn): 323 # if any of our files does exist without the manifest 324 # in the same dir, the assembly is incomplete 325 return [] 326 return files 327 328 def getid(self): 329 return '%s_%s_%s_%s' % (self.processorArchitecture, 330 self.name, 331 self.publicKeyToken, 332 ".".join([str(i) 333 for i in 334 self.version])) 335 336 def load_dom(self, domtree, initialize=True): 337 """ Load manifest from DOM tree. 338 If initialize is True (default), reset existing attributes first.""" 339 if domtree.nodeType == Node.DOCUMENT_NODE: 340 rootElement = domtree.documentElement 341 elif domtree.nodeType == Node.ELEMENT_NODE: 342 rootElement = domtree 343 else: 344 raise InvalidManifestError("Invalid root element node type " + 345 str(rootElement.nodeType) + 346 " - has to be one of (DOCUMENT_NODE, ELEMENT_NODE)") 347 allowed_names = ("assembly", "assemblyBinding", "configuration", 348 "dependentAssembly") 349 if rootElement.tagName not in allowed_names: 350 raise InvalidManifestError("Invalid root element <" + 351 rootElement.tagName + 352 "> - has to be one of " + 353 repr(allowed_names)) 354 # print "I: loading manifest metadata from element <%s>" % \ 355 # rootElement.tagName 356 if rootElement.tagName == "configuration": 357 for windows in rootElement.getCEByTN("windows"): 358 for assemblyBinding in windows.getCEByTN("assemblyBinding"): 359 self.load_dom(assemblyBinding) 360 else: 361 if initialize: 362 self.__init__() 363 self.manifestType = rootElement.tagName 364 self.manifestVersion = [int(i) for i in (rootElement.getA("manifestVersion") or "1.0").split(".")] 365 self.noInheritable = bool(rootElement.getFCEByTN("noInheritable")) 366 self.noInherit = bool(rootElement.getFCEByTN("noInherit")) 367 for assemblyIdentity in rootElement.getCEByTN("assemblyIdentity"): 368 self.type = assemblyIdentity.getA("type") 369 self.name = assemblyIdentity.getA("name") 370 self.language = assemblyIdentity.getA("language") 371 self.processorArchitecture = assemblyIdentity.getA("processorArchitecture") 372 self.version = [int(i) for i in (assemblyIdentity.getA("version") or "0.0.0.0").split(".")] 373 self.publicKeyToken = assemblyIdentity.getA("publicKeyToken") 374 for publisherPolicy in rootElement.getCEByTN("publisherPolicy"): 375 self.applyPublisherPolicy = (publisherPolicy.getA("apply") or "").lower() == "yes" 376 for description in rootElement.getCEByTN("description"): 377 if description.firstChild: 378 self.description = description.firstChild.wholeText 379 for trustInfo in rootElement.getCEByTN("trustInfo"): 380 for security in trustInfo.getCEByTN("security"): 381 for requestedPrivileges in security.getCEByTN("requestedPrivileges"): 382 for requestedExecutionLevel in requestedPrivileges.getCEByTN("requestedExecutionLevel"): 383 self.requestedExecutionLevel = requestedExecutionLevel.getA("level") 384 self.uiAccess = (requestedExecutionLevel.getA("uiAccess") or "").lower() == "true" 385 for dependency in (rootElement.getCEByTN("dependency") if 386 rootElement.tagName != "assemblyBinding" else 387 [rootElement]): 388 for dependentAssembly in dependency.getCEByTN("dependentAssembly"): 389 manifest = ManifestFromDOM(dependentAssembly) 390 manifest.optional = (dependency.getA("optional") or "").lower() == "yes" 391 self.dependentAssemblies.append(manifest) 392 for bindingRedirect in rootElement.getCEByTN("bindingRedirect"): 393 oldVersion = [[int(i) for i in part.split(".")] for part in bindingRedirect.getA("oldVersion").split("-")] 394 newVersion = [int(i) for i in bindingRedirect.getA("newVersion").split(".")] 395 self.bindingRedirects.append((oldVersion, newVersion)) 396 for file_ in rootElement.getCEByTN("file"): 397 self.add_file(name=file_.getA("name"), 398 hashalg=file_.getA("hashalg"), 399 hash=file_.getA("hash")) 400 401 def parse(self, filename_or_file): 402 """ Load manifest from file or file object """ 403 self.load_dom(minidom.parse(filename_or_file)) 404 if isinstance(filename_or_file, (str, unicode)): 405 self.filename = filename_or_file 406 else: 407 self.filename = filename_or_file.filename 408 409 def parse_string(self, xmlstr): 410 """ Load manifest from XML string """ 411 self.load_dom(minidom.parseString(xmlstr)) 412 413 def todom(self): 414 """ Return the manifest as DOM tree """ 415 doc = Document() 416 docE = doc.cE(self.manifestType) 417 if self.manifestType == "assemblyBinding": 418 cfg = doc.cE("configuration") 419 win = doc.cE("windows") 420 win.aChild(docE) 421 cfg.aChild(win) 422 doc.aChild(cfg) 423 else: 424 doc.aChild(docE) 425 if self.manifestType != "dependentAssembly": 426 docE.setA("xmlns", "urn:schemas-microsoft-com:asm.v1") 427 if self.manifestType != "assemblyBinding": 428 docE.setA("manifestVersion", 429 ".".join([str(i) for i in self.manifestVersion])) 430 if self.noInheritable: 431 docE.aChild(doc.cE("noInheritable")) 432 if self.noInherit: 433 docE.aChild(doc.cE("noInherit")) 434 aId = doc.cE("assemblyIdentity") 435 if self.type: 436 aId.setAttribute("type", self.type) 437 if self.name: 438 aId.setAttribute("name", self.name) 439 if self.language: 440 aId.setAttribute("language", self.language) 441 if self.processorArchitecture: 442 aId.setAttribute("processorArchitecture", 443 self.processorArchitecture) 444 if self.version: 445 aId.setAttribute("version", 446 ".".join([str(i) for i in self.version])) 447 if self.publicKeyToken: 448 aId.setAttribute("publicKeyToken", self.publicKeyToken) 449 if aId.hasAttributes(): 450 docE.aChild(aId) 451 else: 452 aId.unlink() 453 if self.applyPublisherPolicy != None: 454 ppE = doc.cE("publisherPolicy") 455 ppE.setA("apply", "yes" if self.applyPublisherPolicy else "no") 456 docE.aChild(ppE) 457 if self.description: 458 descE = doc.cE("description") 459 descE.aChild(doc.cT(self.description)) 460 docE.aChild(descE) 461 if self.requestedExecutionLevel in ("asInvoker", "highestAvailable", 462 "requireAdministrator"): 463 tE = doc.cE("trustInfo") 464 tE.setA("xmlns", "urn:schemas-microsoft-com:asm.v3") 465 sE = doc.cE("security") 466 rpE = doc.cE("requestedPrivileges") 467 relE = doc.cE("requestedExecutionLevel") 468 relE.setA("level", self.requestedExecutionLevel) 469 relE.setA("uiAccess", "true" if self.uiAccess else "false") 470 rpE.aChild(relE) 471 sE.aChild(rpE) 472 tE.aChild(sE) 473 docE.aChild(tE) 474 if self.dependentAssemblies: 475 for assembly in self.dependentAssemblies: 476 if self.manifestType != "assemblyBinding": 477 dE = doc.cE("dependency") 478 if assembly.optional: 479 dE.setAttribute("optional", "yes") 480 daE = doc.cE("dependentAssembly") 481 adom = assembly.todom() 482 for child in adom.documentElement.childNodes: 483 daE.aChild(child.cloneNode(False)) 484 adom.unlink() 485 if self.manifestType != "assemblyBinding": 486 dE.aChild(daE) 487 docE.aChild(dE) 488 else: 489 docE.aChild(daE) 490 if self.bindingRedirects: 491 for bindingRedirect in self.bindingRedirects: 492 brE = doc.cE("bindingRedirect") 493 brE.setAttribute("oldVersion", 494 "-".join(".".join(str(i) for i in part) for part in bindingRedirect[0])) 495 brE.setAttribute("newVersion", 496 ".".join(str(i) for i in bindingRedirect[1])) 497 docE.aChild(brE) 498 if self.files: 499 for file_ in self.files: 500 fE = doc.cE("file") 501 for attr in ("name", "hashalg", "hash"): 502 val = getattr(file_, attr) 503 if val: 504 fE.setA(attr, val) 505 docE.aChild(fE) 506 return doc 507 508 def toprettyxml(self, indent=" ", newl=os.linesep, encoding="UTF-8"): 509 """ Return the manifest as pretty-printed XML """ 510 domtree = self.todom() 511 # WARNING: The XML declaration has to follow the order version-encoding-standalone (standalone being optional), 512 # otherwise if it is embedded in an exe the exe will fail to launch! ('application configuration incorrect') 513 xmlstr = domtree.toprettyxml(indent, newl, encoding).strip(os.linesep).replace('<?xml version="1.0" encoding="UTF-8"?>', 514 '<?xml version="1.0" encoding="%s" standalone="yes"?>' % encoding) 515 domtree.unlink() 516 return xmlstr 517 518 def toxml(self, encoding="UTF-8"): 519 """ Return the manifest as XML """ 520 domtree = self.todom() 521 # WARNING: The XML declaration has to follow the order version-encoding-standalone (standalone being optional), 522 # otherwise if it is embedded in an exe the exe will fail to launch! ('application configuration incorrect') 523 xmlstr = domtree.toxml(encoding).replace('<?xml version="1.0" encoding="UTF-8"?>', 524 '<?xml version="1.0" encoding="%s" standalone="yes"?>' % encoding) 525 domtree.unlink() 526 return xmlstr 527 528 def update_resources(self, dstpath, names=None, languages=None): 529 """ Update or add manifest to dll/exe file dstpath, as manifest 530 resource """ 531 UpdateManifestResourcesFromXML(dstpath, self.toprettyxml(), names, 532 languages) 533 534 def writeprettyxml(self, filename_or_file, indent=" ", newl=os.linesep, encoding="UTF-8"): 535 """ Write the manifest as XML to a file or file object """ 536 if isinstance(filename_or_file, (str, unicode)): 537 filename_or_file = open(filename_or_file, "wb") 538 xmlstr = self.toprettyxml(indent, newl, encoding) 539 filename_or_file.write(xmlstr) 540 filename_or_file.close() 541 542 def writexml(self, filename_or_file, indent=" ", newl=os.linesep, encoding="UTF-8"): 543 """ Write the manifest as XML to a file or file object """ 544 if isinstance(filename_or_file, (str, unicode)): 545 filename_or_file = open(filename_or_file, "wb") 546 xmlstr = self.toxml(indent, newl, encoding) 547 filename_or_file.write(xmlstr) 548 filename_or_file.close() 549 550 def ManifestFromResFile(filename, names=None, languages=None): 551 """ Create and return manifest instance from manifest resource in 552 dll/exe file """ 553 res = GetManifestResources(filename, names, languages) 554 if res and res[RT_MANIFEST]: 555 while isinstance(res, dict) and res.keys(): 556 res = res[res.keys()[0]] 557 if isinstance(res, dict): 558 raise InvalidManifestError("No manifest resource found in '%s'" % 559 filename) 560 manifest = ManifestFromXML(res) 561 manifest.filename = filename 562 return manifest 563 564 def ManifestFromDOM(domtree): 565 """ Create and return manifest instance from DOM tree """ 566 manifest = Manifest() 567 manifest.load_dom(domtree) 568 return manifest 569 570 def ManifestFromXML(xmlstr): 571 """ Create and return manifest instance from XML """ 572 manifest = Manifest() 573 manifest.parse_string(xmlstr) 574 return manifest 575 576 def ManifestFromXMLFile(filename_or_file): 577 """ Create and return manifest instance from manifest file """ 578 manifest = Manifest() 579 manifest.parse(filename_or_file) 580 return manifest 581 582 def GetManifestResources(filename, names=None, languages=None): 583 """ Get manifest resources from dll/exe file """ 584 return resource.GetResources(filename, [RT_MANIFEST], names, languages) 585 586 def UpdateManifestResourcesFromXML(dstpath, xmlstr, names=None, 587 languages=None): 588 """ Update or add manifest XML to dll/exe file dstpath, as manifest 589 resource """ 590 if not silent: 591 print "I: Updating manifest in", dstpath 592 name = 1 if dstpath.lower().endswith(".exe") else 2 593 resource.UpdateResources(dstpath, xmlstr, RT_MANIFEST, names or [name], 594 languages or [0, "*"]) 595 596 def UpdateManifestResourcesFromXMLFile(dstpath, srcpath, names=None, 597 languages=None): 598 """ Update or add manifest XML from file srcpath to dll/exe file 599 dstpath, as manifest resource """ 600 if not silent: 601 print "I: Updating manifest from", srcpath, "to", dstpath 602 name = 1 if dstpath.lower().endswith(".exe") else 2 603 resource.UpdateResourcesFromDataFile(dstpath, srcpath, RT_MANIFEST, 604 names or [name], 605 languages or [0, "*"]) 606 607 if __name__ == "__main__": 608 import sys 609 610 dstpath = sys.argv[1] 611 srcpath = sys.argv[2] 612 UpdateManifestResourcesFromXMLFile(dstpath, srcpath) 613 No newline at end of file -
publisher.policy
1 <?xml version="1.0" encoding="UTF-8" standalone="yes"?> 2 <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> 3 <assemblyIdentity type="win32-policy" publicKeyToken="0000000000000000" name="policy.2.0.Microsoft.Windows.SampleAssembly" version="1.1.0.0" processorArchitecture="x86"/> 4 <dependency> 5 <dependentAssembly> 6 <assemblyIdentity type="win32" name="Microsoft.Windows.SampleAssembly" processorArchitecture="x86" publicKeyToken="75e377300ab7b886"/> 7 <bindingRedirect oldVersion="2.0.0.0" newVersion="2.0.1.0"/> 8 </dependentAssembly> 9 </dependency> 10 </assembly> 11 No newline at end of file -
resource.py
1 #!/usr/bin/env python 2 3 import os.path 4 import pywintypes 5 import win32api 6 7 LOAD_LIBRARY_AS_DATAFILE = 2 8 ERROR_BAD_EXE_FORMAT = 193 9 ERROR_RESOURCE_DATA_NOT_FOUND = 1812 10 ERROR_RESOURCE_TYPE_NOT_FOUND = 1813 11 ERROR_RESOURCE_NAME_NOT_FOUND = 1814 12 ERROR_RESOURCE_LANG_NOT_FOUND = 1815 13 14 class File(): 15 def __init__(self, filename): 16 self.filename = filename 17 18 def get_resources(self, types=None, names=None, languages=None): 19 """ Get resources. 20 types = a list of resource types to search for (None = all) 21 names = a list of resource names to search for (None = all) 22 languages = a list of resource languages to search for (None = all) 23 Return a dict of the form {type_: {name: {language: data}}} which 24 might also be empty if no matching resources were found.""" 25 return GetResources(self.filename, types, names, languages) 26 27 def update_resources(self, data, type_, names=None, languages=None): 28 """ Update or add resource data. 29 type_ = resource type to update 30 names = a list of resource names to update (None = all) 31 languages = a list of resource languages to update (None = all)""" 32 UpdateResources(self.filename, data, type_, names, languages) 33 34 def update_resources_from_datafile(self, srcpath, type_, names=None, 35 languages=None): 36 """ Update or add resource data from file srcpath. 37 type_ = resource type to update 38 names = a list of resource names to update (None = all) 39 languages = a list of resource languages to update (None = all)""" 40 UpdateResourcesFromDataFile(self.filename, srcpath, type_, names, 41 languages) 42 43 def update_resources_from_dict(self, res, types=None, names=None, 44 languages=None): 45 """ Update or add resources from resource dict. 46 types = a list of resource types to update (None = all) 47 names = a list of resource names to update (None = all) 48 languages = a list of resource languages to update (None = all)""" 49 UpdateResourcesFromDict(self.filename, res, types, names, 50 languages) 51 52 def update_resources_from_resfile(self, srcpath, types=None, names=None, 53 languages=None): 54 """ Update or add resources from dll/exe file srcpath. 55 types = a list of resource types to update (None = all) 56 names = a list of resource names to update (None = all) 57 languages = a list of resource languages to update (None = all)""" 58 UpdateResourcesFromResFile(self.filename, srcpath, types, names, 59 languages) 60 61 def _GetResources(hsrc, types=None, names=None, languages=None): 62 """ Get resources from hsrc. 63 types = a list of resource types to search for (None = all) 64 names = a list of resource names to search for (None = all) 65 languages = a list of resource languages to search for (None = all) 66 Return a dict of the form {type_: {name: {language: data}}} which 67 might also be empty if no matching resources were found.""" 68 res = {} 69 try: 70 # print "I: Enumerating resource types" 71 enum_types = win32api.EnumResourceTypes(hsrc) 72 if types and not "*" in types: 73 enum_types = filter(lambda type_: 74 type_ in types, 75 enum_types) 76 for type_ in enum_types: 77 # print "I: Enumerating resources of type", type_ 78 enum_names = win32api.EnumResourceNames(hsrc, type_) 79 if names and not "*" in names: 80 enum_names = filter(lambda name: 81 name in names, 82 enum_names) 83 for name in enum_names: 84 # print "I: Enumerating resources of type", type_, "name", name 85 enum_languages = win32api.EnumResourceLanguages(hsrc, 86 type_, 87 name) 88 if languages and not "*" in languages: 89 enum_languages = filter(lambda language: 90 language in languages, 91 enum_languages) 92 for language in enum_languages: 93 data = win32api.LoadResource(hsrc, type_, name, language) 94 if not type_ in res: 95 res[type_] = {} 96 if not name in res[type_]: 97 res[type_][name] = {} 98 res[type_][name][language] = data 99 except pywintypes.error, exception: 100 if exception.args[0] in (ERROR_RESOURCE_DATA_NOT_FOUND, 101 ERROR_RESOURCE_TYPE_NOT_FOUND, 102 ERROR_RESOURCE_NAME_NOT_FOUND, 103 ERROR_RESOURCE_LANG_NOT_FOUND): 104 # print "I:", exception.args[1] + ":", \ 105 # exception.args[2] 106 pass 107 else: 108 raise exception 109 return res 110 111 def GetResources(filename, types=None, names=None, languages=None): 112 """ Get resources from dll/exe file. 113 types = a list of resource types to search for (None = all) 114 names = a list of resource names to search for (None = all) 115 languages = a list of resource languages to search for (None = all) 116 Return a dict of the form {type_: {name: {language: data}}} which 117 might also be empty if no matching resources were found.""" 118 hsrc = win32api.LoadLibraryEx(filename, 0, LOAD_LIBRARY_AS_DATAFILE) 119 res = _GetResources(hsrc, types, names, languages) 120 win32api.FreeLibrary(hsrc) 121 return res 122 123 def UpdateResources(dstpath, data, type_, names=None, languages=None): 124 """ Update or add resource data to dll/exe file dstpath. 125 type_ = resource type to update 126 names = a list of resource names to update (None = all) 127 languages = a list of resource languages to update (None = all)""" 128 # look for existing resources 129 res = GetResources(dstpath, [type_], names, languages) 130 # add type_, names and languages not already present in existing resources 131 if not type_ in res and type_ != "*": 132 res[type_] = {} 133 if names: 134 for name in names: 135 if not name in res[type_] and name != "*": 136 res[type_][name] = [] 137 if languages: 138 for language in languages: 139 if not language in res[type_][name] and language != "*": 140 res[type_][name].append(language) 141 # add resource to destination, overwriting existing resources 142 hdst = win32api.BeginUpdateResource(dstpath, 0) 143 for type_ in res: 144 for name in res[type_]: 145 for language in res[type_][name]: 146 print "I: Updating resource type", type_, "name", name, "language", language 147 win32api.UpdateResource(hdst, type_, name, data, language) 148 win32api.EndUpdateResource(hdst, 0) 149 150 def UpdateResourcesFromDataFile(dstpath, srcpath, type_, names=None, 151 languages=None): 152 """ Update or add resource data from file srcpath to dll/exe file 153 dstpath. 154 type_ = resource type to update 155 names = a list of resource names to update (None = all) 156 languages = a list of resource languages to update (None = all)""" 157 src = open(srcpath, "rb") 158 data = src.read() 159 src.close() 160 UpdateResources(dstpath, data, type_, names, languages) 161 162 def UpdateResourcesFromDict(dstpath, res, types=None, names=None, 163 languages=None): 164 """ Update or add resources from resource dict to dll/exe file 165 dstpath. 166 types = a list of resource types to update (None = all) 167 names = a list of resource names to update (None = all) 168 languages = a list of resource languages to update (None = all)""" 169 for type_ in res: 170 if not types or type_ in types: 171 for name in res[type_]: 172 if not names or name in names: 173 for language in res[type_][name]: 174 if not languages or language in languages: 175 UpdateResources(dstpath, 176 res[type_][name][language], 177 [type_], [name], [language]) 178 179 def UpdateResourcesFromResFile(dstpath, srcpath, types=None, names=None, 180 languages=None): 181 """ Update or add resources from dll/exe file srcpath to dll/exe file 182 dstpath. 183 types = a list of resource types to update (None = all) 184 names = a list of resource names to update (None = all) 185 languages = a list of resource languages to update (None = all)""" 186 res = GetResources(srcpath, types, names, languages) 187 UpdateResourcesFromDict(dstpath, res) 188 No newline at end of file
