Пример #1
0
def CopyIcons_FromIco(dstpath, srcpath, id=1):
    '''
    Use the Win API UpdateResource facility to apply the icon
    resource(s) to the .exe file.

    :param str dstpath: absolute path of the .exe file being built.
    :param str srcpath: list of 1 or more .ico file paths
    '''
    icons = map(IconFile, srcpath)
    logger.info("Copying icons from %s", srcpath)

    hdst = win32api.BeginUpdateResource(dstpath, 0)

    iconid = 1
    # Each step in the following enumerate() will instantiate an IconFile
    # object, as a result of deferred execution of the map() above.
    for i, f in enumerate(icons):
        data = f.grp_icon_dir()
        data = data + f.grp_icondir_entries(iconid)
        win32api.UpdateResource(hdst, RT_GROUP_ICON, i, data)
        logger.info("Writing RT_GROUP_ICON %d resource with %d bytes", i,
                    len(data))
        for data in f.images:
            win32api.UpdateResource(hdst, RT_ICON, iconid, data)
            logger.info("Writing RT_ICON %d resource with %d bytes", iconid,
                        len(data))
            iconid = iconid + 1

    win32api.EndUpdateResource(hdst, 0)
Пример #2
0
def UpdateResources(dstpath, data, type_, names=None, languages=None):
    """
    Update or add resource data in dll/exe file dstpath.

    type_ = resource type to update
    names = a list of resource names to update (None = all)
    languages = a list of resource languages to update (None = all)
    """
    # Look for existing resources.
    res = GetResources(dstpath, [type_], names, languages)
    # add type_, names and languages not already present in existing resources
    if not type_ in res and type_ != "*":
        res[type_] = {}
    if names:
        for name in names:
            if not name in res[type_] and name != "*":
                res[type_][name] = []
                if languages:
                    for language in languages:
                        if not language in res[type_][name] and language != "*":
                            res[type_][name].append(language)
    # add resource to destination, overwriting existing resources
    hdst = win32api.BeginUpdateResource(dstpath, 0)
    for type_ in res:
        for name in res[type_]:
            for language in res[type_][name]:
                logger.info("Updating resource type %s name %s language %s",
                            type_, name, language)
                win32api.UpdateResource(hdst, type_, name, data, language)
    win32api.EndUpdateResource(hdst, 0)
Пример #3
0
def SetVersion(exenm, versionfile):
    if isinstance(versionfile, VSVersionInfo):
        vs = versionfile
    else:
        with codecs.open(versionfile, 'r', 'utf-8') as fp:
            txt = fp.read()
        vs = eval(txt)

    # Remember overlay
    pe = pefile.PE(exenm, fast_load=True)
    overlay_before = pe.get_overlay()
    pe.close()

    hdst = win32api.BeginUpdateResource(exenm, 0)
    win32api.UpdateResource(hdst, pefile.RESOURCE_TYPE['RT_VERSION'], 1,
                            vs.toRaw())
    win32api.EndUpdateResource(hdst, 0)

    if overlay_before:
        # Check if the overlay is still present
        pe = pefile.PE(exenm, fast_load=True)
        overlay_after = pe.get_overlay()
        pe.close()

        # If the update removed the overlay data, re-append it
        if not overlay_after:
            with open(exenm, 'ab') as exef:
                exef.write(overlay_before)
Пример #4
0
def RemoveAllResources(filename):
    """
    Remove all resources from the dll/exe file.
    """
    hsrc = win32api.BeginUpdateResource(filename,
                                        True)  # bDeleteExistingResources=True
    win32api.EndUpdateResource(hsrc, False)
