public static void BuildAppxPackage(string BuildOutputFolder, string BuildLongVersion, BuildFlags Flags) { string error = string.Empty; string sdkRootPath = string.Empty; string[] cleanupAppxArray = { BuildOutputFolder + "\\AppxManifest32.xml", BuildOutputFolder + "\\AppxManifest64.xml", BuildOutputFolder + "\\package32.map", BuildOutputFolder + "\\package64.map", BuildOutputFolder + "\\bundle.map", BuildOutputFolder + "\\ProcessHacker-44.png", BuildOutputFolder + "\\ProcessHacker-50.png", BuildOutputFolder + "\\ProcessHacker-150.png" }; Program.PrintColorMessage("Building processhacker-build-package.appxbundle...", ConsoleColor.Cyan); using (var view32 = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32)) { using (var kitsroot = view32.OpenSubKey("Software\\Microsoft\\Windows Kits\\Installed Roots", false)) { sdkRootPath = (string)kitsroot.GetValue("WdkBinRootVersioned", string.Empty); } } if (string.IsNullOrEmpty(sdkRootPath)) { Program.PrintColorMessage("[Skipped] Windows SDK", ConsoleColor.Red); return; } string makeAppxExePath = Environment.ExpandEnvironmentVariables(sdkRootPath + "\\x64\\MakeAppx.exe"); string signToolExePath = Environment.ExpandEnvironmentVariables(sdkRootPath + "\\x64\\SignTool.exe"); try { Win32.ImageResizeFile(44, "ProcessHacker\\resources\\ProcessHacker.png", BuildOutputFolder + "\\ProcessHacker-44.png"); Win32.ImageResizeFile(50, "ProcessHacker\\resources\\ProcessHacker.png", BuildOutputFolder + "\\ProcessHacker-50.png"); Win32.ImageResizeFile(150, "ProcessHacker\\resources\\ProcessHacker.png", BuildOutputFolder + "\\ProcessHacker-150.png"); if ((Flags & BuildFlags.Build32bit) == BuildFlags.Build32bit) { // create the package manifest string appxManifestString = Properties.Resources.AppxManifest; appxManifestString = appxManifestString.Replace("PH_APPX_ARCH", "x86"); appxManifestString = appxManifestString.Replace("PH_APPX_VERSION", BuildLongVersion); File.WriteAllText(BuildOutputFolder + "\\AppxManifest32.xml", appxManifestString); // create the package mapping file StringBuilder packageMap32 = new StringBuilder(0x100); packageMap32.AppendLine("[Files]"); packageMap32.AppendLine("\"" + BuildOutputFolder + "\\AppxManifest32.xml\" \"AppxManifest.xml\""); packageMap32.AppendLine("\"" + BuildOutputFolder + "\\ProcessHacker-44.png\" \"Assets\\ProcessHacker-44.png\""); packageMap32.AppendLine("\"" + BuildOutputFolder + "\\ProcessHacker-50.png\" \"Assets\\ProcessHacker-50.png\""); packageMap32.AppendLine("\"" + BuildOutputFolder + "\\ProcessHacker-150.png\" \"Assets\\ProcessHacker-150.png\""); var filesToAdd = Directory.GetFiles("bin\\Release32", "*", SearchOption.AllDirectories); foreach (string filePath in filesToAdd) { // Ignore junk files if (filePath.EndsWith(".pdb", StringComparison.OrdinalIgnoreCase) || filePath.EndsWith(".iobj", StringComparison.OrdinalIgnoreCase) || filePath.EndsWith(".ipdb", StringComparison.OrdinalIgnoreCase) || filePath.EndsWith(".exp", StringComparison.OrdinalIgnoreCase) || filePath.EndsWith(".lib", StringComparison.OrdinalIgnoreCase)) { continue; } packageMap32.AppendLine("\"" + filePath + "\" \"" + filePath.Substring("bin\\Release32\\".Length) + "\""); } File.WriteAllText(BuildOutputFolder + "\\package32.map", packageMap32.ToString()); // create the package error = Win32.ShellExecute( makeAppxExePath, "pack /o /f " + BuildOutputFolder + "\\package32.map /p " + BuildOutputFolder + "\\processhacker-build-package-x32.appx" ); Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray, true, Flags); // sign the package error = Win32.ShellExecute( signToolExePath, "sign /v /fd SHA256 /a /f " + BuildOutputFolder + "\\processhacker-appx.pfx /td SHA256 " + BuildOutputFolder + "\\processhacker-build-package-x32.appx" ); Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray, true, Flags); } if ((Flags & BuildFlags.Build64bit) == BuildFlags.Build64bit) { // create the package manifest string appxManifestString = Properties.Resources.AppxManifest; appxManifestString = appxManifestString.Replace("PH_APPX_ARCH", "x64"); appxManifestString = appxManifestString.Replace("PH_APPX_VERSION", BuildLongVersion); File.WriteAllText(BuildOutputFolder + "\\AppxManifest64.xml", appxManifestString); StringBuilder packageMap64 = new StringBuilder(0x100); packageMap64.AppendLine("[Files]"); packageMap64.AppendLine("\"" + BuildOutputFolder + "\\AppxManifest64.xml\" \"AppxManifest.xml\""); packageMap64.AppendLine("\"" + BuildOutputFolder + "\\ProcessHacker-44.png\" \"Assets\\ProcessHacker-44.png\""); packageMap64.AppendLine("\"" + BuildOutputFolder + "\\ProcessHacker-50.png\" \"Assets\\ProcessHacker-50.png\""); packageMap64.AppendLine("\"" + BuildOutputFolder + "\\ProcessHacker-150.png\" \"Assets\\ProcessHacker-150.png\""); var filesToAdd = Directory.GetFiles("bin\\Release64", "*", SearchOption.AllDirectories); foreach (string filePath in filesToAdd) { // Ignore junk files if (filePath.EndsWith(".pdb", StringComparison.OrdinalIgnoreCase) || filePath.EndsWith(".iobj", StringComparison.OrdinalIgnoreCase) || filePath.EndsWith(".ipdb", StringComparison.OrdinalIgnoreCase) || filePath.EndsWith(".exp", StringComparison.OrdinalIgnoreCase) || filePath.EndsWith(".lib", StringComparison.OrdinalIgnoreCase)) { continue; } packageMap64.AppendLine("\"" + filePath + "\" \"" + filePath.Substring("bin\\Release64\\".Length) + "\""); } File.WriteAllText(BuildOutputFolder + "\\package64.map", packageMap64.ToString()); // create the package error = Win32.ShellExecute( makeAppxExePath, "pack /o /f " + BuildOutputFolder + "\\package64.map /p " + BuildOutputFolder + "\\processhacker-build-package-x64.appx" ); Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray, true, Flags); // sign the package error = Win32.ShellExecute( signToolExePath, "sign /v /fd SHA256 /a /f " + BuildOutputFolder + "\\processhacker-appx.pfx /td SHA256 " + BuildOutputFolder + "\\processhacker-build-package-x64.appx" ); Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray, true, Flags); } { // create the appx bundle map StringBuilder bundleMap = new StringBuilder(0x100); bundleMap.AppendLine("[Files]"); bundleMap.AppendLine("\"" + BuildOutputFolder + "\\processhacker-build-package-x32.appx\" \"processhacker-build-package-x32.appx\""); bundleMap.AppendLine("\"" + BuildOutputFolder + "\\processhacker-build-package-x64.appx\" \"processhacker-build-package-x64.appx\""); File.WriteAllText(BuildOutputFolder + "\\bundle.map", bundleMap.ToString()); if (File.Exists(BuildOutputFolder + "\\processhacker-build-package.appxbundle")) { File.Delete(BuildOutputFolder + "\\processhacker-build-package.appxbundle"); } // create the appx bundle package error = Win32.ShellExecute( makeAppxExePath, "bundle /f " + BuildOutputFolder + "\\bundle.map /p " + BuildOutputFolder + "\\processhacker-build-package.appxbundle" ); Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray, true, Flags); // sign the appx bundle package error = Win32.ShellExecute( signToolExePath, "sign /v /fd SHA256 /a /f " + BuildOutputFolder + "\\processhacker-appx.pfx /td SHA256 " + BuildOutputFolder + "\\processhacker-build-package.appxbundle" ); Program.PrintColorMessage(Environment.NewLine + error, ConsoleColor.Gray, true, Flags); } foreach (string file in cleanupAppxArray) { if (File.Exists(file)) { File.Delete(file); } } } catch (Exception ex) { Program.PrintColorMessage("[ERROR] " + ex, ConsoleColor.Red); } }