Skip to content

Commit

Permalink
setup silent option prep for winget support
Browse files Browse the repository at this point in the history
  • Loading branch information
jxy-s committed Oct 7, 2024
1 parent d3e266f commit 37654a9
Show file tree
Hide file tree
Showing 6 changed files with 252 additions and 88 deletions.
196 changes: 127 additions & 69 deletions tools/CustomSetupTool/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@

#include "setup.h"

#define SETUP_CMD_INSTALL 1
#define SETUP_CMD_UNINSTALL 2
#define SETUP_CMD_UPDATE 3
#define SETUP_CMD_SILENT 4

LRESULT CALLBACK SetupTaskDialogSubclassProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
Expand Down Expand Up @@ -133,13 +138,13 @@ HRESULT CALLBACK SetupTaskDialogBootstrapCallback(
switch (context->SetupMode)
{
default:
case SETUP_COMMAND_INSTALL:
case SetupCommandInstall:
ShowWelcomePageDialog(context);
break;
case SETUP_COMMAND_UNINSTALL:
case SetupCommandUninstall:
ShowUninstallPageDialog(context);
break;
case SETUP_COMMAND_UPDATE:
case SetupCommandUpdate:
ShowUpdatePageDialog(context);
break;
}
Expand Down Expand Up @@ -194,72 +199,100 @@ INT SetupShowMessagePromptForLegacyVersion(
}
}

NTSTATUS SetupCommandQuietInstall(
_In_ PPH_SETUP_CONTEXT Context
)
{
NTSTATUS status;

status = SetupProgressThread(Context);

return status;
}