Пример #5
0
def CopyIcons(dstpath, srcpath):
    '''
    Called from building/api.py to handle icons. If the input was by
    --icon on the command line, srcpath is a single string. However it
    is possible to modify the spec file adding icon=['foo.ico','bar.ico']
    to the EXE() statement. In that case, srcpath is a list of strings.

    The string format is either path-to-.ico or path-to-.exe,n for n an
    integer resource index in the .exe. In either case the path can be
    relative or absolute.
    '''

    if isinstance(srcpath, str):
        # just a single string, make it a one-element list
        srcpath = [srcpath]

    def splitter(s):
        '''
        Convert "pathname" to tuple ("pathname", None)
        Convert "pathname,n" to tuple ("pathname", n)
        '''
        try:
            srcpath, index = s.split(',')
            return srcpath.strip(), int(index)
        except ValueError:
            return s, None

    # split all the items in the list into tuples as above.
    srcpath = list(map(splitter, srcpath))

    if len(srcpath) > 1:
        # More than one icon source given. We currently handle multiple
        # icons by calling CopyIcons_FromIco(), which only allows .ico.
        # In principle we could accept a mix of .ico and .exe, but it
        # would complicate things. If you need it submit a pull request.
        #
        # Note that a ",index" on a .ico is just ignored in the single
        # or multiple case.
        srcs = []
        for s in srcpath:
            e = os.path.splitext(s[0])[1]
            if e.lower() != '.ico':
                raise ValueError(
                    'Multiple icons supported only from .ico files')
            srcs.append(s[0])
        return CopyIcons_FromIco(dstpath, srcs)

    # Just one source given.
    srcpath, index = srcpath[0]
    srcext = os.path.splitext(srcpath)[1]
    # Handle the simple case of foo.ico, ignoring any ,index.
    if srcext.lower() == '.ico':
        return CopyIcons_FromIco(dstpath, [srcpath])

    # Single source is not .ico, presumably it is .exe (and if not, some
    # error will occur). If relative, make it relative to the .spec file.
    if not os.path.isabs(srcpath):
        srcpath = os.path.join(config.CONF['specpath'], srcpath)
    if index is not None:
        logger.info("Copying icon from %s, %d", srcpath, index)
    else:
        logger.info("Copying icons from %s", srcpath)

    # Bail out quickly if the input is invalid. Letting images in the wrong
    # format be passed to Window's API gives very cryptic error messages as
    # it's generally unclear why PyInstaller would treat an image file as an
    # executable.
    if srcext != ".exe":
        raise ValueError(
            f"Received icon path '{srcpath}' which exists but is not in the "
            f"correct format. On Windows, only '.ico' images or other "
            f"'.exe' files may be used as icons. Please convert your "
            f"'{srcext}' file to a '.ico' then try again.")

    try:
        # Attempt to load the .ico or .exe containing the icon into memory
        # using the same mechanism as if it were a DLL. If this fails for
        # any reason (for example if the file does not exist or is not a
        # .ico/.exe) then LoadLibraryEx returns a null handle and win32api
        # raises a unique exception with a win error code and a string.
        hsrc = win32api.LoadLibraryEx(srcpath, 0, LOAD_LIBRARY_AS_DATAFILE)
    except pywintypes.error as W32E:
        # We could continue with no icon (i.e. just return) however it seems
        # best to terminate the build with a message.
        raise SystemExit(
            "Unable to load icon file {}\n    {} (Error code {})".format(
                srcpath, W32E.strerror, W32E.winerror))
    hdst = win32api.BeginUpdateResource(dstpath, 0)
    if index is None:
        grpname = win32api.EnumResourceNames(hsrc, RT_GROUP_ICON)[0]
    elif index >= 0:
        grpname = win32api.EnumResourceNames(hsrc, RT_GROUP_ICON)[index]
    else:
        grpname = -index
    data = win32api.LoadResource(hsrc, RT_GROUP_ICON, grpname)
    win32api.UpdateResource(hdst, RT_GROUP_ICON, grpname, data)
    for iconname in win32api.EnumResourceNames(hsrc, RT_ICON):
        data = win32api.LoadResource(hsrc, RT_ICON, iconname)
        win32api.UpdateResource(hdst, RT_ICON, iconname, data)
    win32api.FreeLibrary(hsrc)
    win32api.EndUpdateResource(hdst, 0)