@joebigelow / wix-1 / commits / d47c73db

Show Burn splash screen earlier.

Make the initial Burn process show the splash screen, and show it before parsing the manifest. Fixes half of #5300

Sean Hall committed Jun 8, 2021 at 11:21 UTC d47c73dbcd0a314cf3346b9b1294063ed4a124c4
9 files changed +155 -23
src/burn/engine/core.cpp
+42 -3
@@ -1060,7 +1060,7 @@ extern "C" HRESULT CoreAppendFileHandleAttachedToCommandLine(
1060 ExitWithLastError(hr, "Failed to duplicate file handle for attached container.");
1061 }
1062
1063 - hr = StrAllocFormattedSecure(psczCommandLine, L"%ls -%ls=%Iu", *psczCommandLine, BURN_COMMANDLINE_SWITCH_FILEHANDLE_ATTACHED, reinterpret_cast<size_t>(hExecutableFile));
1063 + hr = StrAllocConcatFormattedSecure(psczCommandLine, L" -%ls=%Iu", BURN_COMMANDLINE_SWITCH_FILEHANDLE_ATTACHED, reinterpret_cast<size_t>(hExecutableFile));
1064 ExitOnFailure(hr, "Failed to append the file handle to the command line.");
1065
1066 *phExecutableFile = hExecutableFile;
@@ -1088,12 +1088,12 @@ extern "C" HRESULT CoreAppendFileHandleSelfToCommandLine(
1088 hExecutableFile = ::CreateFileW(wzExecutablePath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE, &securityAttributes, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1089 if (INVALID_HANDLE_VALUE != hExecutableFile)
1090 {
1091 - hr = StrAllocFormattedSecure(psczCommandLine, L"%ls -%ls=%Iu", *psczCommandLine, BURN_COMMANDLINE_SWITCH_FILEHANDLE_SELF, reinterpret_cast<size_t>(hExecutableFile));
1091 + hr = StrAllocConcatFormattedSecure(psczCommandLine, L" -%ls=%Iu", BURN_COMMANDLINE_SWITCH_FILEHANDLE_SELF, reinterpret_cast<size_t>(hExecutableFile));
1092 ExitOnFailure(hr, "Failed to append the file handle to the command line.");
1093
1094 if (psczObfuscatedCommandLine)
1095 {
1096 - hr = StrAllocFormatted(psczObfuscatedCommandLine, L"%ls -%ls=%Iu", *psczObfuscatedCommandLine, BURN_COMMANDLINE_SWITCH_FILEHANDLE_SELF, reinterpret_cast<size_t>(hExecutableFile));
1096 + hr = StrAllocConcatFormatted(psczObfuscatedCommandLine, L" -%ls=%Iu", BURN_COMMANDLINE_SWITCH_FILEHANDLE_SELF, reinterpret_cast<size_t>(hExecutableFile));
1097 ExitOnFailure(hr, "Failed to append the file handle to the obfuscated command line.");
1098 }
1099
@@ -1107,6 +1107,23 @@ LExit:
1107 return hr;
1108 }
1109
1110 +extern "C" HRESULT CoreAppendSplashScreenWindowToCommandLine(
1111 + __in_opt HWND hwndSplashScreen,
1112 + __deref_inout_z LPWSTR* psczCommandLine
1113 + )
1114 +{
1115 + HRESULT hr = S_OK;
1116 +
1117 + if (hwndSplashScreen)
1118 + {
1119 + hr = StrAllocConcatFormattedSecure(psczCommandLine, L" -%ls=%Iu", BURN_COMMANDLINE_SWITCH_SPLASH_SCREEN, reinterpret_cast<size_t>(hwndSplashScreen));
1120 + ExitOnFailure(hr, "Failed to append the splash screen window to the command line.");
1121 + }
1122 +
1123 +LExit:
1124 + return hr;
1125 +}
1126 +
1127 extern "C" void CoreCleanup(
1128 __in BURN_ENGINE_STATE* pEngineState
1129 )
@@ -1571,6 +1588,28 @@ extern "C" HRESULT CoreParseCommandLine(
1588 }
1589 }
1590 }
1591 + else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], lstrlenW(BURN_COMMANDLINE_SWITCH_SPLASH_SCREEN), BURN_COMMANDLINE_SWITCH_SPLASH_SCREEN, lstrlenW(BURN_COMMANDLINE_SWITCH_SPLASH_SCREEN)))
1592 + {
1593 + LPCWSTR wzParam = &argv[i][2 + lstrlenW(BURN_COMMANDLINE_SWITCH_SPLASH_SCREEN)];
1594 + if (L'=' != wzParam[-1] || L'\0' == wzParam[0])
1595 + {
1596 + fInvalidCommandLine = TRUE;
1597 + TraceLog(E_INVALIDARG, "Missing required parameter for switch: %ls", BURN_COMMANDLINE_SWITCH_SPLASH_SCREEN);
1598 + }
1599 + else
1600 + {
1601 + hr = StrStringToUInt64(wzParam, 0, &qw);
1602 + if (FAILED(hr))
1603 + {
1604 + TraceLog(hr, "Failed to parse splash screen window: '%ls'", wzParam);
1605 + hr = S_OK;
1606 + }
1607 + else
1608 + {
1609 + pCommand->hwndSplashScreen = (HWND)qw;
1610 + }
1611 + }
1612 + }
1613 else if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, &argv[i][1], lstrlenW(BURN_COMMANDLINE_SWITCH_PREFIX), BURN_COMMANDLINE_SWITCH_PREFIX, lstrlenW(BURN_COMMANDLINE_SWITCH_PREFIX)))
1614 {
1615 // Skip (but log) any other private burn switches we don't recognize, so that
src/burn/engine/core.h
+5
@@ -29,6 +29,7 @@ const LPCWSTR BURN_COMMANDLINE_SWITCH_IGNOREDEPENDENCIES = L"burn.ignoredependen
29 const LPCWSTR BURN_COMMANDLINE_SWITCH_ANCESTORS = L"burn.ancestors";
30 const LPCWSTR BURN_COMMANDLINE_SWITCH_FILEHANDLE_ATTACHED = L"burn.filehandle.attached";
31 const LPCWSTR BURN_COMMANDLINE_SWITCH_FILEHANDLE_SELF = L"burn.filehandle.self";
32 +const LPCWSTR BURN_COMMANDLINE_SWITCH_SPLASH_SCREEN = L"burn.splash.screen";
33 const LPCWSTR BURN_COMMANDLINE_SWITCH_PREFIX = L"burn.";
34
35 const LPCWSTR BURN_BUNDLE_LAYOUT_DIRECTORY = L"WixBundleLayoutDirectory";
@@ -228,6 +229,10 @@ HRESULT CoreAppendFileHandleSelfToCommandLine(
229 __deref_inout_z LPWSTR* psczCommandLine,
230 __deref_inout_z_opt LPWSTR* psczObfuscatedCommandLine
231 );
232 +HRESULT CoreAppendSplashScreenWindowToCommandLine(
233 + __in_opt HWND hwndSplashScreen,
234 + __deref_inout_z LPWSTR* psczCommandLine
235 + );
236 void CoreCleanup(
237 __in BURN_ENGINE_STATE* pEngineState
238 );
src/burn/engine/engine.cpp
+9 -6
@@ -122,6 +122,11 @@ extern "C" HRESULT EngineRun(
122
123 engineState.command.nCmdShow = nCmdShow;
124
125 + if (BURN_MODE_ELEVATED != engineState.mode && BOOTSTRAPPER_DISPLAY_NONE < engineState.command.display && !engineState.command.hwndSplashScreen)
126 + {
127 + SplashScreenCreate(hInstance, NULL, &engineState.command.hwndSplashScreen);
128 + }
129 +
130 // initialize platform layer
131 PlatformInitialize();
132
@@ -452,7 +457,10 @@ static HRESULT RunUntrusted(
457 hr = CoreAppendFileHandleSelfToCommandLine(wzCleanRoomBundlePath, &hFileSelf, &sczParameters, NULL);
458 ExitOnFailure(hr, "Failed to append %ls", BURN_COMMANDLINE_SWITCH_FILEHANDLE_SELF);
459
455 - hr = StrAllocFormattedSecure(&sczParameters, L"%ls %ls", sczParameters, wzCommandLine);
460 + hr = CoreAppendSplashScreenWindowToCommandLine(pEngineState->command.hwndSplashScreen, &sczParameters);
461 + ExitOnFailure(hr, "Failed to append %ls", BURN_COMMANDLINE_SWITCH_SPLASH_SCREEN);
462 +
463 + hr = StrAllocConcatFormattedSecure(&sczParameters, L" %ls", wzCommandLine);
464 ExitOnFailure(hr, "Failed to append original command line.");
465
466 #ifdef ENABLE_UNELEVATE
@@ -525,11 +533,6 @@ static HRESULT RunNormal(
533 ExitFunction1(hr = S_OK);
534 }
535
528 - if (pEngineState->userExperience.fSplashScreen && BOOTSTRAPPER_DISPLAY_NONE < pEngineState->command.display)
529 - {
530 - SplashScreenCreate(hInstance, NULL, &pEngineState->command.hwndSplashScreen);
531 - }
532 -
536 // Create a top-level window to handle system messages.
537 hr = UiCreateMessageWindow(hInstance, pEngineState);
538 ExitOnFailure(hr, "Failed to create the message window.");
src/burn/engine/splashscreen.cpp
+37 -2
@@ -3,7 +3,6 @@
3 #include "precomp.h"
4
5 #define BURN_SPLASHSCREEN_CLASS_WINDOW L"WixBurnSplashScreen"
6 -#define IDB_SPLASHSCREEN 1
6
7 // struct
8
@@ -21,12 +20,17 @@ struct SPLASHSCREEN_CONTEXT
20 HANDLE hInitializedEvent;
21 HINSTANCE hInstance;
22 LPCWSTR wzCaption;
23 + BURN_SPLASH_SCREEN_CONFIGURATION* pSplashScreenConfiguration;
24
25 HWND* pHwnd;
26 };
27
28 // internal function definitions
29
30 +static HRESULT LoadConfiguration(
31 + __in HINSTANCE hInstance,
32 + __in BURN_SPLASH_SCREEN_CONFIGURATION** ppSplashScreenConfiguration
33 + );
34 static DWORD WINAPI ThreadProc(
35 __in LPVOID pvContext
36 );
@@ -74,6 +78,19 @@ extern "C" void SplashScreenCreate(
78 HANDLE rgSplashScreenEvents[2] = { };
79 DWORD dwSplashScreenThreadId = 0;
80
81 + hr = LoadConfiguration(hInstance, &context.pSplashScreenConfiguration);
82 + ExitOnFailure(hr, "Failed to load splash screen configuration.");
83 +
84 + switch (context.pSplashScreenConfiguration->type)
85 + {
86 + case BURN_SPLASH_SCREEN_TYPE_NONE:
87 + ExitFunction();
88 + case BURN_SPLASH_SCREEN_TYPE_BITMAP_RESOURCE:
89 + break;
90 + default:
91 + ExitWithRootFailure(hr, E_INVALIDDATA, "Invalid splash screen type: %i", context.pSplashScreenConfiguration->type);
92 + }
93 +
94 rgSplashScreenEvents[0] = ::CreateEventW(NULL, TRUE, FALSE, NULL);
95 ExitOnNullWithLastError(rgSplashScreenEvents[0], hr, "Failed to create modal event.");
96
@@ -125,6 +142,24 @@ LExit:
142 }
143
144
145 +static HRESULT LoadConfiguration(
146 + __in HINSTANCE hInstance,
147 + __in BURN_SPLASH_SCREEN_CONFIGURATION** ppSplashScreenConfiguration
148 + )
149 +{
150 + HRESULT hr = S_OK;
151 + DWORD cbData = 0;
152 +
153 + hr = ResReadData(hInstance, MAKEINTRESOURCEA(IDD_BURN_SPLASH_SCREEN_CONFIGURATION), reinterpret_cast<PVOID*>(ppSplashScreenConfiguration), &cbData);
154 + ExitOnFailure(hr, "Failed to read splash screen configuration resource.");
155 +
156 + AssertSz(sizeof(BURN_SPLASH_SCREEN_CONFIGURATION) == cbData, "Splash screen configuration resource size is wrong");
157 +
158 +LExit:
159 + return hr;
160 +}
161 +
162 +
163 static DWORD WINAPI ThreadProc(
164 __in LPVOID pvContext
165 )
@@ -242,7 +277,7 @@ static HRESULT LoadSplashScreen(
277 RECT* pMonitorRect = NULL;
278
279 pSplashScreen->nDpi = USER_DEFAULT_SCREEN_DPI;
245 - pSplashScreen->hBitmap = ::LoadBitmapW(pContext->hInstance, MAKEINTRESOURCEW(IDB_SPLASHSCREEN));
280 + pSplashScreen->hBitmap = ::LoadBitmapW(pContext->hInstance, MAKEINTRESOURCEW(pContext->pSplashScreenConfiguration->wResourceId));
281 ExitOnNullWithLastError(pSplashScreen->hBitmap, hr, "Failed to load splash screen bitmap.");
282
283 ::GetObject(pSplashScreen->hBitmap, sizeof(bmp), static_cast<void*>(&bmp));
src/burn/engine/splashscreen.h
+14
@@ -6,12 +6,26 @@
6 extern "C" {
7 #endif
8
9 +// IDD_BURN_SPLASH_SCREEN_CONFIGURATION, BURN_SPLASH_SCREEN_TYPE, and BURN_SPLASH_SCREEN_CONFIGURATION must stay in sync with src\wix\WixToolset.Core.Burn\Bundles\CreateBundleExeCommand.cs
10 +
11 +#define IDD_BURN_SPLASH_SCREEN_CONFIGURATION 1
12
13 // constants
14
15 +enum BURN_SPLASH_SCREEN_TYPE
16 +{
17 + BURN_SPLASH_SCREEN_TYPE_NONE,
18 + BURN_SPLASH_SCREEN_TYPE_BITMAP_RESOURCE,
19 +};
20
21 // structs
22
23 +typedef struct _BURN_SPLASH_SCREEN_CONFIGURATION
24 +{
25 + BURN_SPLASH_SCREEN_TYPE type;
26 + WORD wResourceId;
27 +} BURN_SPLASH_SCREEN_CONFIGURATION;
28 +
29
30 // functions
31
src/burn/engine/userexperience.cpp
-7
@@ -54,13 +54,6 @@ extern "C" HRESULT UserExperienceParseFromXml(
54 }
55 ExitOnFailure(hr, "Failed to select user experience node.");
56
57 - // parse splash screen
58 - hr = XmlGetYesNoAttribute(pixnUserExperienceNode, L"SplashScreen", &pUserExperience->fSplashScreen);
59 - if (E_NOTFOUND != hr)
60 - {
61 - ExitOnFailure(hr, "Failed to to get UX/@SplashScreen");
62 - }
63 -
57 // parse payloads
58 hr = PayloadsParseFromXml(&pUserExperience->payloads, NULL, NULL, pixnUserExperienceNode);
59 ExitOnFailure(hr, "Failed to parse user experience payloads.");
src/burn/engine/userexperience.h
-1
@@ -19,7 +19,6 @@ typedef struct _BOOTSTRAPPER_ENGINE_CONTEXT BOOTSTRAPPER_ENGINE_CONTEXT;
19
20 typedef struct _BURN_USER_EXPERIENCE
21 {
22 - BOOL fSplashScreen;
22 BURN_PAYLOADS payloads;
23
24 HMODULE hUXModule;
src/wix/WixToolset.Core.Burn/Bundles/CreateBundleExeCommand.cs
+48
@@ -6,6 +6,7 @@ namespace WixToolset.Core.Burn.Bundles
6 using System.Collections.Generic;
7 using System.IO;
8 using System.Reflection;
9 + using System.Runtime.InteropServices;
10 using System.Text;
11 using System.Xml;
12 using WixToolset.Core.Native;
@@ -303,17 +304,64 @@ namespace WixToolset.Core.Burn.Bundles
304 }
305 }
306
307 + var splashScreenType = BURN_SPLASH_SCREEN_TYPE.BURN_SPLASH_SCREEN_TYPE_NONE;
308 +
309 if (!String.IsNullOrEmpty(bundleInfo.SplashScreenSourceFile))
310 {
311 var bitmap = new Dtf.Resources.BitmapResource("#1", burnLocale);
312 bitmap.ReadFromFile(bundleInfo.SplashScreenSourceFile);
313 resources.Add(bitmap);
314 +
315 + splashScreenType = BURN_SPLASH_SCREEN_TYPE.BURN_SPLASH_SCREEN_TYPE_BITMAP_RESOURCE;
316 }
317
318 + var splashScreenConfig = new BURN_SPLASH_SCREEN_CONFIGURATION
319 + {
320 + Type = splashScreenType,
321 + ResourceId = 1,
322 + };
323 +
324 + var splashScreenConfigResource = new Dtf.Resources.Resource(ResourceType.RCData, "#1", burnLocale, splashScreenConfig.ToBytes());
325 + resources.Add(splashScreenConfigResource);
326 +
327 var manifestResource = new Resource(ResourceType.Manifest, "#1", burnLocale, applicationManifestData);
328 resources.Add(manifestResource);
329
330 resources.Save(bundleTempPath);
331 }
332 +
333 + enum BURN_SPLASH_SCREEN_TYPE
334 + {
335 + BURN_SPLASH_SCREEN_TYPE_NONE,
336 + BURN_SPLASH_SCREEN_TYPE_BITMAP_RESOURCE,
337 + }
338 +
339 + [StructLayout(LayoutKind.Sequential)]
340 + struct BURN_SPLASH_SCREEN_CONFIGURATION
341 + {
342 + [MarshalAs(UnmanagedType.I4)]
343 + public BURN_SPLASH_SCREEN_TYPE Type;
344 +
345 + [MarshalAs(UnmanagedType.U2)]
346 + public UInt16 ResourceId;
347 +
348 + public byte[] ToBytes()
349 + {
350 + var cb = Marshal.SizeOf(this);
351 + var data = new byte[cb];
352 + var pBuffer = Marshal.AllocHGlobal(cb);
353 +
354 + try
355 + {
356 + Marshal.StructureToPtr(this, pBuffer, true);
357 + Marshal.Copy(pBuffer, data, 0, cb);
358 + return data;
359 + }
360 + finally
361 + {
362 + Marshal.FreeHGlobal(pBuffer);
363 + }
364 + }
365 + }
366 }
367 }
src/wix/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs
-4
@@ -158,10 +158,6 @@ namespace WixToolset.Core.Burn.Bundles
158
159 // write the UX element
160 writer.WriteStartElement("UX");
161 - if (!String.IsNullOrEmpty(this.BundleSymbol.SplashScreenSourceFile))
162 - {
163 - writer.WriteAttributeString("SplashScreen", "yes");
164 - }
161
162 // write the UX allPayloads...
163 foreach (var payload in this.UXContainerPayloads)