VOID SetupShowDialog(
VOID
_In_ PPH_SETUP_CONTEXT Context
)
{
PPH_SETUP_CONTEXT context;
PH_AUTO_POOL autoPool;
BOOL value = FALSE;
TASKDIALOGCONFIG config;

assert(!Context->Silent);

PhInitializeAutoPool(&autoPool);

context = PhCreateAlloc(sizeof(PH_SETUP_CONTEXT));
memset(context, 0, sizeof(PH_SETUP_CONTEXT));
if (Context->SetupIsLegacyUpdate)
{
SetupShowMessagePromptForLegacyVersion();
}

SetupParseCommandLine(context);
memset(&config, 0, sizeof(TASKDIALOGCONFIG));
config.cbSize = sizeof(TASKDIALOGCONFIG);
config.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION | TDF_CAN_BE_MINIMIZED;
config.hInstance = PhInstanceHandle;
config.pszContent = L"Initializing...";
config.pfCallback = SetupTaskDialogBootstrapCallback;
config.lpCallbackData = (LONG_PTR)Context;

if (PhIsNullOrEmptyString(context->SetupInstallPath))
TaskDialogIndirect(&config, NULL, NULL, &value);

if (value)
{
context->SetupInstallPath = SetupFindInstallDirectory();
SetupExecuteApplication(Context);
}

if (context->SetupMode == SETUP_COMMAND_SILENTINSTALL)
{
NTSTATUS status = SetupCommandQuietInstall(context);
PhDeleteAutoPool(&autoPool);
}

VOID SetupSilent(
_In_ PPH_SETUP_CONTEXT Context
)
{
NTSTATUS status;

if (NT_SUCCESS(status))
assert(Context->Silent);

if (PhGetOwnTokenAttributes().Elevated)
{
switch (Context->SetupMode)
{
SetupExecuteApplication(context);
default:
case SetupCommandInstall:
status = SetupProgressThread(Context);
break;
case SetupCommandUninstall:
status = SetupUninstallBuild(Context);
break;
case SetupCommandUpdate:
status = SetupUpdateBuild(Context);
break;
}
}
else
{
TASKDIALOGCONFIG config;
PPH_STRING applicationFileName;
PH_STRINGREF applicationCommandLine;

if (context->SetupIsLegacyUpdate)
if (!NT_SUCCESS(status = PhGetProcessCommandLineStringRef(&applicationCommandLine)))
{
SetupShowMessagePromptForLegacyVersion();
Context->ErrorCode = WIN32_FROM_NTSTATUS(status);
return;
}

memset(&config, 0, sizeof(TASKDIALOGCONFIG));
config.cbSize = sizeof(TASKDIALOGCONFIG);
config.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION | TDF_CAN_BE_MINIMIZED;
config.hInstance = PhInstanceHandle;
config.pszContent = L"Initializing...";
config.pfCallback = SetupTaskDialogBootstrapCallback;
config.lpCallbackData = (LONG_PTR)context;

TaskDialogIndirect(&config, NULL, NULL, &value);
if (!(applicationFileName = PhGetApplicationFileNameWin32()))
{
Context->ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
return;
}

if (value)
if (!NT_SUCCESS(status = PhShellExecuteEx(
NULL,
PhGetString(applicationFileName),
PhGetStringRefZ(&applicationCommandLine),
NULL,
SW_SHOW,
PH_SHELL_EXECUTE_ADMIN,
INFINITE,
&Context->SubProcessHandle
)))
{
SetupExecuteApplication(context);
Context->ErrorCode = WIN32_FROM_NTSTATUS(status);
return;
}
}

PhDeleteAutoPool(&autoPool);
if (!NT_SUCCESS(status) && Context->ErrorCode == ERROR_SUCCESS)
Context->ErrorCode = WIN32_FROM_NTSTATUS(status);
}

_Success_(return)
Expand Down Expand Up @@ -334,9 +367,23 @@ BOOLEAN NTAPI MainPropSheetCommandLineCallback(

if (Option)
{
context->SetupMode = Option->Id;
switch (Option->Id)
{
case SETUP_CMD_INSTALL:
context->SetupMode = SetupCommandInstall;
break;
case SETUP_CMD_UNINSTALL:
context->SetupMode = SetupCommandUninstall;
break;
case SETUP_CMD_UPDATE:
context->SetupMode = SetupCommandUpdate;
break;
case SETUP_CMD_SILENT:
context->Silent = TRUE;
break;
}

if (context->SetupMode == SETUP_COMMAND_UPDATE && Value)
if (Option->Id == SETUP_CMD_UPDATE && Value)
{
PPH_STRING directory;
PPH_STRING serviceName;
Expand All @@ -361,24 +408,6 @@ BOOLEAN NTAPI MainPropSheetCommandLineCallback(
}
}
}
else
{
// HACK: PhParseCommandLine requires the - symbol for commandline parameters
// and we already support the -silent parameter however we need to maintain
// compatibility with the legacy Inno Setup. (dmex)
if (!PhIsNullOrEmptyString(Value))
{
if (Value && PhEqualString2(Value, L"/silent", TRUE))
{
//context->SetupMode = SETUP_COMMAND_SILENTINSTALL;
}
}
}

if (PhIsNullOrEmptyString(context->SetupInstallPath))
{
context->SetupInstallPath = SetupFindInstallDirectory();
}

return TRUE;
}
Expand All @@ -389,11 +418,10 @@ VOID SetupParseCommandLine(
{
static PH_COMMAND_LINE_OPTION options[] =
{
{ SETUP_COMMAND_INSTALL, L"install", NoArgumentType },
{ SETUP_COMMAND_UNINSTALL, L"uninstall", NoArgumentType },
{ SETUP_COMMAND_UPDATE, L"update", OptionalArgumentType },
//{ SETUP_COMMAND_UPDATE, L"silent", NoArgumentType },
//{ SETUP_COMMAND_REPAIR, L"repair", NoArgumentType },
{ SETUP_CMD_INSTALL, L"install", NoArgumentType },
{ SETUP_CMD_UNINSTALL, L"uninstall", NoArgumentType },
{ SETUP_CMD_UPDATE, L"update", NoArgumentType },
{ SETUP_CMD_SILENT, L"silent", OptionalArgumentType },
};
PH_STRINGREF commandLine;

Expand Down Expand Up @@ -451,6 +479,8 @@ INT WINAPI wWinMain(
_In_ INT CmdShow
)
{
PPH_SETUP_CONTEXT context;

if (!NT_SUCCESS(PhInitializePhLib(L"System Informer - Setup", Instance)))
return EXIT_FAILURE;

Expand All @@ -459,9 +489,37 @@ INT WINAPI wWinMain(

SetupInitializeMutant();

PhGuiSupportInitialization();
context = PhAllocateZero(sizeof(PH_SETUP_CONTEXT));

SetupShowDialog();
if (PhIsNullOrEmptyString(context->SetupInstallPath))
{
context->SetupInstallPath = SetupFindInstallDirectory();
}

SetupParseCommandLine(context);

if (context->Silent)
{
SetupSilent(context);
}
else
{
PhGuiSupportInitialization();

SetupShowDialog(context);
}

if (context->SubProcessHandle)
{
PROCESS_BASIC_INFORMATION processInfo;

PhWaitForSingleObject(context->SubProcessHandle, NULL);
PhGetProcessBasicInformation(context->SubProcessHandle, &processInfo);

context->ErrorCode = WIN32_FROM_NTSTATUS(processInfo.ExitStatus);

NtClose(context->SubProcessHandle);
}

return EXIT_SUCCESS;
return context->ErrorCode;
}
27 changes: 21 additions & 6 deletions tools/CustomSetupTool/setup.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,9 @@ DECLSPEC_SELECTANY GUID FOLDERID_PublicDesktop = { 0xC4AA340D, 0xF20F, 0x4863, {

typedef enum _SETUP_COMMAND_TYPE
{
SETUP_COMMAND_INSTALL,
SETUP_COMMAND_SILENTINSTALL,
SETUP_COMMAND_UNINSTALL,
SETUP_COMMAND_UPDATE,
SetupCommandInstall,
SetupCommandUninstall,
SetupCommandUpdate,
} SETUP_COMMAND_TYPE;

typedef struct _PH_SETUP_CONTEXT
Expand All @@ -77,7 +76,8 @@ typedef struct _PH_SETUP_CONTEXT
{
ULONG SetupRemoveAppData: 1;
ULONG SetupIsLegacyUpdate : 1;
ULONG Spare : 30;
ULONG Silent : 1;
ULONG Spare : 29;
};
};

Expand Down Expand Up @@ -113,6 +113,7 @@ typedef struct _PH_SETUP_CONTEXT
ULONG CurrentRevisionVersion;

BOOLEAN NeedsReboot;
HANDLE SubProcessHandle;
} PH_SETUP_CONTEXT, *PPH_SETUP_CONTEXT;

VOID SetupParseCommandLine(
Expand Down Expand Up @@ -306,11 +307,25 @@ BOOLEAN UpdateDownloadUpdateData(

// extract.c

BOOLEAN SetupExtractBuild(
_In_ PPH_SETUP_CONTEXT Context
);

// install.c

NTSTATUS SetupProgressThread(
_In_ PPH_SETUP_CONTEXT Context
);

BOOLEAN SetupExtractBuild(
// update.c

NTSTATUS SetupUpdateBuild(
_In_ PPH_SETUP_CONTEXT Context
);

// uninstall.c

NTSTATUS SetupUninstallBuild(
_In_ PPH_SETUP_CONTEXT Context
);

Expand Down
23 changes: 17 additions & 6 deletions tools/CustomSetupTool/startpage.c
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,10 @@ VOID ShowErrorPageDialog(
config.dwCommonButtons = TDCBF_CLOSE_BUTTON;
config.hMainIcon = Context->IconLargeHandle;
config.pszWindowTitle = PhApplicationName;
config.pszMainInstruction = L"Setup failed with an error.";
if (Context->ErrorCode)
config.pszMainInstruction = PhGetStatusMessage(0, Context->ErrorCode)->Buffer;
else
config.pszMainInstruction = L"Setup failed with an error.";
config.pszContent = L"Select Close to exit setup.";
config.cxWidth = 200;

Expand Down Expand Up @@ -177,29 +180,37 @@ HRESULT CALLBACK SetupWelcomePageCallbackProc(
}
else
{
NTSTATUS status;
PPH_STRING applicationFileName;
PH_STRINGREF applicationCommandLine;

if (!NT_SUCCESS(PhGetProcessCommandLineStringRef(&applicationCommandLine)))
if (!NT_SUCCESS(status = PhGetProcessCommandLineStringRef(&applicationCommandLine)))
{
context->ErrorCode = WIN32_FROM_NTSTATUS(status);
return S_FALSE;
}
if (!(applicationFileName = PhGetApplicationFileNameWin32()))
{
context->ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
return S_FALSE;
}

if (NT_SUCCESS(PhShellExecuteEx(
hwndDlg,
if (NT_SUCCESS(status = PhShellExecuteEx(
hwndDlg,
PhGetString(applicationFileName),
PhGetStringRefZ(&applicationCommandLine),
NULL,
SW_SHOW,
PH_SHELL_EXECUTE_ADMIN,
0,
NULL
&context->SubProcessHandle
)))
{
PhExitApplication(STATUS_SUCCESS);
ShowWindow(hwndDlg, SW_HIDE);
}
else
{
context->ErrorCode = WIN32_FROM_NTSTATUS(status);
PhDereferenceObject(applicationFileName);
return S_FALSE;
}
Expand Down
Loading

2 comments on commit 37654a9

@MagicAndre1981
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do you handle the update channels? You could submit 2 manifests with ids like Winsiderss.Systeminformer for the stable release version or Winsiderss.Systeminformer.Canary (like for Firefox where Mozilla.Firefox.ESR and Mozilla.Firefox exists) but winget needs to detect which version the users have installed and offer the correct update when running winget upgrade

@jxy-s
Copy link
Member Author

@jxy-s jxy-s commented on 37654a9 Oct 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure yet, I need to do more testing regarding that and investigate how others are handling it. The winget manifest does have an option for Channel: but it's not fully implemented. Worse case scenario UpgradeBehavior: can be set to deny to force upgrade using our own plugin - which is maybe the preferred method anyway since we have addition signature validation that happens beyond what winget could provide.

Please sign in to comment.