From 676b8192d953a6361ac1ca88d24d8fa368883d8a Mon Sep 17 00:00:00 2001 From: NotEnsoul Date: Tue, 7 Jul 2026 13:47:35 +0200 Subject: [PATCH 1/2] Setup: Fix modern uninstaller wizard and legacy uninstall launch behavior --- tools/CustomSetupTool/install.c | 1 + tools/CustomSetupTool/main.c | 2 +- tools/CustomSetupTool/resource.h | 3 +- tools/CustomSetupTool/resource.rc | 7 +- tools/CustomSetupTool/setup.h | 10 +- tools/CustomSetupTool/uninstall.c | 1 + tools/CustomSetupTool/wizard.c | 197 +++++++++++++++++++++++++++++- 7 files changed, 210 insertions(+), 11 deletions(-) diff --git a/tools/CustomSetupTool/install.c b/tools/CustomSetupTool/install.c index 70f9193f4f6b..6ef69c64b3e1 100644 --- a/tools/CustomSetupTool/install.c +++ b/tools/CustomSetupTool/install.c @@ -153,6 +153,7 @@ NTSTATUS CALLBACK SetupProgressThread( SetupSetProgressText(context, L"Installation complete.", NULL); SetupSetProgressValue(context, 100); context->SetupProgressActive = FALSE; + context->SetupCompleted = TRUE; PostMessage(context->DialogHandle, SETUP_SHOWFINAL, 0, 0); return STATUS_SUCCESS; diff --git a/tools/CustomSetupTool/main.c b/tools/CustomSetupTool/main.c index 84d372ba762e..a207a4cddfa6 100644 --- a/tools/CustomSetupTool/main.c +++ b/tools/CustomSetupTool/main.c @@ -269,7 +269,7 @@ VOID SetupShowDialog( TaskDialogIndirect(&config, NULL, NULL, &value); - if (value) + if (Context->SetupMode == SetupCommandInstall && Context->SetupCompleted && value) { SetupExecuteApplication(Context); } diff --git a/tools/CustomSetupTool/resource.h b/tools/CustomSetupTool/resource.h index 9e67c934fae0..e9236f7af26f 100644 --- a/tools/CustomSetupTool/resource.h +++ b/tools/CustomSetupTool/resource.h @@ -23,6 +23,7 @@ #define IDC_PAGEICON 1008 #define IDC_SIDEBAR 1009 #define IDC_SIDEBARICON 1010 +#define IDC_REMOVESETTINGS 1011 // Next default values for new objects // @@ -31,7 +32,7 @@ #define _APS_NO_MFC 1 #define _APS_NEXT_RESOURCE_VALUE 112 #define _APS_NEXT_COMMAND_VALUE 40002 -#define _APS_NEXT_CONTROL_VALUE 1011 +#define _APS_NEXT_CONTROL_VALUE 1012 #define _APS_NEXT_SYMED_VALUE 105 #endif #endif diff --git a/tools/CustomSetupTool/resource.rc b/tools/CustomSetupTool/resource.rc index 8350bae1172f..2fcef81a4d55 100644 --- a/tools/CustomSetupTool/resource.rc +++ b/tools/CustomSetupTool/resource.rc @@ -81,7 +81,7 @@ FONT 8, "MS Shell Dlg", 400, 0, 0x0 BEGIN CONTROL "",IDC_SIDEBAR,"Static",SS_BITMAP,21,20,140,212 LTEXT "Completing the System Informer Setup Wizard",IDC_TITLE,148,4,250,34 - LTEXT "Setup has finished installing System Informer on your computer. The application may be launched by selecting the installed shortcuts.",IDC_STATIC,148,55,240,30 + LTEXT "Setup has finished installing System Informer on your computer. The application may be launched by selecting the installed shortcuts.",IDC_SUBTITLE,148,55,240,30 LTEXT "Click Finish to exit Setup.",IDC_STATIC,148,88,240,14 CONTROL "Start System Informer",IDC_STARTAPP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,148,112,240,12 END @@ -93,13 +93,13 @@ FONT 8, "MS Shell Dlg", 400, 0, 0x0 BEGIN CONTROL "",IDC_SIDEBAR,"Static",SS_BITMAP,21,20,15,13 LTEXT "System Informer Setup Wizard failed",IDC_TITLE,148,4,250,34 - LTEXT "Setup was unable to complete the operation.",IDC_STATIC,148,55,240,14 + LTEXT "Setup was unable to complete the operation.",IDC_SUBTITLE,148,55,240,14 LTEXT "",IDC_STATUS,148,78,240,42 LTEXT "Click Finish to exit Setup.",IDC_STATIC,148,130,240,14 END IDD_UNINSTALL DIALOGEX 0, 0, 408, 234 -STYLE DS_SETFONT | WS_CHILD | WS_DISABLED | WS_CAPTION +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_DISABLED | WS_CAPTION CAPTION "Uninstall" FONT 8, "MS Shell Dlg", 400, 0, 0x0 BEGIN @@ -107,6 +107,7 @@ BEGIN LTEXT "Setup is ready to remove System Informer from your computer.",IDC_SUBTITLE,25,11,338,10 ICON IDI_ICON,IDC_PAGEICON,378,0,20,20 LTEXT "Click Uninstall to continue with the uninstallation, or click Back if you want to review or change any settings.",IDC_STATIC,25,40,358,18 + CONTROL "Remove application settings",IDC_REMOVESETTINGS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,25,70,358,12 END IDD_UPDATE DIALOGEX 0, 0, 408, 234 diff --git a/tools/CustomSetupTool/setup.h b/tools/CustomSetupTool/setup.h index 470528fbf8ed..64381d2e7458 100644 --- a/tools/CustomSetupTool/setup.h +++ b/tools/CustomSetupTool/setup.h @@ -80,7 +80,8 @@ typedef struct _PH_SETUP_CONTEXT ULONG Hide : 1; ULONG NeedsReboot : 1; ULONG SetupProgressActive : 1; - ULONG Spare : 25; + ULONG SetupCompleted : 1; + ULONG Spare : 24; }; }; @@ -115,6 +116,13 @@ VOID SetupShowWizard( _In_ PPH_SETUP_CONTEXT Context ); +INT_PTR CALLBACK SetupUninstallPageDlgProc( + _In_ HWND WindowHandle, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ); + VOID ShowWelcomePageDialog( _In_ PPH_SETUP_CONTEXT Context ); diff --git a/tools/CustomSetupTool/uninstall.c b/tools/CustomSetupTool/uninstall.c index 2e6eb93ed0e8..0b85bf9b6011 100644 --- a/tools/CustomSetupTool/uninstall.c +++ b/tools/CustomSetupTool/uninstall.c @@ -113,6 +113,7 @@ NTSTATUS CALLBACK SetupUninstallBuild( if (Context->SetupRemoveAppData) SetupDeleteAppdataDirectory(Context); + Context->SetupCompleted = TRUE; PostMessage(Context->DialogHandle, SETUP_SHOWUNINSTALLFINAL, 0, 0); return STATUS_SUCCESS; diff --git a/tools/CustomSetupTool/wizard.c b/tools/CustomSetupTool/wizard.c index e58157b698c9..9e6384777fec 100644 --- a/tools/CustomSetupTool/wizard.c +++ b/tools/CustomSetupTool/wizard.c @@ -328,6 +328,8 @@ VOID SetupPaintDarkButton( oldTextColor = SetTextColor(hdc, disabled ? SetupWizardColorDisabledText : SetupWizardColorText); HFONT font = SelectFont(hdc, GetWindowFont(windowHandle)); + + // Draw the button image list (if any) before the text so the text is painted // on top. Guard against a NULL himl: Button_GetImageList can succeed while // leaving himl NULL when no image list has been assigned to the button. @@ -1134,6 +1136,152 @@ VOID SetupSetWizardButtons( SetupApplyDarkModeToControl(GetDlgItem(parentWindowHandle, IDC_PROPSHEET_CANCEL)); } +INT_PTR CALLBACK SetupUninstallPageDlgProc( + _In_ HWND WindowHandle, + _In_ UINT uMsg, + _In_ WPARAM wParam, + _In_ LPARAM lParam + ) +{ + PPH_SETUP_CONTEXT context; + + if (uMsg == WM_INITDIALOG) + { + LPPROPSHEETPAGE page = (LPPROPSHEETPAGE)lParam; + context = (PPH_SETUP_CONTEXT)page->lParam; + PhSetWindowContext(WindowHandle, PH_WINDOW_CONTEXT_DEFAULT, context); + } + else + { + context = PhGetWindowContext(WindowHandle, PH_WINDOW_CONTEXT_DEFAULT); + } + + if (!context) + return FALSE; + + switch (uMsg) + { + case WM_INITDIALOG: + { + context->DialogHandle = WindowHandle; + context->ParentWindowHandle = GetParent(WindowHandle); + + PhCenterWindow(context->ParentWindowHandle, NULL); + SetupInitializeWizardTitleFont(context, WindowHandle, FALSE); + SetupApplyDarkModeToPage(WindowHandle); + + if (PhGetOwnTokenAttributes().Elevated) + { + ShowWindow(GetDlgItem(WindowHandle, IDC_REMOVESETTINGS), SW_SHOW); + EnableWindow(GetDlgItem(WindowHandle, IDC_REMOVESETTINGS), TRUE); + } + else + { + ShowWindow(GetDlgItem(WindowHandle, IDC_REMOVESETTINGS), SW_HIDE); + EnableWindow(GetDlgItem(WindowHandle, IDC_REMOVESETTINGS), FALSE); + } + } + break; + case WM_NOTIFY: + { + LPNMHDR header = (LPNMHDR)lParam; + LRESULT result; + + result = SetupHandleControlCustomDraw((LPNMCUSTOMDRAW)lParam); + + if (result != CDRF_DODEFAULT) + { + SetWindowLongPtr(WindowHandle, DWLP_MSGRESULT, result); + return TRUE; + } + + switch (header->code) + { + case PSN_SETACTIVE: + SetupSetWizardButtons(WindowHandle, PSWIZB_NEXT, FALSE, TRUE, FALSE, TRUE); + SetupSetWizardButtonText(context->ParentWindowHandle, IDC_PROPSHEET_NEXT, L"Uninstall"); + if (!PhGetOwnTokenAttributes().Elevated) + { + Button_SetElevationRequiredState(GetDlgItem(context->ParentWindowHandle, IDC_PROPSHEET_NEXT), TRUE); + } + break; + case PSN_QUERYCANCEL: + return !SetupCancelWizard(WindowHandle, context); + case PSN_WIZNEXT: + { + if (PhGetOwnTokenAttributes().Elevated) + { + context->SetupRemoveAppData = (IsDlgButtonChecked(WindowHandle, IDC_REMOVESETTINGS) == BST_CHECKED); + } + else + { + NTSTATUS status; + PPH_STRING applicationFileName; + PH_STRINGREF applicationCommandLine; + + if (NT_SUCCESS(status = PhGetProcessCommandLineStringRef(&applicationCommandLine))) + { + if (applicationFileName = PhGetApplicationFileNameWin32()) + { + status = PhShellExecuteEx( + NULL, + PhGetString(applicationFileName), + PhGetStringRefZ(&applicationCommandLine), + NULL, + SW_SHOW, + PH_SHELL_EXECUTE_ADMIN, + 0, + NULL + ); + + if (NT_SUCCESS(status)) + { + PhExitApplication(status); + } + else if (status != STATUS_CANCELLED && status != NTSTATUS_FROM_WIN32(ERROR_CANCELLED)) + { + PhShowStatus(NULL, L"Unable to restart the application.", status, 0); + } + + PhDereferenceObject(applicationFileName); + } + } + SetWindowLongPtr(WindowHandle, DWLP_MSGRESULT, TRUE); + return TRUE; + } + SetWindowLongPtr(WindowHandle, DWLP_MSGRESULT, (LPARAM)MAKEINTRESOURCE(IDD_INSTALL)); + return TRUE; + } + break; + } + } + break; + case WM_DPICHANGED: + case WM_DPICHANGED_AFTERPARENT: + SetupRedrawEditBorder(WindowHandle); + break; + case WM_ERASEBKGND: + if (SetupWizardDarkMode) + { + SetupPaintDarkBackground(WindowHandle, (HDC)wParam); + return TRUE; + } + break; + case WM_CTLCOLORDLG: + case WM_CTLCOLORBTN: + case WM_CTLCOLORSTATIC: + case WM_CTLCOLOREDIT: + if (SetupWizardDarkMode) + return SetupHandleDarkControlColor(wParam, lParam); + break; + case WM_NCDESTROY: + SetupDestroyWizardPage(WindowHandle); + break; + } + + return FALSE; +} + /** * Dialog procedure for the wizard welcome page. * @@ -1242,7 +1390,7 @@ INT_PTR CALLBACK SetupWelcomePageDlgProc( { PhExitApplication(status); } - else + else if (status != STATUS_CANCELLED && status != NTSTATUS_FROM_WIN32(ERROR_CANCELLED)) { PhShowStatus(NULL, L"Unable to restart the application.", status, 0); } @@ -1450,6 +1598,11 @@ VOID SetupStartWizardProgress( PhCreateThread2(SetupUpdateBuild, Context); } break; + case SetupCommandUninstall: + { + PhCreateThread2(SetupUninstallBuild, Context); + } + break; case SetupCommandInstall: default: { @@ -1494,6 +1647,11 @@ INT_PTR CALLBACK SetupInstallPageDlgProc( { PostMessage(WindowHandle, SETUP_SHOWUPDATE, 0, 0); } + else if (context->SetupMode == SetupCommandUninstall) + { + SetDlgItemText(WindowHandle, IDC_TITLE, L"Uninstalling"); + SetDlgItemText(WindowHandle, IDC_SUBTITLE, L"Please wait while Setup removes System Informer from your computer."); + } } else { @@ -1535,6 +1693,7 @@ INT_PTR CALLBACK SetupInstallPageDlgProc( SetupRedrawEditBorder(WindowHandle); break; case SETUP_SHOWFINAL: + case SETUP_SHOWUNINSTALLFINAL: { PropSheet_SetCurSel(context->ParentWindowHandle, NULL, SETUP_WIZARD_COMPLETED_PAGE_INDEX); } @@ -1552,6 +1711,7 @@ INT_PTR CALLBACK SetupInstallPageDlgProc( break; case SETUP_SHOWERROR: case SETUP_SHOWUPDATEERROR: + case SETUP_SHOWUNINSTALLERROR: { PropSheet_SetCurSel(context->ParentWindowHandle, NULL, SETUP_WIZARD_ERROR_PAGE_INDEX); } @@ -1610,6 +1770,16 @@ INT_PTR CALLBACK SetupCompletedPageDlgProc( SetupApplyDarkModeToPage(WindowHandle); CheckDlgButton(WindowHandle, IDC_STARTAPP, BST_CHECKED); SetupLoadWelcomeBitmap(WindowHandle); + + if (context->SetupMode == SetupCommandUninstall) + { + ShowWindow(GetDlgItem(WindowHandle, IDC_STARTAPP), SW_HIDE); + SetDlgItemText(WindowHandle, IDC_TITLE, L"Completing the System Informer Uninstall Wizard"); + if (context->NeedsReboot) + SetDlgItemText(WindowHandle, IDC_SUBTITLE, L"A reboot is required to complete the uninstall."); + else + SetDlgItemText(WindowHandle, IDC_SUBTITLE, L"System Informer has been successfully uninstalled and removed from your computer."); + } } else { @@ -1643,7 +1813,7 @@ INT_PTR CALLBACK SetupCompletedPageDlgProc( return !SetupCancelWizard(WindowHandle, context); case PSN_WIZFINISH: { - if (IsDlgButtonChecked(WindowHandle, IDC_STARTAPP) == BST_CHECKED) + if (context->SetupMode != SetupCommandUninstall && IsDlgButtonChecked(WindowHandle, IDC_STARTAPP) == BST_CHECKED) { SetupExecuteApplication(context); } @@ -1711,6 +1881,12 @@ INT_PTR CALLBACK SetupErrorPageDlgProc( SetupInitializeWizardTitleFont(context, WindowHandle, TRUE); SetupApplyDarkModeToPage(WindowHandle); SetupLoadWelcomeBitmap(WindowHandle); + + if (context->SetupMode == SetupCommandUninstall) + { + SetDlgItemText(WindowHandle, IDC_TITLE, L"System Informer Uninstall Wizard failed"); + SetDlgItemText(WindowHandle, IDC_SUBTITLE, L"Uninstall was unable to complete the operation."); + } } else { @@ -2009,8 +2185,16 @@ VOID SetupShowWizard( pages[0].dwSize = sizeof(PROPSHEETPAGE); pages[0].dwFlags = PSP_DEFAULT | PSP_PREMATURE; pages[0].hInstance = PhInstanceHandle; - pages[0].pszTemplate = MAKEINTRESOURCE(IDD_WELCOME); - pages[0].pfnDlgProc = SetupWelcomePageDlgProc; + if (Context->SetupMode == SetupCommandUninstall) + { + pages[0].pszTemplate = MAKEINTRESOURCE(IDD_UNINSTALL); + pages[0].pfnDlgProc = SetupUninstallPageDlgProc; + } + else + { + pages[0].pszTemplate = MAKEINTRESOURCE(IDD_WELCOME); + pages[0].pfnDlgProc = SetupWelcomePageDlgProc; + } pages[0].lParam = (LPARAM)Context; pages[1].dwSize = sizeof(PROPSHEETPAGE); @@ -2048,7 +2232,10 @@ VOID SetupShowWizard( header.hInstance = PhInstanceHandle; header.hIcon = Context->IconLargeHandle; header.pfnCallback = SetupPropSheetProc; - header.pszCaption = L"System Informer Setup"; + if (Context->SetupMode == SetupCommandUninstall) + header.pszCaption = L"System Informer Uninstall"; + else + header.pszCaption = L"System Informer Setup"; header.nPages = ARRAYSIZE(pages); header.ppsp = pages; From 4f8ee4ccf3c219a6d62d6d1ead32337845f7a790 Mon Sep 17 00:00:00 2001 From: NotEnsoul Date: Tue, 7 Jul 2026 14:31:55 +0200 Subject: [PATCH 2/2] Setup: Add start page to uninstaller wizard --- tools/CustomSetupTool/resource.h | 1 + tools/CustomSetupTool/resource.rc | 17 +++++++++++++++++ tools/CustomSetupTool/wizard.c | 18 +++++++++++++----- 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/tools/CustomSetupTool/resource.h b/tools/CustomSetupTool/resource.h index e9236f7af26f..9375b2eb9bd5 100644 --- a/tools/CustomSetupTool/resource.h +++ b/tools/CustomSetupTool/resource.h @@ -13,6 +13,7 @@ #define IDD_REPAIR 109 #define IDB_PNG1 110 #define IDD_ERROR 111 +#define IDD_UNINSTALL_WELCOME 112 #define IDC_PATH 1001 #define IDC_BROWSE 1002 #define IDC_PROGRESS 1003 diff --git a/tools/CustomSetupTool/resource.rc b/tools/CustomSetupTool/resource.rc index 2fcef81a4d55..9922b6bffd8f 100644 --- a/tools/CustomSetupTool/resource.rc +++ b/tools/CustomSetupTool/resource.rc @@ -47,6 +47,18 @@ BEGIN LTEXT "Click Next to continue, or Cancel to exit setup.",IDC_STATIC,148,126,240,14 END +IDD_UNINSTALL_WELCOME DIALOGEX 0, 0, 408, 234 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_DISABLED | WS_CAPTION +CAPTION "System Informer Uninstall" +FONT 8, "MS Shell Dlg", 400, 0, 0x0 +BEGIN + CONTROL "",IDC_SIDEBAR,"Static",SS_BITMAP,21,20,140,212 + LTEXT "Welcome to the System Informer Uninstall Wizard",IDC_TITLE,148,4,250,34 + LTEXT "This will uninstall System Informer on your computer. System Informer helps you monitor system resources, debug software, and detect malware.",IDC_STATIC,148,55,240,30 + LTEXT "It is recommended you close all other applications before continuing.",IDC_STATIC,148,94,240,18 + LTEXT "Click Next to continue, or Cancel to exit uninstallation.",IDC_STATIC,148,126,240,14 +END + IDD_CONFIG DIALOGEX 0, 0, 408, 234 STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_DISABLED | WS_CAPTION CAPTION "Setup Options" @@ -173,6 +185,11 @@ BEGIN RIGHTMARGIN, 398 END + IDD_UNINSTALL_WELCOME, DIALOG + BEGIN + RIGHTMARGIN, 398 + END + IDD_CONFIG, DIALOG BEGIN RIGHTMARGIN, 395 diff --git a/tools/CustomSetupTool/wizard.c b/tools/CustomSetupTool/wizard.c index 9e6384777fec..6324f625c8e7 100644 --- a/tools/CustomSetupTool/wizard.c +++ b/tools/CustomSetupTool/wizard.c @@ -1198,7 +1198,7 @@ INT_PTR CALLBACK SetupUninstallPageDlgProc( switch (header->code) { case PSN_SETACTIVE: - SetupSetWizardButtons(WindowHandle, PSWIZB_NEXT, FALSE, TRUE, FALSE, TRUE); + SetupSetWizardButtons(WindowHandle, PSWIZB_BACK | PSWIZB_NEXT, TRUE, TRUE, FALSE, TRUE); SetupSetWizardButtonText(context->ParentWindowHandle, IDC_PROPSHEET_NEXT, L"Uninstall"); if (!PhGetOwnTokenAttributes().Elevated) { @@ -2187,8 +2187,8 @@ VOID SetupShowWizard( pages[0].hInstance = PhInstanceHandle; if (Context->SetupMode == SetupCommandUninstall) { - pages[0].pszTemplate = MAKEINTRESOURCE(IDD_UNINSTALL); - pages[0].pfnDlgProc = SetupUninstallPageDlgProc; + pages[0].pszTemplate = MAKEINTRESOURCE(IDD_UNINSTALL_WELCOME); + pages[0].pfnDlgProc = SetupWelcomePageDlgProc; } else { @@ -2200,8 +2200,16 @@ VOID SetupShowWizard( pages[1].dwSize = sizeof(PROPSHEETPAGE); pages[1].dwFlags = PSP_DEFAULT | PSP_PREMATURE; pages[1].hInstance = PhInstanceHandle; - pages[1].pszTemplate = MAKEINTRESOURCE(IDD_CONFIG); - pages[1].pfnDlgProc = SetupConfigPageDlgProc; + if (Context->SetupMode == SetupCommandUninstall) + { + pages[1].pszTemplate = MAKEINTRESOURCE(IDD_UNINSTALL); + pages[1].pfnDlgProc = SetupUninstallPageDlgProc; + } + else + { + pages[1].pszTemplate = MAKEINTRESOURCE(IDD_CONFIG); + pages[1].pfnDlgProc = SetupConfigPageDlgProc; + } pages[1].lParam = (LPARAM)Context; pages[2].dwSize = sizeof(PROPSHEETPAGE);