Attachments you submit will be routed for moderation. If you have an account, please log in first.

Ticket #39: pyinstaller-trunk-r681-py26-win-tweaks-20090618.patch

File pyinstaller-trunk-r681-py26-win-tweaks-20090618.patch, 58.3 KB (added by openticket, 15 months ago)

- chg: assembly file handling code now uses glob instead of os.listdir and re.match

  • 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"  
     3manifestVersion="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

     
    4343iswin = sys.platform[:3] == 'win' 
    4444cygwin = sys.platform == 'cygwin' 
    4545 
     46if iswin: 
     47    from manifest import RT_MANIFEST, GetManifestResources, ManifestFromXML 
     48    try: 
     49        import resource 
     50    except ImportError, detail: 
     51        resource = None 
     52 
    4653excludes = { 
    4754    'KERNEL32.DLL':1, 
    4855    'ADVAPI.DLL':1, 
     
    7885    'PSAPI.DLL':1, 
    7986    'MSVCP80.DLL':1, 
    8087    'MSVCR80.DLL':1, 
     88    'IERTUTIL.DLL':1, 
     89    'POWRPROF.DLL':1, 
     90    'SHLWAPI.DLL':1, 
     91    'URLMON.DLL':1, 
    8192    # regex excludes 
    8293    # don't include in the bundle the libc and the tls stuff 
    8394    r'^/usr/lib/tls':1, 
     
    8798    r'/usr/lib/libGL.*':1, 
    8899    # 
    89100    '^/System/Library/Frameworks':1, 
     101    # MS assembly excludes 
     102    'Microsoft.Windows.Common-Controls':1, 
    90103} 
    91104 
    92105excludesRe = re.compile('|'.join(excludes.keys()), re.I) 
     
    283296        for lib, npth in selectImports(pth, platform, xtrapath): 
    284297            if seen.get(string.upper(lib),0): 
    285298                continue 
     299            if iswin: 
     300                for ftocnm, fn in selectAssemblies(npth): 
     301                    lTOC.append((ftocnm, fn, 'BINARY')) 
    286302            lTOC.append((lib, npth, 'BINARY')) 
    287303 
    288304    return lTOC 
    289305 
     306def selectAssemblies(npth): 
     307    """Return the dependent assemblies of a binary that should be included. 
     308 
     309    Return a list of pairs (name, fullpath) 
     310    """ 
     311    # check for manifest file 
     312    manifestnm = npth + ".manifest" 
     313    if os.path.isfile(manifestnm): 
     314        fd = open(manifestnm, "rb") 
     315        res = {RT_MANIFEST: {1: {0: fd.read()}}} 
     316        fd.close() 
     317    elif not resource: 
     318        # resource access unavailable (needs pywin32) 
     319        return [] 
     320    else: 
     321        # check the binary for embedded manifest 
     322        res = GetManifestResources(npth) 
     323    rv = [] 
     324    if RT_MANIFEST in res and len(res[RT_MANIFEST]): 
     325        for name in res[RT_MANIFEST]: 
     326            for language in res[RT_MANIFEST][name]: 
     327                # check the manifest for dependent assemblies 
     328                try: 
     329                    manifest = ManifestFromXML(res[RT_MANIFEST][name][language]) 
     330                except Exception, exc: 
     331                    print "E:", npth, str(exc) 
     332                    pass 
     333                else: 
     334                    for assembly in manifest.dependentAssemblies: 
     335                        if assembly.optional or \ 
     336                           excludesRe.search(assembly.name) or \ 
     337                           seen.get(assembly.name.upper(),0): 
     338                            #print "I: skipping assembly:", assembly.name, "dependency of", npth 
     339                            continue 
     340                        files = assembly.find_files() 
     341                        if files: 
     342                            seen[assembly.name.upper()] = 1 
     343                            for fn in files: 
     344                                fname, fext = os.path.splitext(fn) 
     345                                if fext.lower() == ".manifest": 
     346                                    ftocnm = assembly.name + fext 
     347                                else: 
     348                                    ftocnm = os.path.basename(fn) 
     349                                ftocnm, fn = [item.encode(sys.getfilesystemencoding()) for item in (ftocnm, fn)] 
     350                                if not excludesRe.search(ftocnm) and \ 
     351                                   not seen.get(ftocnm.upper(),0): 
     352                                    print "I: SRCPATH:", fn 
     353                                    print "I:", ftocnm, "part of assembly", assembly.name, "dependency of", npth 
     354                                    seen[ftocnm.upper()] = 1 
     355                                    rv.append((ftocnm, fn)) 
     356                                else: 
     357                                    #print "I: skipping", ftocnm, "part of assembly", assembly.name, "dependency of", npth 
     358                                    pass 
     359                        else: 
     360                            print "E: assembly not found:", assembly.name, "dependency of", npth 
     361    return rv 
     362 
    290363def selectImports(pth, platform=sys.platform, xtrapath=None): 
    291364    """Return the dependencies of a binary that should be included. 
    292365 
     
    302375    iswin = platform[:3] == 'win' 
    303376    for lib in dlls: 
    304377        if not iswin and not cygwin: 
    305                 # plain win case 
     378            # all other platforms 
    306379            npth = lib 
    307380            dir, lib = os.path.split(lib) 
    308381            if excludes.get(dir,0): 
    309382                continue 
    310383        else: 
    311             # all other platforms 
     384            # plain win case 
    312385            npth = getfullnameof(lib, xtrapath) 
    313386 
    314         # now npth is a candidate lib 
     387        # now npth is a candidate lib if found 
    315388        # 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: 
     389        candidatelib = npth if npth else lib 
     390        if excludesRe.search(candidatelib): 
     391            if 'libpython' not in candidatelib and 'Python.framework' not in candidatelib: 
    318392                # skip libs not containing (libpython or Python.framework) 
    319393                #print "I: skipping %20s <- %s" % (npth, pth) 
    320394                continue 
     
    324398 
    325399        if npth: 
    326400            rv.append((lib, npth)) 
    327         else: 
     401        elif not seen.get(lib.upper(),0): 
    328402            print "E: lib not found:", lib, "dependency of", pth 
    329403 
    330404    return rv 
     
    375449    """Forwards to the correct getImports implementation for the platform. 
    376450    """ 
    377451    if platform[:3] == 'win' or platform == 'cygwin': 
    378         return _getImports_pe(pth) 
     452        try: 
     453            return _getImports_pe(pth) 
     454        except: 
     455            # not a binary file - assemblies can pull in files which don't  
     456            # necessarily have a PE header, but are still needed by the  
     457            # assembly. Any additional binary dependencies will already have  
     458            # been handled by selectAssemblies, so just return an empty list. 
     459            return [] 
    379460    elif platform == 'darwin': 
    380461        return _getImports_otool(pth) 
    381462    else: 
     
    461542    import glob 
    462543    for a in args: 
    463544        for fn in glob.glob(a): 
    464             print fn, getImports(fn, opts.target_platform) 
     545            print fn, getImports(fn, opts.target_platform) 
     546 No newline at end of file 
  • Build.py

     
    627627        self.name = kws.get('name',None) 
    628628        self.icon = kws.get('icon',None) 
    629629        self.versrsrc = kws.get('version',None) 
     630        self.manifest = kws.get('manifest',None) 
     631        self.resources = kws.get('resources',[]) 
    630632        self.strip = kws.get('strip',None) 
    631633        self.upx = kws.get('upx',None) 
    632634        self.crypt = kws.get('crypt', 0) 
     
    660662            ('debug',    _check_guts_eq), 
    661663            ('icon',     _check_guts_eq), 
    662664            ('versrsrc', _check_guts_eq), 
     665            ('manifest', _check_guts_eq), 
     666            ('resources', _check_guts_eq), 
    663667            ('strip',    _check_guts_eq), 
    664668            ('upx',      _check_guts_eq), 
    665669            ('crypt',    _check_guts_eq), 
     
    679683        if not data: 
    680684            return True 
    681685 
    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']: 
    684688            # todo: really ignore :-) 
    685             print "ignoring icon and version resources = platform not capable" 
     689            print "ignoring icon, version, manifest and resources = platform not capable" 
    686690 
    687691        mtm = data[-1] 
    688692        crypt = data[-2] 
     
    722726        exe = os.path.join(HOMEPATH, exe) 
    723727        if target_iswin or cygwin: 
    724728            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) 
    726734            if self.icon: 
    727                 tmpnm = tempfile.mktemp() 
    728                 shutil.copy2(exe, tmpnm) 
    729                 os.chmod(tmpnm, 0755) 
    730735                icon.CopyIcons(tmpnm, self.icon) 
    731                 trash.append(tmpnm) 
    732                 exe = tmpnm 
    733736            if self.versrsrc: 
    734                 tmpnm = tempfile.mktemp() 
    735                 shutil.copy2(exe, tmpnm) 
    736                 os.chmod(tmpnm, 0755) 
    737737                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 
    740778        exe = checkCache(exe, self.strip, self.upx and config['hasUPX']) 
    741779        self.copy(exe, outf) 
    742780        if self.append_pkg: 
     
    749787        os.chmod(self.name, 0755) 
    750788        _save_data(self.out, 
    751789                   (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))) 
    753791        for item in trash: 
    754792            os.remove(item) 
    755793        return 1 
     
    773811        os.chmod(self.name, 0755) 
    774812        _save_data(self.out, 
    775813                   (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))) 
    777815        return 1 
    778816 
    779817 
     
    10221060 
    10231061def main(specfile, configfilename): 
    10241062    global target_platform, target_iswin, config 
    1025     global icon, versionInfo 
     1063    global icon, versionInfo, resource, manifest 
    10261064 
    10271065    try: 
    10281066        config = _load_data(configfilename) 
     
    10461084        sys.exit(1) 
    10471085 
    10481086    if config['hasRsrcUpdate']: 
    1049         import icon, versionInfo 
     1087        import icon, versionInfo, resource, manifest 
    10501088 
    10511089    if config['hasUPX']: 
    10521090        setupUPXFlags() 
     
    10621100    parser.add_option('-C', '--configfile', 
    10631101                      default=os.path.join(HOMEPATH, 'config.dat'), 
    10641102                      help='Name of generated configfile (default: %default)') 
     1103    parser.add_option('-o', '--buildpath', 
     1104                      default=None, 
     1105                      help='Buildpath') 
    10651106    opts, args = parser.parse_args() 
    10661107    if len(args) != 1: 
    10671108        parser.error('Requires exactly one .spec-file') 
    10681109 
    1069     main(args[0], configfilename=opts.configfile) 
     1110    main(args[0], configfilename=opts.configfile) 
     1111 No newline at end of file 
  • Makespec.py

     
    135135 
    136136def main(scripts, configfile=None, name=None, tk=0, freeze=0, console=1, debug=0, 
    137137         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): 
    139139 
    140140    try: 
    141141        config = eval(open(configfile, 'r').read()) 
     
    168168        exe_options = "%s, version='%s'" % (exe_options, quote_win_filepath(version_file)) 
    169169    if icon_file: 
    170170        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)) 
    171177    if not ascii and config['hasUnicode']: 
    172178        scripts.insert(0, os.path.join(HOME, 'support', 'useUnicode.py')) 
    173179    for i in range(len(scripts)): 
     
    278284                 dest="version_file", metavar="FILE", 
    279285                 help="add a version resource from FILE to the exe " 
    280286                      "(Windows only)") 
    281     g.add_option("--icon", type="string", dest="icon_file", 
     287    g.add_option("-i", "--icon", type="string", dest="icon_file", 
    282288                 metavar="FILE.ICO or FILE.EXE,ID", 
    283289                 help="If FILE is an .ico file, add the icon to the final " 
    284290                      "executable. Otherwise, the syntax 'file.exe,id' to " 
    285291                      "extract the icon with the specified id " 
    286292                      "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.") 
    287310 
    288311    opts,args = p.parse_args() 
    289312 
  • manifest.py

     
     1#!/usr/bin/env python 
     2 
     3""" 
     4manifest.py 2009-03 Florian Hoech 
     5 
     6Provides 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 
     12Implemented: 
     13* Shared and private assemblies support 
     14* Publisher configuration support (.policy files) 
     15* application configuration support (.config files) 
     16 
     17Not 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 
     24Reference: 
     25About Isolated Applications and Side-by-side Assemblies 
     26http://msdn.microsoft.com/en-us/library/aa374029(VS.85).aspx 
     27""" 
     28try: 
     29    import hashlib 
     30except ImportError, detail: 
     31    hashlib = None 
     32    print 'I: ... file hash calculation unavailable -', detail 
     33import os.path 
     34from glob import glob 
     35from xml.dom import Node, minidom 
     36from xml.dom.minidom import Document, Element 
     37 
     38Document.aChild = Document.appendChild 
     39Document.cE = Document.createElement 
     40Document.cT = Document.createTextNode 
     41Document.getEById = Document.getElementById 
     42Document.getEByTN = Document.getElementsByTagName 
     43Element.aChild = Element.appendChild 
     44Element.getA = Element.getAttribute 
     45Element.getEByTN = Element.getElementsByTagName 
     46Element.remA = Element.removeAttribute 
     47Element.setA = Element.setAttribute 
     48 
     49try: 
     50    import resource 
     51except ImportError, detail: 
     52    resource = None 
     53    print 'I: ... manifest resource access unavailable -', detail 
     54 
     55RT_MANIFEST = 24 
     56 
     57def getChildElementsByTagName(self, tagName): 
     58    """ Return child elements of type tagName if found, else [] """ 
     59    result = [] 
     60    for child in self.childNodes: 
     61        if isinstance(child, Element): 
     62            if child.tagName == tagName: 
     63                result.append(child) 
     64    return result 
     65 
     66def getFirstChildElementByTagName(self, tagName): 
     67    """ Return the first element of type tagName if found, else None """ 
     68    for child in self.childNodes: 
     69        if isinstance(child, Element): 
     70            if child.tagName == tagName: 
     71                return child 
     72    return None 
     73 
     74Document.getCEByTN = getChildElementsByTagName 
     75Document.getFCEByTN = getFirstChildElementByTagName 
     76Element.getCEByTN = getChildElementsByTagName 
     77Element.getFCEByTN = getFirstChildElementByTagName 
     78 
     79class _Dummy: 
     80    pass 
     81 
     82class File(resource.File if resource else _Dummy): 
     83    """ A file referenced by an assembly inside a manifest. """ 
     84    def __init__(self, filename="", hashalg=None, hash=None, comClasses=None,  
     85                 typelibs=None, comInterfaceProxyStubs=None,  
     86                 windowClasses=None): 
     87        if resource: 
     88            resource.File.__init__(self, filename) 
     89        else: 
     90            self.filename = filename 
     91        self.name = os.path.basename(filename) 
     92        self.hashalg = hashalg.upper() if hashalg else None 
     93        if os.path.isfile(filename) and hashalg and hashlib: 
     94            self.calc_hash() 
     95        else: 
     96            self.hash = hash 
     97        self.comClasses = comClasses or [] # TO-DO: implement 
     98        self.typelibs = typelibs or [] # TO-DO: implement 
     99        self.comInterfaceProxyStubs = comInterfaceProxyStubs or [] # TO-DO: implement 
     100        self.windowClasses = windowClasses or [] # TO-DO: implement 
     101    def calc_hash(self, hashalg=None): 
     102        """ Calculate the hash of the file. Will be called automatically from  
     103        the constructor if the file exists and hashalg is given, but may  
     104        also be called manually e.g. to update the hash if the file has  
     105        changed. """ 
     106        fd = open(self.filename, "rb") 
     107        buf = fd.read() 
     108        fd.close() 
     109        if hashalg: 
     110            self.hashalg = hashalg.upper() 
     111        self.hash = getattr(hashlib, self.hashalg.lower())(buf).hexdigest() 
     112 
     113class InvalidManifestError(Exception): 
     114    pass 
     115 
     116class Manifest(): 
     117    def __init__(self, manifestVersion=None, noInheritable=False,  
     118                 noInherit=False, type_=None, name=None, language=None,  
     119                 processorArchitecture=None, version=None,  
     120                 publicKeyToken=None, description=None,  
     121                 requestedExecutionLevel=None, uiAccess=None,  
     122                 dependentAssemblies=None, files=None,  
     123                 comInterfaceExternalProxyStubs=None): 
     124        """ Manifest constructor. 
     125         
     126        To build a basic manifest for your application: 
     127          mf = Manifest(type='win32', name='YourAppName', language='*',  
     128                        processorArchitecture='x86', version=[1, 0, 0, 0]) 
     129         
     130        To write the XML to a manifest file: 
     131          mf.writexml("YourAppName.exe.manifest") 
     132        or 
     133          mf.writeprettyxml("YourAppName.exe.manifest") 
     134        """ 
     135        self.filename = None 
     136        self.optional = None 
     137        self.manifestType = "assembly" 
     138        self.manifestVersion = manifestVersion or [1, 0] 
     139        self.noInheritable = noInheritable 
     140        self.noInherit = noInherit 
     141        self.type = type_ 
     142        self.name = name 
     143        self.language = language 
     144        self.processorArchitecture = processorArchitecture 
     145        self.version = version 
     146        self.publicKeyToken = publicKeyToken 
     147        # public key token 
     148        # "A 16-character hexadecimal string that represents the last 8 bytes  
     149        # of the SHA-1 hash of the public key under which the assembly is  
     150        # signed. The public key used to sign the catalog must be 2048 bits  
     151        # or greater. Required for all shared side-by-side assemblies." 
     152        # http://msdn.microsoft.com/en-us/library/aa375692(VS.85).aspx 
     153        self.applyPublisherPolicy = None 
     154        self.description = None 
     155        self.requestedExecutionLevel = requestedExecutionLevel 
     156        self.uiAccess = uiAccess 
     157        self.dependentAssemblies = dependentAssemblies or [] 
     158        self.bindingRedirects = [] 
     159        self.files = files or [] 
     160        self.comInterfaceExternalProxyStubs = comInterfaceExternalProxyStubs or [] # TO-DO: implement 
     161     
     162    def add_dependent_assembly(self, manifestVersion=None, noInheritable=False,  
     163                 noInherit=False, type_=None, name=None, language=None,  
     164                 processorArchitecture=None, version=None,  
     165                 publicKeyToken=None, description=None,  
     166                 requestedExecutionLevel=None, uiAccess=None,  
     167                 dependentAssemblies=None, files=None,  
     168                 comInterfaceExternalProxyStubs=None): 
     169        """ Shortcut for: 
     170        manifest.dependentAssemblies.append(Manifest(*args, *kwargs)) """ 
     171        self.dependentAssemblies.append(Manifest(manifestVersion,  
     172                                        noInheritable, noInherit, type_, name,  
     173                                        language, processorArchitecture,  
     174                                        version, publicKeyToken, description,  
     175                                        requestedExecutionLevel, uiAccess,  
     176                                        dependentAssemblies, files,  
     177                                        comInterfaceExternalProxyStubs)) 
     178     
     179    def add_file(self, name="", hashalg="", hash="", comClasses=None,  
     180                 typelibs=None, comInterfaceProxyStubs=None,  
     181                 windowClasses=None): 
     182        """ Shortcut for: 
     183        manifest.files.append(File(*args, *kwargs)) """ 
     184        self.files.append(File(name, hashalg, hash, comClasses,  
     185                          typelibs, comInterfaceProxyStubs, windowClasses)) 
     186     
     187    def find_files(self): 
     188        """ Search shared and private assemblies and return a list of all  
     189        related files if found. If any files are not found, return an empty  
     190        list.""" 
     191        if None in (self.processorArchitecture, self.name, self.publicKeyToken,  
     192                    self.version): 
     193                        return [] 
     194        files = [] 
     195        # search winsxs 
     196        winsxs = os.path.join(os.getenv('SystemRoot'), 'WinSxS') 
     197        if os.path.isdir(winsxs): 
     198            manifests = os.path.join(winsxs, "Manifests") 
     199            if os.path.isdir(manifests): 
     200                for manifestpth in glob(os.path.join(manifests,  
     201                                                    '%s_%s_%s_%s_*.manifest' %  
     202                                                    (self.processorArchitecture,  
     203                                                     self.name,  
     204                                                     self.publicKeyToken,  
     205                                                     ".".join([str(i) for i in self.version])))): 
     206                    assemblynm = os.path.basename(os.path.splitext(manifestpth)[0]) 
     207                    if not os.path.isfile(manifestpth): 
     208                        print "W: No such file", manifestpth, "part of assembly", assemblynm 
     209                        continue 
     210                    print "I: Found manifest", manifestpth 
     211                    assemblydir = os.path.join(winsxs, assemblynm) 
     212                    if not os.path.isdir(assemblydir): 
     213                        print "W: No such dir", assemblydir 
     214                        continue 
     215                    try: 
     216                        manifest = ManifestFromXMLFile(manifestpth) 
     217                    except Exception, exc: 
     218                        print "E:", manifestpth, str(exc) 
     219                        pass 
     220                    else: 
     221                        rfiles = [] 
     222                        for file_ in self.files or manifest.files: 
     223                            fn = os.path.join(assemblydir, file_.name) 
     224                            if os.path.isfile(fn): 
     225                                rfiles.append(fn) 
     226                            else: 
     227                                print "W: No such file", fn, "part of assembly", assemblynm 
     228                                # if any of our files does not exist, 
     229                                # the assembly is incomplete 
     230                                rfiles = [] 
     231                                break 
     232                        if rfiles: 
     233                            files.append(manifestpth) 
     234                            files.extend(rfiles) 
     235                            return files 
     236                    break 
     237            else: 
     238                print "W: No such dir", manifests 
     239        else: 
     240            print "W: No such dir", winsxs 
     241        # search for private assemblies 
     242        if not self.filename: 
     243            return [] 
     244        dirnm = os.path.dirname(self.filename) 
     245        # if embedded in a dll the assembly may have the same name as the  
     246        # dll, so we need to make sure we don't search for *.dll.dll 
     247        assemblynm, ext = os.path.splitext(self.name) 
     248        if ext.lower() == ".dll": 
     249            # discard the extension 
     250            pass 
     251        else: 
     252            assemblynm = self.name 
     253        for path in [os.path.join(dirnm, self.language or "*"), 
     254                     os.path.join(dirnm, self.language or "*", assemblynm),  
     255                     dirnm,  
     256                     os.path.join(dirnm, assemblynm)]: 
     257            for ext in (".dll", ".manifest"): 
     258                # private assemblies can have the manifest either as  
     259                # separate file or embedded in a DLL 
     260                manifestpth = os.path.join(path, assemblynm + ext) 
     261                if not os.path.isfile(manifestpth): 
     262                    print "W: No such file", manifestpth, "part of assembly", assemblynm 
     263                    continue 
     264                print "I: Found manifest", manifestpth 
     265                try: 
     266                    if ext == ".dll": 
     267                        manifest = ManifestFromResFile(manifestpth, [1]) 
     268                    else: 
     269                        manifest = ManifestFromXMLFile(manifestpth) 
     270                except Exception, exc: 
     271                    print "E:", manifestpth, str(exc) 
     272                    pass 
     273                else: 
     274                    rfiles = [] 
     275                    for file_ in self.files or manifest.files: 
     276                        fn = os.path.join(path, file_.name) 
     277                        if os.path.isfile(fn): 
     278                            rfiles.append(fn) 
     279                        else: 
     280                            print "W: No such file", fn, "part of assembly", assemblynm 
     281                            # if any of our files does not exist, 
     282                            # the assembly is incomplete 
     283                            return [] 
     284                    files.append(manifestpth) 
     285                    files.extend(rfiles) 
     286                break 
     287            if not os.path.isfile(manifestpth): 
     288                for file_ in self.files: 
     289                    fn = os.path.join(path, file_.name) 
     290                    if os.path.exists(fn): 
     291                        # if any of our files does exist without the manifest  
     292                        # in the same dir, the assembly is incomplete 
     293                        return [] 
     294        return files 
     295     
     296    def load_dom(self, domtree, initialize=True): 
     297        """ Load manifest from DOM tree. 
     298        If initialize is True (default), reset existing attributes first.""" 
     299        if domtree.nodeType == Node.DOCUMENT_NODE: 
     300            rootElement = domtree.documentElement 
     301        elif domtree.nodeType == Node.ELEMENT_NODE: 
     302            rootElement = domtree 
     303        else: 
     304            raise InvalidManifestError("Invalid root element node type " +  
     305                                       str(rootElement.nodeType) +  
     306                                       " - has to be one of (DOCUMENT_NODE, ELEMENT_NODE)") 
     307        allowed_names = ("assembly", "assemblyBinding", "configuration",  
     308                         "dependentAssembly") 
     309        if rootElement.tagName not in allowed_names: 
     310            raise InvalidManifestError("Invalid root element <" +  
     311                                       rootElement.tagName +  
     312                                       "> - has to be one of " +  
     313                                       repr(allowed_names)) 
     314        # print "I: loading manifest metadata from element <%s>" % \ 
     315              # rootElement.tagName 
     316        if rootElement.tagName == "configuration": 
     317            for windows in rootElement.getCEByTN("windows"): 
     318                for assemblyBinding in windows.getCEByTN("assemblyBinding"): 
     319                    self.load_dom(assemblyBinding) 
     320        else: 
     321            if initialize: 
     322                self.__init__() 
     323            self.manifestType = rootElement.tagName 
     324            self.manifestVersion = [int(i) for i in (rootElement.getA("manifestVersion") or "1.0").split(".")] 
     325            self.noInheritable = bool(rootElement.getFCEByTN("noInheritable")) 
     326            self.noInherit = bool(rootElement.getFCEByTN("noInherit")) 
     327            for assemblyIdentity in rootElement.getCEByTN("assemblyIdentity"): 
     328                self.type = assemblyIdentity.getA("type") 
     329                self.name = assemblyIdentity.getA("name") 
     330                self.language = assemblyIdentity.getA("language") 
     331                self.processorArchitecture = assemblyIdentity.getA("processorArchitecture") 
     332                self.version = [int(i) for i in (assemblyIdentity.getA("version") or "0.0.0.0").split(".")] 
     333                self.publicKeyToken = assemblyIdentity.getA("publicKeyToken") 
     334            for publisherPolicy in rootElement.getCEByTN("publisherPolicy"): 
     335                self.applyPublisherPolicy = (publisherPolicy.getA("apply") or "").lower() == "yes" 
     336            for description in rootElement.getCEByTN("description"): 
     337                                if description.firstChild: 
     338                                        self.description = description.firstChild.wholeText 
     339            for trustInfo in rootElement.getCEByTN("trustInfo"): 
     340                for security in trustInfo.getCEByTN("security"): 
     341                    for requestedPrivileges in security.getCEByTN("requestedPrivileges"): 
     342                        for requestedExecutionLevel in requestedPrivileges.getCEByTN("requestedExecutionLevel"): 
     343                            self.requestedExecutionLevel = requestedExecutionLevel.getA("level") 
     344                            self.uiAccess = (requestedExecutionLevel.getA("uiAccess") or "").lower() == "true" 
     345            for dependency in (rootElement.getCEByTN("dependency") if  
     346                               rootElement.tagName != "assemblyBinding" else  
     347                               [rootElement]): 
     348                for dependentAssembly in dependency.getCEByTN("dependentAssembly"): 
     349                    manifest = ManifestFromDOM(dependentAssembly) 
     350                    manifest.optional = (dependency.getA("optional") or "").lower() == "yes" 
     351                    self.dependentAssemblies.append(manifest) 
     352            for bindingRedirect in rootElement.getCEByTN("bindingRedirect"): 
     353                oldVersion = [[int(i) for i in part.split(".")] for part in bindingRedirect.getA("oldVersion").split("-")] 
     354                newVersion = [int(i) for i in bindingRedirect.getA("newVersion").split(".")] 
     355                self.bindingRedirects.append((oldVersion, newVersion)) 
     356            for file_ in rootElement.getCEByTN("file"): 
     357                self.add_file(name=file_.getA("name"), 
     358                              hashalg=file_.getA("hashalg"), 
     359                              hash=file_.getA("hash")) 
     360     
     361    def parse(self, filename_or_file): 
     362        """ Load manifest from file or file object """ 
     363        self.load_dom(minidom.parse(filename_or_file)) 
     364        if isinstance(filename_or_file, (str, unicode)): 
     365            self.filename = filename_or_file 
     366        else: 
     367            self.filename = filename_or_file.filename 
     368     
     369    def parse_string(self, xmlstr): 
     370        """ Load manifest from XML string """ 
     371        self.load_dom(minidom.parseString(xmlstr)) 
     372     
     373    def todom(self): 
     374        """ Return the manifest as DOM tree """ 
     375        doc = Document() 
     376        docE = doc.cE(self.manifestType) 
     377        if self.manifestType == "assemblyBinding": 
     378            cfg = doc.cE("configuration") 
     379            win = doc.cE("windows") 
     380            win.aChild(docE) 
     381            cfg.aChild(win) 
     382            doc.aChild(cfg) 
     383        else: 
     384            doc.aChild(docE) 
     385        if self.manifestType != "dependentAssembly": 
     386            docE.setA("xmlns", "urn:schemas-microsoft-com:asm.v1") 
     387            if self.manifestType != "assemblyBinding": 
     388                docE.setA("manifestVersion",  
     389                          ".".join([str(i) for i in self.manifestVersion])) 
     390        if self.noInheritable: 
     391            docE.aChild(doc.cE("noInheritable")) 
     392        if self.noInherit: 
     393            docE.aChild(doc.cE("noInherit")) 
     394        aId = doc.cE("assemblyIdentity") 
     395        if self.type: 
     396            aId.setAttribute("type", self.type) 
     397        if self.name: 
     398            aId.setAttribute("name", self.name) 
     399        if self.language: 
     400            aId.setAttribute("language", self.language) 
     401        if self.processorArchitecture: 
     402            aId.setAttribute("processorArchitecture",  
     403                             self.processorArchitecture) 
     404        if self.version: 
     405            aId.setAttribute("version",  
     406                             ".".join([str(i) for i in self.version])) 
     407        if self.publicKeyToken: 
     408            aId.setAttribute("publicKeyToken", self.publicKeyToken) 
     409        if aId.hasAttributes(): 
     410            docE.aChild(aId) 
     411        else: 
     412            aId.unlink() 
     413        if self.applyPublisherPolicy != None: 
     414            ppE = doc.cE("publisherPolicy") 
     415            ppE.setA("apply", "yes" if self.applyPublisherPolicy else "no") 
     416            docE.aChild(ppE) 
     417        if self.description: 
     418            descE = doc.cE("description") 
     419            descE.aChild(doc.cT(self.description)) 
     420            docE.aChild(descE) 
     421        if self.requestedExecutionLevel in ("asInvoker", "highestAvailable",  
     422                                            "requireAdministrator"): 
     423            tE = doc.cE("trustInfo") 
     424            tE.setA("xmlns", "urn:schemas-microsoft-com:asm.v3") 
     425            sE = doc.cE("security") 
     426            rpE = doc.cE("requestedPrivileges") 
     427            relE = doc.cE("requestedExecutionLevel") 
     428            relE.setA("level", self.requestedExecutionLevel) 
     429            relE.setA("uiAccess", "true" if self.uiAccess else "false") 
     430            rpE.aChild(relE) 
     431            sE.aChild(rpE) 
     432            tE.aChild(sE) 
     433            docE.aChild(tE) 
     434        if self.dependentAssemblies: 
     435            for assembly in self.dependentAssemblies: 
     436                if self.manifestType != "assemblyBinding": 
     437                    dE = doc.cE("dependency") 
     438                    if assembly.optional: 
     439                        dE.setAttribute("optional", "yes") 
     440                daE = doc.cE("dependentAssembly") 
     441                adom = assembly.todom() 
     442                for child in adom.documentElement.childNodes: 
     443                    daE.aChild(child.cloneNode(False)) 
     444                adom.unlink() 
     445                if self.manifestType != "assemblyBinding": 
     446                    dE.aChild(daE) 
     447                    docE.aChild(dE) 
     448                else: 
     449                    docE.aChild(daE) 
     450        if self.bindingRedirects: 
     451            for bindingRedirect in self.bindingRedirects: 
     452                brE = doc.cE("bindingRedirect") 
     453                brE.setAttribute("oldVersion",  
     454                                 "-".join(".".join(str(i) for i in part) for part in bindingRedirect[0])) 
     455                brE.setAttribute("newVersion",  
     456                                 ".".join(str(i) for i in bindingRedirect[1])) 
     457                docE.aChild(brE) 
     458        if self.files: 
     459            for file_ in self.files: 
     460                fE = doc.cE("file") 
     461                for attr in ("name", "hashalg", "hash"): 
     462                    val = getattr(file_, attr) 
     463                    if val: 
     464                        fE.setA(attr, val) 
     465                docE.aChild(fE) 
     466        return doc 
     467     
     468    def toprettyxml(self, indent="  ", newl=os.linesep, encoding="UTF-8"): 
     469        """ Return the manifest as pretty-printed XML """ 
     470        domtree = self.todom() 
     471                # WARNING: The XML declaration has to follow the order version-encoding-standalone (standalone being optional), 
     472                # otherwise if it is embedded in an exe the exe will fail to launch! ('application configuration incorrect') 
     473        xmlstr = domtree.toprettyxml(indent, newl, encoding).strip(os.linesep).replace('<?xml version="1.0" encoding="UTF-8"?>',  
     474                        '<?xml version="1.0" encoding="%s" standalone="yes"?>' % encoding) 
     475        domtree.unlink() 
     476        return xmlstr 
     477     
     478    def toxml(self, encoding="UTF-8"): 
     479        """ Return the manifest as XML """ 
     480        domtree = self.todom() 
     481                # WARNING: The XML declaration has to follow the order version-encoding-standalone (standalone being optional), 
     482                # otherwise if it is embedded in an exe the exe will fail to launch! ('application configuration incorrect') 
     483        xmlstr = domtree.toxml(encoding).replace('<?xml version="1.0" encoding="UTF-8"?>',  
     484                        '<?xml version="1.0" encoding="%s" standalone="yes"?>' % encoding) 
     485        domtree.unlink() 
     486        return xmlstr 
     487 
     488    def update_resources(self, dstpath, names=None, languages=None): 
     489        """ Update or add manifest to dll/exe file dstpath, as manifest  
     490        resource """ 
     491        UpdateManifestResourcesFromXML(dstpath, self.toprettyxml(), names,  
     492                                       languages) 
     493     
     494    def writeprettyxml(self, filename_or_file, indent="  ", newl=os.linesep, encoding="UTF-8"): 
     495        """ Write the manifest as XML to a file or file object """ 
     496        if isinstance(filename_or_file, (str, unicode)): 
     497            filename_or_file = open(filename_or_file, "wb") 
     498        xmlstr = self.toprettyxml(indent, newl, encoding) 
     499        filename_or_file.write(xmlstr) 
     500        filename_or_file.close() 
     501     
     502    def writexml(self, filename_or_file, indent="  ", newl=os.linesep, encoding="UTF-8"): 
     503        """ Write the manifest as XML to a file or file object """ 
     504        if isinstance(filename_or_file, (str, unicode)): 
     505            filename_or_file = open(filename_or_file, "wb") 
     506        xmlstr = self.toxml(indent, newl, encoding) 
     507        filename_or_file.write(xmlstr) 
     508        filename_or_file.close() 
     509         
     510def ManifestFromResFile(filename, names=None, languages=None): 
     511    """ Create and return manifest instance from manifest resource in  
     512    dll/exe file """ 
     513    res = GetManifestResources(filename, names, languages) 
     514    if res and res[RT_MANIFEST]: 
     515        while isinstance(res, dict) and res.keys(): 
     516            res = res[res.keys()[0]] 
     517    if isinstance(res, dict): 
     518        raise InvalidManifestError("No manifest resource found in '%s'" %  
     519                                   filename) 
     520    manifest = ManifestFromXML(res) 
     521    manifest.filename = filename 
     522    return manifest 
     523         
     524def ManifestFromDOM(domtree): 
     525    """ Create and return manifest instance from DOM tree """ 
     526    manifest = Manifest() 
     527    manifest.load_dom(domtree) 
     528    return manifest 
     529         
     530def ManifestFromXML(xmlstr): 
     531    """ Create and return manifest instance from XML """ 
     532    manifest = Manifest() 
     533    manifest.parse_string(xmlstr) 
     534    return manifest 
     535         
     536def ManifestFromXMLFile(filename_or_file): 
     537    """ Create and return manifest instance from manifest file """ 
     538    manifest = Manifest() 
     539    manifest.parse(filename_or_file) 
     540    return manifest 
     541 
     542def GetManifestResources(filename, names=None, languages=None): 
     543    """ Get manifest resources from dll/exe file """ 
     544    return resource.GetResources(filename, [RT_MANIFEST], names, languages) 
     545 
     546def UpdateManifestResourcesFromXML(dstpath, xmlstr, names=None,  
     547                                   languages=None): 
     548    """ Update or add manifest XML to dll/exe file dstpath, as manifest  
     549    resource """ 
     550    print "I: Updating manifest in", dstpath 
     551    name = 1 if dstpath.lower().endswith(".exe") else 2 
     552    resource.UpdateResources(dstpath, xmlstr, RT_MANIFEST, names or [name],  
     553                             languages or [0, "*"]) 
     554 
     555def UpdateManifestResourcesFromXMLFile(dstpath, srcpath, names=None,  
     556                                       languages=None): 
     557    """ Update or add manifest XML from file srcpath to dll/exe file  
     558    dstpath, as manifest resource """ 
     559    print "I: Updating manifest from", srcpath, "to", dstpath 
     560    name = 1 if dstpath.lower().endswith(".exe") else 2 
     561    resource.UpdateResourcesFromDataFile(dstpath, srcpath, RT_MANIFEST,  
     562                                         names or [name],  
     563                                         languages or [0, "*"]) 
     564 
     565if __name__ == "__main__": 
     566    import sys 
     567     
     568    dstpath = sys.argv[1] 
     569    srcpath = sys.argv[2] 
     570    UpdateManifestResourcesFromXMLFile(dstpath, srcpath) 
     571 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 
     3import os.path 
     4import pywintypes 
     5import win32api 
     6 
     7LOAD_LIBRARY_AS_DATAFILE = 2 
     8ERROR_BAD_EXE_FORMAT = 193 
     9ERROR_RESOURCE_DATA_NOT_FOUND = 1812 
     10ERROR_RESOURCE_TYPE_NOT_FOUND = 1813 
     11ERROR_RESOURCE_NAME_NOT_FOUND = 1814 
     12ERROR_RESOURCE_LANG_NOT_FOUND = 1815 
     13 
     14class 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 
     61def _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 
     111def 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 
     123def 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 
     150def 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 
     162def 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 
     179def 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