From ab732692a0b8939e95b81014bd52093227463c41 Mon Sep 17 00:00:00 2001 From: Chun-wei Fan Date: Fri, 30 Jun 2023 10:29:28 +0800 Subject: [PATCH] tools: Add script to create UAC manifests for Windows This is copied from the GTK source tree to put into our builds so that we can generate a manifest file to pacify UAC on Windows for 32-bit builds, as UAC will kill any 32-bit processes that it believes will be an installer or will alter the system in any ways. This will be used to fix running the custom-dispatch test program on 32-bit Windows builds. --- tools/generate-uac-manifest.py | 137 +++++++++++++++++++++++++++++++++ tools/meson.build | 8 ++ 2 files changed, 145 insertions(+) create mode 100644 tools/generate-uac-manifest.py diff --git a/tools/generate-uac-manifest.py b/tools/generate-uac-manifest.py new file mode 100644 index 000000000..a99f0a92f --- /dev/null +++ b/tools/generate-uac-manifest.py @@ -0,0 +1,137 @@ +#!/usr/bin/env python3 +# +# Copyright © 2021 Chun-wei Fan. +# +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# Original author: Chun-wei Fan + +""" +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 windows.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("\n") + outfile.write( + "\n" + ) + outfile.write(" \n") + outfile.write(" \n") + outfile.write(" \n") + outfile.write(" \n") + outfile.write(" \n") + outfile.write(" \n") + outfile.write(" \n") + outfile.write(" \n") + outfile.write("\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("#define WIN32_LEAN_AND_MEAN\n") + outfile.write("#include \n") + 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() diff --git a/tools/meson.build b/tools/meson.build index e80d4be98..257312ebf 100644 --- a/tools/meson.build +++ b/tools/meson.build @@ -24,3 +24,11 @@ if host_system != 'windows' endif gen_visibility_macros = find_program('gen-visibility-macros.py') + +# This is only needed for 32-bit (x86) Windows builds +if host_system == 'windows' and host_machine.cpu_family() == 'x86' + embed_uac_manifest = true + gen_uac_manifest = find_program('generate-uac-manifest.py') +else + embed_uac_manifest = false +endif