forked from AuroraMiddleware/gtk
a612a42c11
As the program executable name has 'update' in its filename, gtk-update-icon-cache.exe is considered to be an installer program on 32-bit Windows [1], which will cause the program to fail to run unless it is running with elevated privileges (i.e. UAC). Avoid this situation by embedding a manifest file into the final executable that tells Windows that this is not a program that requires elevation. Also make the autotools build files dist the new script and use the new script to generate the manifest and rc files, instead of hardcoding the generating bits in gtk/Makefile.am Fixes issue #3632. [1]: https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-vista/cc709628(v=ws.10)?redirectedfrom=MSDN, under section "Installer Detection Technology"
111 lines
4.2 KiB
Python
111 lines
4.2 KiB
Python
#!/usr/bin/env python3
|
|
|
|
"""
|
|
This script generates a Windows manifest file and optionally a resource file to
|
|
determine whether a specified program requires UAC elevation
|
|
"""
|
|
|
|
import os
|
|
import argparse
|
|
|
|
DOMAIN_NAME='gnome'
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(
|
|
description=__doc__)
|
|
parser.add_argument('-p', '--package', required=True,
|
|
help='package name of the executable')
|
|
parser.add_argument('-n', '--name', required=True,
|
|
help='name of executable')
|
|
parser.add_argument('--pkg-version', required=True, dest='version',
|
|
help='version of package')
|
|
parser.add_argument('--require-admin', action='store_true', dest='admin',
|
|
default=False,
|
|
help='require admin access to application')
|
|
parser.add_argument('--input-resource-file', dest='resource',
|
|
default=None,
|
|
help='existing .rc file to embed UAC manifest (do not generate a new .rc file), must have included winuser.h in it')
|
|
parser.add_argument('--output-dir', dest='outdir',
|
|
default=None,
|
|
help='directory to output resulting files')
|
|
args = parser.parse_args()
|
|
|
|
if args.resource is not None:
|
|
if not os.path.isfile(args.resource):
|
|
raise FileNotFoundError("Specified resource file '%s' does not exist" % args.resource)
|
|
|
|
generate_manifest(args.package, args.name, args.version, args.admin, args.outdir)
|
|
write_rc_file(args.name, args.resource, args.outdir)
|
|
|
|
def generate_manifest(package, name, version, admin, outdir):
|
|
if version.count('.') == 0:
|
|
manifest_package_version = version + '.0.0.0'
|
|
elif version.count('.') == 1:
|
|
manifest_package_version = version + '.0.0'
|
|
elif version.count('.') == 2:
|
|
manifest_package_version = version + '.0'
|
|
elif version.count('.') == 3:
|
|
manifest_package_version = version
|
|
else:
|
|
parts = version.split('.')
|
|
manifest_package_version = ''
|
|
for x in (0, 1, 2, 3):
|
|
if x == 0:
|
|
manifest_package_version += parts[x]
|
|
else:
|
|
manifest_package_version += '.' + parts[x]
|
|
|
|
if outdir is not None:
|
|
output_file_base_name = os.path.join(outdir, name)
|
|
else:
|
|
output_file_base_name = name
|
|
|
|
outfile = open(output_file_base_name + '.exe.manifest', 'w+')
|
|
outfile.write('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n')
|
|
outfile.write('<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">\n')
|
|
outfile.write(' <assemblyIdentity version="%s"\n' % manifest_package_version)
|
|
outfile.write(' processorArchitecture="*"\n')
|
|
outfile.write(' name="%s.%s.%s.exe"\n' % (DOMAIN_NAME, package, name))
|
|
outfile.write(' type="win32" />\n')
|
|
outfile.write(' <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">\n')
|
|
outfile.write(' <security>\n')
|
|
outfile.write(' <requestedPrivileges>\n')
|
|
outfile.write(' <requestedExecutionLevel\n')
|
|
|
|
if admin:
|
|
outfile.write(' level="requireAdministrator"\n')
|
|
else:
|
|
outfile.write(' level="asInvoker"\n')
|
|
|
|
outfile.write(' uiAccess="false" />\n')
|
|
outfile.write(' </requestedPrivileges>\n')
|
|
outfile.write(' </security>\n')
|
|
outfile.write(' </trustInfo>\n')
|
|
outfile.write('</assembly>\n')
|
|
outfile.close()
|
|
|
|
def write_rc_file(name, resource, outdir):
|
|
if outdir is not None:
|
|
output_file_base_name = os.path.join(outdir, name)
|
|
else:
|
|
output_file_base_name = name
|
|
|
|
if resource is None:
|
|
outfile = open(output_file_base_name + '.rc', 'w+')
|
|
outfile.write('#include <winuser.h>')
|
|
else:
|
|
if resource != output_file_base_name + '.rc':
|
|
outfile = open(output_file_base_name + '.rc', 'w+')
|
|
else:
|
|
outfile = open(output_file_base_name + '.final.rc', 'w+')
|
|
srcfile = open(resource, 'r')
|
|
outfile.write(srcfile.read())
|
|
srcfile.close()
|
|
|
|
outfile.write('\n')
|
|
outfile.write('CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "%s.exe.manifest"' % name)
|
|
outfile.close()
|
|
|
|
if __name__ == '__main__':
|
|
main()
|