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)