Allow more customization of control ids in thmutil.
Allow BAFunctions to set control ids. Make sure control ids don't collide.
Sean Hall committed
Oct 27, 2021 at 13:55 UTC
8fa040da9d0d3826f5ffda6bcbec4f53abd97452
13 files changed
+374
-48
src/api/burn/balutil/inc/BAFunctions.h
+18
@@ -85,6 +85,7 @@ enum BA_FUNCTIONS_MESSAGE
85
86
BA_FUNCTIONS_MESSAGE_ONTHEMELOADED = 1024,
87
BA_FUNCTIONS_MESSAGE_WNDPROC,
88
+ BA_FUNCTIONS_MESSAGE_ONTHEMECONTROLLOADING,
89
};
90
91
typedef HRESULT(WINAPI *PFN_BA_FUNCTIONS_PROC)(
@@ -94,6 +95,10 @@ typedef HRESULT(WINAPI *PFN_BA_FUNCTIONS_PROC)(
95
__in_opt LPVOID pvContext
96
);
97
98
+// Should be the same as THEME_FIRST_ASSIGN_CONTROL_ID.
99
+// BAFunctions must only assign ids in the range [BAFUNCTIONS_FIRST_ASSIGN_CONTROL_ID, 0x8000) to avoid collisions.
100
+const WORD BAFUNCTIONS_FIRST_ASSIGN_CONTROL_ID = 0x4000;
101
+
102
struct BA_FUNCTIONS_CREATE_ARGS
103
{
104
DWORD cbSize;
@@ -108,6 +113,19 @@ struct BA_FUNCTIONS_CREATE_RESULTS
113
LPVOID pvBAFunctionsProcContext;
114
};
115
116
+struct BA_FUNCTIONS_ONTHEMECONTROLLOADING_ARGS
117
+{
118
+ DWORD cbSize;
119
+ LPCWSTR wzName;
120
+};
121
+
122
+struct BA_FUNCTIONS_ONTHEMECONTROLLOADING_RESULTS
123
+{
124
+ DWORD cbSize;
125
+ BOOL fProcessed;
126
+ WORD wId;
127
+};
128
+
129
struct BA_FUNCTIONS_ONTHEMELOADED_ARGS
130
{
131
DWORD cbSize;
src/api/burn/balutil/inc/BalBaseBAFunctions.h
+9
@@ -841,6 +841,15 @@ public: // IBAFunctions
841
return E_NOTIMPL;
842
}
843
844
+ virtual STDMETHODIMP OnThemeControlLoading(
845
+ __in LPCWSTR /*wzName*/,
846
+ __inout BOOL* /*pfProcessed*/,
847
+ __inout WORD* /*pwId*/
848
+ )
849
+ {
850
+ return S_OK;
851
+ }
852
+
853
protected:
854
CBalBaseBAFunctions(
855
__in HMODULE hModule,
src/api/burn/balutil/inc/BalBaseBAFunctionsProc.h
+12
@@ -24,6 +24,15 @@ static HRESULT BalBaseBAFunctionsProcWndProc(
24
return pBAFunctions->WndProc(pArgs->pTheme, pArgs->hWnd, pArgs->uMsg, pArgs->wParam, pArgs->lParam, &pResults->lres);
25
}
26
27
+static HRESULT BalBaseBAFunctionsProcOnThemeControlLoading(
28
+ __in IBAFunctions* pBAFunctions,
29
+ __in BA_FUNCTIONS_ONTHEMECONTROLLOADING_ARGS* pArgs,
30
+ __inout BA_FUNCTIONS_ONTHEMECONTROLLOADING_RESULTS* pResults
31
+ )
32
+{
33
+ return pBAFunctions->OnThemeControlLoading(pArgs->wzName, &pResults->fProcessed, &pResults->wId);
34
+}
35
+
36
/*******************************************************************
37
BalBaseBAFunctionsProc - requires pvContext to be of type IBAFunctions.
38
Provides a default mapping between the message based BAFunctions interface and
@@ -125,6 +134,9 @@ static HRESULT WINAPI BalBaseBAFunctionsProc(
134
case BA_FUNCTIONS_MESSAGE_WNDPROC:
135
hr = BalBaseBAFunctionsProcWndProc(pBAFunctions, reinterpret_cast<BA_FUNCTIONS_WNDPROC_ARGS*>(pvArgs), reinterpret_cast<BA_FUNCTIONS_WNDPROC_RESULTS*>(pvResults));
136
break;
137
+ case BA_FUNCTIONS_MESSAGE_ONTHEMECONTROLLOADING:
138
+ hr = BalBaseBAFunctionsProcOnThemeControlLoading(pBAFunctions, reinterpret_cast<BA_FUNCTIONS_ONTHEMECONTROLLOADING_ARGS*>(pvArgs), reinterpret_cast<BA_FUNCTIONS_ONTHEMECONTROLLOADING_RESULTS*>(pvResults));
139
+ break;
140
}
141
}
142
src/api/burn/balutil/inc/IBAFunctions.h
+8
@@ -31,4 +31,12 @@ DECLARE_INTERFACE_IID_(IBAFunctions, IBootstrapperApplication, "0FB445ED-17BD-49
31
__inout LPVOID pvResults,
32
__in_opt LPVOID pvContext
33
) = 0;
34
+
35
+ // OnThemeControlLoading - Called while creating a control for the theme.
36
+ //
37
+ STDMETHOD(OnThemeControlLoading)(
38
+ __in LPCWSTR wzName,
39
+ __inout BOOL* pfProcessed,
40
+ __inout WORD* pwId
41
+ ) = 0;
42
};
src/ext/Bal/wixstdba/WixStandardBootstrapperApplication.cpp
+62
-3
@@ -77,10 +77,15 @@ static LPCWSTR vrgwzPageNames[] = {
77
L"Failure",
78
};
79
80
+// The range [0, 100) is unused to avoid collisions with system ids,
81
+// the range [100, 0x4000) is unused to avoid collisions with thmutil,
82
+// the range [0x4000, 0x8000) is unused to avoid collisions with BAFunctions.
83
+const WORD WIXSTDBA_FIRST_ASSIGN_CONTROL_ID = 0x8000;
84
+
85
enum WIXSTDBA_CONTROL
86
{
87
// Welcome page
83
- WIXSTDBA_CONTROL_INSTALL_BUTTON = THEME_FIRST_ASSIGN_CONTROL_ID,
88
+ WIXSTDBA_CONTROL_INSTALL_BUTTON = WIXSTDBA_FIRST_ASSIGN_CONTROL_ID,
89
WIXSTDBA_CONTROL_EULA_RICHEDIT,
90
WIXSTDBA_CONTROL_EULA_LINK,
91
WIXSTDBA_CONTROL_EULA_ACCEPT_CHECKBOX,
@@ -2833,6 +2838,9 @@ private:
2838
}
2839
break;
2840
2841
+ case WM_THMUTIL_LOADING_CONTROL:
2842
+ return pBA->OnThemeLoadingControl(reinterpret_cast<THEME_LOADINGCONTROL_ARGS*>(wParam), reinterpret_cast<THEME_LOADINGCONTROL_RESULTS*>(lParam));
2843
+
2844
case WM_QUERYENDSESSION:
2845
fCancel = true;
2846
pBA->OnSystemShutdown(static_cast<DWORD>(lParam), &fCancel);
@@ -2956,7 +2964,7 @@ private:
2964
BA_FUNCTIONS_ONTHEMELOADED_ARGS themeLoadedArgs = { };
2965
BA_FUNCTIONS_ONTHEMELOADED_RESULTS themeLoadedResults = { };
2966
2959
- hr = ThemeLoadControls(m_pTheme, vrgInitControls, countof(vrgInitControls));
2967
+ hr = ThemeLoadControls(m_pTheme);
2968
BalExitOnFailure(hr, "Failed to load theme controls.");
2969
2970
C_ASSERT(COUNT_WIXSTDBA_PAGE == countof(vrgwzPageNames));
@@ -3029,6 +3037,57 @@ private:
3037
return SUCCEEDED(hr);
3038
}
3039
3040
+ BOOL OnThemeLoadingControl(
3041
+ __in const THEME_LOADINGCONTROL_ARGS* pArgs,
3042
+ __in THEME_LOADINGCONTROL_RESULTS* pResults
3043
+ )
3044
+ {
3045
+ HRESULT hr = S_OK;
3046
+ BOOL fProcessed = FALSE;
3047
+ BA_FUNCTIONS_ONTHEMECONTROLLOADING_ARGS themeControlLoadingArgs = { };
3048
+ BA_FUNCTIONS_ONTHEMECONTROLLOADING_RESULTS themeControlLoadingResults = { };
3049
+
3050
+ for (DWORD iAssignControl = 0; iAssignControl < countof(vrgInitControls); ++iAssignControl)
3051
+ {
3052
+ if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, pArgs->pThemeControl->sczName, -1, vrgInitControls[iAssignControl].wzName, -1))
3053
+ {
3054
+ fProcessed = TRUE;
3055
+ pResults->wId = vrgInitControls[iAssignControl].wId;
3056
+ ExitFunction();
3057
+ }
3058
+ }
3059
+
3060
+ if (m_pfnBAFunctionsProc)
3061
+ {
3062
+ themeControlLoadingArgs.cbSize = sizeof(themeControlLoadingArgs);
3063
+ themeControlLoadingArgs.wzName = pArgs->pThemeControl->sczName;
3064
+
3065
+ themeControlLoadingResults.cbSize = sizeof(themeControlLoadingResults);
3066
+ themeControlLoadingResults.wId = pResults->wId;
3067
+
3068
+ hr = m_pfnBAFunctionsProc(BA_FUNCTIONS_MESSAGE_ONTHEMECONTROLLOADING, &themeControlLoadingArgs, &themeControlLoadingResults, m_pvBAFunctionsProcContext);
3069
+
3070
+ if (E_NOTIMPL == hr)
3071
+ {
3072
+ hr = S_OK;
3073
+ }
3074
+ else
3075
+ {
3076
+ BalExitOnFailure(hr, "BAFunctions OnThemeControlLoading failed.");
3077
+
3078
+ if (themeControlLoadingResults.fProcessed)
3079
+ {
3080
+ fProcessed = TRUE;
3081
+ pResults->wId = themeControlLoadingResults.wId;
3082
+ }
3083
+ }
3084
+ }
3085
+
3086
+ LExit:
3087
+ pResults->hr = hr;
3088
+ return fProcessed || FAILED(hr);
3089
+ }
3090
+
3091
3092
//
3093
// OnShowFailure - display the failure page.
@@ -3857,7 +3916,7 @@ private:
3916
BalExitOnNullWithLastError(pfnBAFunctionsCreate, hr, "Failed to get BAFunctionsCreate entry-point from: %ls", sczBafPath);
3917
3918
bafCreateArgs.cbSize = sizeof(bafCreateArgs);
3860
- bafCreateArgs.qwBAFunctionsAPIVersion = MAKEQWORDVERSION(0, 0, 0, 2); // TODO: need to decide whether to keep this, and if so when to update it.
3919
+ bafCreateArgs.qwBAFunctionsAPIVersion = MAKEQWORDVERSION(2021, 9, 20, 0);
3920
bafCreateArgs.pBootstrapperCreateArgs = &m_createArgs;
3921
3922
bafCreateResults.cbSize = sizeof(bafCreateResults);
src/libs/dutil/WixToolset.DUtil/inc/thmutil.h
+30
-5
@@ -95,6 +95,15 @@ typedef enum THEME_WINDOW_INITIAL_POSITION
95
THEME_WINDOW_INITIAL_POSITION_CENTER_MONITOR_FROM_COORDINATES,
96
} THEME_WINDOW_INITIAL_POSITION;
97
98
+// These messages are sent by thmutil to the parent window created in ThemeCreateParentWindow.
99
+// thmutil reserves the last values of WM_USER's range.
100
+typedef enum _WM_THMUTIL
101
+{
102
+ // Sent while creating a control.
103
+ // wparam is THEME_LOADINGCONTROL_ARGS* and lparam is THEME_LOADINGCONTROL_RESULTS*.
104
+ // Return code is TRUE if it was processed.
105
+ WM_THMUTIL_LOADING_CONTROL = WM_APP - 1,
106
+} WM_THMUTIL;
107
108
struct THEME_COLUMN
109
{
@@ -171,7 +180,7 @@ struct THEME_ASSIGN_CONTROL_ID
180
LPCWSTR wzName; // name of control to match
181
};
182
174
-const DWORD THEME_FIRST_ASSIGN_CONTROL_ID = 1024; // Recommended first control id to be assigned.
183
+const WORD THEME_FIRST_ASSIGN_CONTROL_ID = 0x4000; // Recommended first control id to be assigned.
184
185
struct THEME_CONTROL
186
{
@@ -325,7 +334,7 @@ struct THEME_FONT
334
335
struct THEME
336
{
328
- WORD wId;
337
+ WORD wNextControlId;
338
339
BOOL fAutoResize;
340
BOOL fForceResize;
@@ -388,6 +397,24 @@ struct THEME
397
LPVOID pvVariableContext;
398
};
399
400
+typedef struct _THEME_LOADINGCONTROL_ARGS
401
+{
402
+ DWORD cbSize;
403
+ const THEME_CONTROL* pThemeControl;
404
+} THEME_LOADINGCONTROL_ARGS;
405
+
406
+typedef struct _THEME_LOADINGCONTROL_RESULTS
407
+{
408
+ DWORD cbSize;
409
+ HRESULT hr;
410
+
411
+ // Used to apply a specific id to the control (usually used for WM_COMMAND).
412
+ // If assigning an id, it is recommended to start with THEME_FIRST_ASSIGN_CONTROL_ID to avoid collisions with well known ids such as IDOK and IDCANCEL.
413
+ // The values [100, THEME_FIRST_ASSIGN_CONTROL_ID) are reserved for thmutil.
414
+ // Due to this value being packed into 16 bits for many system window messages, this is restricted to a WORD.
415
+ WORD wId;
416
+} THEME_LOADINGCONTROL_RESULTS;
417
+
418
419
/********************************************************************
420
ThemeInitialize - initialized theme management.
@@ -472,9 +499,7 @@ HRESULT DAPI ThemeCreateParentWindow(
499
500
*******************************************************************/
501
HRESULT DAPI ThemeLoadControls(
475
- __in THEME* pTheme,
476
- __in_ecount_opt(cAssignControlIds) const THEME_ASSIGN_CONTROL_ID* rgAssignControlIds,
477
- __in DWORD cAssignControlIds
502
+ __in THEME* pTheme
503
);
504
505
/********************************************************************
src/libs/dutil/WixToolset.DUtil/thmutil.cpp
+51
-24
@@ -39,6 +39,7 @@
39
#define LWS_NOPREFIX 0x0004
40
#endif
41
42
+const WORD THEME_FIRST_AUTO_ASSIGN_CONTROL_ID = 100;
43
const DWORD THEME_INVALID_ID = 0xFFFFFFFF;
44
const COLORREF THEME_INVISIBLE_COLORREF = 0xFFFFFFFF;
45
const DWORD GROW_FONT_INSTANCES = 3;
@@ -272,11 +273,14 @@ static HRESULT FindImageList(
273
__in_z LPCWSTR wzImageListName,
274
__out HIMAGELIST *phImageList
275
);
276
+static HRESULT OnLoadingControl(
277
+ __in THEME* pTheme,
278
+ __in const THEME_CONTROL* pControl,
279
+ __inout WORD* pwId
280
+ );
281
static HRESULT LoadControls(
282
__in THEME* pTheme,
277
- __in_opt THEME_CONTROL* pParentControl,
278
- __in_ecount_opt(cAssignControlIds) const THEME_ASSIGN_CONTROL_ID* rgAssignControlIds,
279
- __in DWORD cAssignControlIds
283
+ __in_opt THEME_CONTROL* pParentControl
284
);
285
static HRESULT ShowControl(
286
__in THEME* pTheme,
@@ -871,9 +875,7 @@ LExit:
875
876
877
DAPI_(HRESULT) ThemeLoadControls(
874
- __in THEME* pTheme,
875
- __in_ecount_opt(cAssignControlIds) const THEME_ASSIGN_CONTROL_ID* rgAssignControlIds,
876
- __in DWORD cAssignControlIds
878
+ __in THEME* pTheme
879
)
880
{
881
HRESULT hr = S_OK;
@@ -883,7 +885,7 @@ DAPI_(HRESULT) ThemeLoadControls(
885
ThmExitOnFailure(hr = E_INVALIDSTATE, "ThemeLoadControls called before theme parent window created.");
886
}
887
886
- hr = LoadControls(pTheme, NULL, rgAssignControlIds, cAssignControlIds);
888
+ hr = LoadControls(pTheme, NULL);
889
890
LExit:
891
return hr;
@@ -1844,8 +1846,6 @@ static HRESULT ParseTheme(
1846
__out THEME** ppTheme
1847
)
1848
{
1847
- static WORD wThemeId = 0;
1848
-
1849
HRESULT hr = S_OK;
1850
THEME* pTheme = NULL;
1851
IXMLDOMElement *pThemeElement = NULL;
@@ -1858,8 +1858,8 @@ static HRESULT ParseTheme(
1858
pTheme = static_cast<THEME*>(MemAlloc(sizeof(THEME), TRUE));
1859
ThmExitOnNull(pTheme, hr, E_OUTOFMEMORY, "Failed to allocate memory for theme.");
1860
1861
- pTheme->wId = ++wThemeId;
1861
pTheme->nDpi = USER_DEFAULT_SCREEN_DPI;
1862
+ pTheme->wNextControlId = THEME_FIRST_AUTO_ASSIGN_CONTROL_ID;
1863
1864
// Parse the optional background resource image.
1865
hr = GetAttributeImageFileOrResource(hModule, wzRelativePath, pThemeElement, &pBitmap);
@@ -5248,7 +5248,7 @@ static BOOL OnButtonClicked(
5248
LExit:
5249
return fHandled;
5250
}
5251
-
5251
+
5252
static BOOL OnDpiChanged(
5253
__in THEME* pTheme,
5254
__in WPARAM wParam,
@@ -5934,11 +5934,38 @@ static LRESULT CALLBACK StaticOwnerDrawWndProc(
5934
}
5935
}
5936
5937
+static HRESULT OnLoadingControl(
5938
+ __in THEME* pTheme,
5939
+ __in const THEME_CONTROL* pControl,
5940
+ __inout WORD* pwId
5941
+ )
5942
+{
5943
+ HRESULT hr = S_OK;
5944
+ THEME_LOADINGCONTROL_ARGS loadingControlArgs = { };
5945
+ THEME_LOADINGCONTROL_RESULTS loadingControlResults = { };
5946
+
5947
+ loadingControlArgs.cbSize = sizeof(loadingControlArgs);
5948
+ loadingControlArgs.pThemeControl = pControl;
5949
+
5950
+ loadingControlResults.cbSize = sizeof(loadingControlResults);
5951
+ loadingControlResults.hr = E_NOTIMPL;
5952
+ loadingControlResults.wId = *pwId;
5953
+
5954
+ if (::SendMessageW(pTheme->hwndParent, WM_THMUTIL_LOADING_CONTROL, reinterpret_cast<WPARAM>(&loadingControlArgs), reinterpret_cast<LPARAM>(&loadingControlResults)))
5955
+ {
5956
+ hr = loadingControlResults.hr;
5957
+ if (SUCCEEDED(hr))
5958
+ {
5959
+ *pwId = loadingControlResults.wId;
5960
+ }
5961
+ }
5962
+
5963
+ return hr;
5964
+}
5965
+
5966
static HRESULT LoadControls(
5967
__in THEME* pTheme,
5939
- __in_opt THEME_CONTROL* pParentControl,
5940
- __in_ecount_opt(cAssignControlIds) const THEME_ASSIGN_CONTROL_ID* rgAssignControlIds,
5941
- __in DWORD cAssignControlIds
5968
+ __in_opt THEME_CONTROL* pParentControl
5969
)
5970
{
5971
HRESULT hr = S_OK;
@@ -6101,16 +6128,16 @@ static HRESULT LoadControls(
6128
}
6129
ThmExitOnNull(wzWindowClass, hr, E_INVALIDDATA, "Failed to configure control %u because of unknown type: %u", i, pControl->type);
6130
6104
- // Default control ids to the theme id and its index in the control array, unless there
6105
- // is a specific id to assign to a named control.
6106
- WORD wControlId = MAKEWORD(i, pTheme->wId);
6107
- for (DWORD iAssignControl = 0; pControl->sczName && iAssignControl < cAssignControlIds; ++iAssignControl)
6131
+ // Default control ids to the next id, unless there is a specific id to assign to a control.
6132
+ WORD wControlId = THEME_FIRST_AUTO_ASSIGN_CONTROL_ID;
6133
+ hr = OnLoadingControl(pTheme, pControl, &wControlId);
6134
+ ThmExitOnFailure(hr, "ThmLoadingControl failed.");
6135
+
6136
+ // This range is reserved for thmutil. The process will run out of available window handles before reaching the end of the range.
6137
+ if (THEME_FIRST_AUTO_ASSIGN_CONTROL_ID <= wControlId && THEME_FIRST_ASSIGN_CONTROL_ID > wControlId)
6138
{
6109
- if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, pControl->sczName, -1, rgAssignControlIds[iAssignControl].wzName, -1))
6110
- {
6111
- wControlId = rgAssignControlIds[iAssignControl].wId;
6112
- break;
6113
- }
6139
+ wControlId = pTheme->wNextControlId;
6140
+ pTheme->wNextControlId += 1;
6141
}
6142
6143
pControl->wId = wControlId;
@@ -6296,7 +6323,7 @@ static HRESULT LoadControls(
6323
6324
if (pControl->cControls)
6325
{
6299
- hr = LoadControls(pTheme, pControl, rgAssignControlIds, cAssignControlIds);
6326
+ hr = LoadControls(pTheme, pControl);
6327
ThmExitOnFailure(hr, "Failed to load child controls.");
6328
}
6329
}
src/samples/thmviewer/display.cpp
+1
-1
@@ -329,7 +329,7 @@ static BOOL DisplayOnCreate(
329
{
330
HRESULT hr = S_OK;
331
332
- hr = ThemeLoadControls(pTheme, NULL, 0);
332
+ hr = ThemeLoadControls(pTheme);
333
ExitOnFailure(hr, "Failed to load theme controls");
334
335
// Pre-populate some control types with data.
src/samples/thmviewer/thmviewer.cpp
+22
-5
@@ -14,10 +14,6 @@ enum THMVWR_CONTROL
14
THMVWR_CONTROL_TREE = THEME_FIRST_ASSIGN_CONTROL_ID,
15
};
16
17
-static THEME_ASSIGN_CONTROL_ID vrgInitControls[] = {
18
- { THMVWR_CONTROL_TREE, L"Tree" },
19
-};
20
-
17
// Internal functions
18
19
static HRESULT ProcessCommandLine(
@@ -52,6 +48,10 @@ static void OnNewTheme(
48
__in HWND hWnd,
49
__in HANDLE_THEME* pHandle
50
);
51
+static BOOL OnThemeLoadingControl(
52
+ __in const THEME_LOADINGCONTROL_ARGS* pArgs,
53
+ __in THEME_LOADINGCONTROL_RESULTS* pResults
54
+ );
55
static void CALLBACK ThmviewerTraceError(
56
__in_z LPCSTR szFile,
57
__in int iLine,
@@ -353,7 +353,7 @@ static LRESULT CALLBACK MainWndProc(
353
354
case WM_CREATE:
355
{
356
- HRESULT hr = ThemeLoadControls(vpTheme, vrgInitControls, countof(vrgInitControls));
356
+ HRESULT hr = ThemeLoadControls(vpTheme);
357
if (FAILED(hr))
358
{
359
return -1;
@@ -400,6 +400,9 @@ static LRESULT CALLBACK MainWndProc(
400
}
401
}
402
break;
403
+
404
+ case WM_THMUTIL_LOADING_CONTROL:
405
+ return OnThemeLoadingControl(reinterpret_cast<THEME_LOADINGCONTROL_ARGS*>(wParam), reinterpret_cast<THEME_LOADINGCONTROL_RESULTS*>(lParam));
406
}
407
408
return ThemeDefWindowProc(vpTheme, hWnd, uMsg, wParam, lParam);
@@ -541,3 +544,17 @@ static void OnNewTheme(
544
ThemeSendControlMessage(pTheme, THMVWR_CONTROL_TREE, TVM_SELECTITEM, TVGN_CARET, reinterpret_cast<LPARAM>(htiSelected));
545
}
546
}
547
+
548
+static BOOL OnThemeLoadingControl(
549
+ __in const THEME_LOADINGCONTROL_ARGS* pArgs,
550
+ __in THEME_LOADINGCONTROL_RESULTS* pResults
551
+ )
552
+{
553
+ if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, pArgs->pThemeControl->sczName, -1, L"Tree", -1))
554
+ {
555
+ pResults->wId = THMVWR_CONTROL_TREE;
556
+ }
557
+
558
+ pResults->hr = S_OK;
559
+ return TRUE;
560
+}
src/test/burn/TestData/Manual/BafThmutilTesting/BafThmUtilTesting.cpp
+51
-8
@@ -6,6 +6,11 @@
6
7
static const LPCWSTR BAFTHMUTILTESTING_WINDOW_CLASS = L"BafThmUtilTesting";
8
9
+enum BAF_CONTROL
10
+{
11
+ BAF_CONTROL_INSTALL_TEST_BUTTON = BAFUNCTIONS_FIRST_ASSIGN_CONTROL_ID,
12
+};
13
+
14
enum BAFTHMUTILTESTING_CONTROL
15
{
16
BAFTHMUTILTESTING_CONTROL_LISTVIEW_TOP_LEFT = THEME_FIRST_ASSIGN_CONTROL_ID,
@@ -59,24 +64,41 @@ public: // IBAFunctions
64
__inout LRESULT* plRes
65
)
66
{
62
- HRESULT hr = S_OK;
63
-
64
- __super::WndProc(pTheme, hWnd, uMsg, wParam, lParam, plRes);
65
-
66
- // Show our window when any button is clicked.
67
switch (uMsg)
68
{
69
case WM_COMMAND:
70
switch (HIWORD(wParam))
71
{
72
case BN_CLICKED:
73
- OnShowTheme();
73
+ switch (LOWORD(wParam))
74
+ {
75
+ case BAF_CONTROL_INSTALL_TEST_BUTTON:
76
+ OnShowTheme();
77
+ *plRes = 0;
78
+ return S_OK;
79
+ }
80
+
81
break;
82
}
83
break;
84
}
85
79
- return hr;
86
+ return __super::WndProc(pTheme, hWnd, uMsg, wParam, lParam, plRes);
87
+ }
88
+
89
+ virtual STDMETHODIMP OnThemeControlLoading(
90
+ __in LPCWSTR wzName,
91
+ __inout BOOL* pfProcessed,
92
+ __inout WORD* pwId
93
+ )
94
+ {
95
+ if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, wzName, -1, L"InstallTestButton", -1))
96
+ {
97
+ *pfProcessed = TRUE;
98
+ *pwId = BAF_CONTROL_INSTALL_TEST_BUTTON;
99
+ }
100
+
101
+ return S_OK;
102
}
103
104
private:
@@ -229,6 +251,9 @@ private:
251
}
252
break;
253
254
+ case WM_THMUTIL_LOADING_CONTROL:
255
+ return pBaf->OnThemeLoadingControl(reinterpret_cast<THEME_LOADINGCONTROL_ARGS*>(wParam), reinterpret_cast<THEME_LOADINGCONTROL_RESULTS*>(lParam));
256
+
257
case WM_TIMER:
258
if (!lParam && pBaf)
259
{
@@ -255,7 +280,7 @@ private:
280
HWND hwndBottomLeft = NULL;
281
HWND hwndBottomRight = NULL;
282
258
- hr = ThemeLoadControls(m_pBafTheme, vrgInitControls, countof(vrgInitControls));
283
+ hr = ThemeLoadControls(m_pBafTheme);
284
BalExitOnFailure(hr, "Failed to load theme controls.");
285
286
hwndTopLeft = ::GetDlgItem(m_pBafTheme->hwndParent, BAFTHMUTILTESTING_CONTROL_LISTVIEW_TOP_LEFT);
@@ -333,6 +358,24 @@ private:
358
return SUCCEEDED(hr);
359
}
360
361
+ BOOL OnThemeLoadingControl(
362
+ __in const THEME_LOADINGCONTROL_ARGS* pArgs,
363
+ __in THEME_LOADINGCONTROL_RESULTS* pResults
364
+ )
365
+ {
366
+ for (DWORD iAssignControl = 0; iAssignControl < countof(vrgInitControls); ++iAssignControl)
367
+ {
368
+ if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, pArgs->pThemeControl->sczName, -1, vrgInitControls[iAssignControl].wzName, -1))
369
+ {
370
+ pResults->wId = vrgInitControls[iAssignControl].wId;
371
+ break;
372
+ }
373
+ }
374
+
375
+ pResults->hr = S_OK;
376
+ return TRUE;
377
+ }
378
+
379
void UpdateProgressBarProgress()
380
{
381
static DWORD dwProgress = 0;
src/test/burn/TestData/Manual/BundleA/BundleA.wixproj
+1
-1
@@ -2,7 +2,7 @@
2
<Project Sdk="WixToolset.Sdk">
3
<PropertyGroup>
4
<OutputType>Bundle</OutputType>
5
- <BA>hyperlinkLicense</BA>
5
+ <BA>customHyperlinkLicense</BA>
6
<UpgradeCode>{98ACBCF6-B54A-46AF-8990-DFB8795B965B}</UpgradeCode>
7
</PropertyGroup>
8
<ItemGroup>
src/test/burn/TestData/Manual/BundleA/BundleA.wxs
+2
-1
@@ -3,7 +3,8 @@
3
4
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:bal="http://wixtoolset.org/schemas/v4/wxs/bal">
5
<Fragment>
6
- <BootstrapperApplication>
6
+ <BootstrapperApplication Id="customHyperlinkLicense">
7
+ <bal:WixStandardBootstrapperApplication LicenseUrl="" Theme="hyperlinkLicense" ThemeFile="CustomHyperlinkTheme.xml" />
8
<Payload SourceFile="$(var.BafThmUtilTesting.TargetPath)" bal:BAFunctions="yes" />
9
</BootstrapperApplication>
10
<PackageGroup Id="BundlePackages">
src/test/burn/TestData/Manual/BundleA/CustomHyperlinkTheme.xml
new
+107
@@ -0,0 +1,107 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
3
+
4
+
5
+<Theme xmlns="http://wixtoolset.org/schemas/v4/thmutil">
6
+ <Font Id="0" Height="-12" Weight="500" Foreground="windowtext" Background="window">Segoe UI</Font>
7
+ <Font Id="1" Height="-24" Weight="500" Foreground="windowtext">Segoe UI</Font>
8
+ <Font Id="2" Height="-22" Weight="500" Foreground="graytext">Segoe UI</Font>
9
+ <Font Id="3" Height="-12" Weight="500" Foreground="windowtext" Background="window">Segoe UI</Font>
10
+
11
+ <Window Width="485" Height="300" HexStyle="100a0000" FontId="0" Caption="#(loc.Caption)">
12
+ <ImageControl X="11" Y="11" Width="64" Height="64" ImageFile="logo.png" Visible="yes"/>
13
+ <Label X="80" Y="11" Width="-11" Height="64" FontId="1" Visible="yes" DisablePrefix="yes">#(loc.Title)</Label>
14
+
15
+ <Page Name="Help">
16
+ <Label X="11" Y="80" Width="-11" Height="30" FontId="2" DisablePrefix="yes">#(loc.HelpHeader)</Label>
17
+ <Label X="11" Y="112" Width="-11" Height="-35" FontId="3" DisablePrefix="yes">#(loc.HelpText)</Label>
18
+ <Button Name="HelpCloseButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
19
+ <Text>#(loc.HelpCloseButton)</Text>
20
+ <CloseWindowAction />
21
+ </Button>
22
+ </Page>
23
+ <Page Name="Install">
24
+ <Hypertext Name="EulaHyperlink" X="11" Y="121" Width="-11" Height="51" TabStop="yes" FontId="3" HideWhenDisabled="yes">#(loc.InstallLicenseLinkText)</Hypertext>
25
+ <Checkbox Name="EulaAcceptCheckbox" X="-11" Y="-41" Width="260" Height="17" TabStop="yes" FontId="3" HideWhenDisabled="yes">#(loc.InstallAcceptCheckbox)</Checkbox>
26
+ <Button Name="InstallTestButton" X="-251" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">Test</Button>
27
+ <Button Name="OptionsButton" X="-171" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" VisibleCondition="NOT WixStdBASuppressOptionsUI">
28
+ <Text>#(loc.InstallOptionsButton)</Text>
29
+ <ChangePageAction Page="Options" />
30
+ </Button>
31
+ <Button Name="InstallButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.InstallInstallButton)</Button>
32
+ <Button Name="InstallCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
33
+ <Text>#(loc.InstallCancelButton)</Text>
34
+ <CloseWindowAction />
35
+ </Button>
36
+ </Page>
37
+ <Page Name="Options">
38
+ <Label X="11" Y="80" Width="-11" Height="30" FontId="2" DisablePrefix="yes">#(loc.OptionsHeader)</Label>
39
+ <Label X="11" Y="121" Width="-11" Height="17" FontId="3" DisablePrefix="yes">#(loc.OptionsLocationLabel)</Label>
40
+ <Editbox Name="InstallFolder" X="11" Y="143" Width="-91" Height="21" TabStop="yes" FontId="3" FileSystemAutoComplete="yes" />
41
+ <Button Name="BrowseButton" X="-11" Y="142" Width="75" Height="23" TabStop="yes" FontId="3">
42
+ <Text>#(loc.OptionsBrowseButton)</Text>
43
+ <BrowseDirectoryAction VariableName="InstallFolder" />
44
+ </Button>
45
+ <Button Name="OptionsOkButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
46
+ <Text>#(loc.OptionsOkButton)</Text>
47
+ <ChangePageAction Page="Install" />
48
+ </Button>
49
+ <Button Name="OptionsCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
50
+ <Text>#(loc.OptionsCancelButton)</Text>
51
+ <ChangePageAction Page="Install" Cancel="yes" />
52
+ </Button>
53
+ </Page>
54
+ <Page Name="Progress">
55
+ <Label X="11" Y="80" Width="-11" Height="30" FontId="2" DisablePrefix="yes">#(loc.ProgressHeader)</Label>
56
+ <Label X="11" Y="121" Width="70" Height="17" FontId="3" DisablePrefix="yes">#(loc.ProgressLabel)</Label>
57
+ <Label Name="OverallProgressPackageText" X="85" Y="121" Width="-11" Height="17" FontId="3" DisablePrefix="yes">#(loc.OverallProgressPackageText)</Label>
58
+ <Progressbar Name="OverallCalculatedProgressbar" X="11" Y="143" Width="-11" Height="15" />
59
+ <Button Name="ProgressCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.ProgressCancelButton)</Button>
60
+ </Page>
61
+ <Page Name="Modify">
62
+ <Label X="11" Y="80" Width="-11" Height="30" FontId="2" DisablePrefix="yes">#(loc.ModifyHeader)</Label>
63
+ <Button Name="RepairButton" X="-171" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.ModifyRepairButton)</Button>
64
+ <Button Name="UninstallButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.ModifyUninstallButton)</Button>
65
+ <Button Name="ModifyCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
66
+ <Text>#(loc.ModifyCancelButton)</Text>
67
+ <CloseWindowAction />
68
+ </Button>
69
+ </Page>
70
+ <Page Name="Success">
71
+ <Label X="11" Y="80" Width="-11" Height="30" FontId="2" DisablePrefix="yes">
72
+ <Text>#(loc.SuccessHeader)</Text>
73
+ <Text Condition="WixBundleAction = 2">#(loc.SuccessLayoutHeader)</Text>
74
+ <Text Condition="WixBundleAction = 3">#(loc.SuccessUninstallHeader)</Text>
75
+ <Text Condition="WixBundleAction = 5">#(loc.SuccessInstallHeader)</Text>
76
+ <Text Condition="WixBundleAction = 7">#(loc.SuccessRepairHeader)</Text>
77
+ </Label>
78
+ <Button Name="LaunchButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.SuccessLaunchButton)</Button>
79
+ <Label X="-11" Y="-51" Width="400" Height="34" FontId="3" DisablePrefix="yes" VisibleCondition="WixStdBARestartRequired">
80
+ <Text>#(loc.SuccessRestartText)</Text>
81
+ <Text Condition="WixBundleAction = 3">#(loc.SuccessUninstallRestartText)</Text>
82
+ </Label>
83
+ <Button Name="SuccessRestartButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.SuccessRestartButton)</Button>
84
+ <Button Name="SuccessCloseButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
85
+ <Text>#(loc.SuccessCloseButton)</Text>
86
+ <CloseWindowAction />
87
+ </Button>
88
+ </Page>
89
+ <Page Name="Failure">
90
+ <Label X="11" Y="80" Width="-11" Height="30" FontId="2" DisablePrefix="yes">
91
+ <Text>#(loc.FailureHeader)</Text>
92
+ <Text Condition="WixBundleAction = 2">#(loc.FailureLayoutHeader)</Text>
93
+ <Text Condition="WixBundleAction = 3">#(loc.FailureUninstallHeader)</Text>
94
+ <Text Condition="WixBundleAction = 5">#(loc.FailureInstallHeader)</Text>
95
+ <Text Condition="WixBundleAction = 7">#(loc.FailureRepairHeader)</Text>
96
+ </Label>
97
+ <Hypertext Name="FailureLogFileLink" X="11" Y="121" Width="-11" Height="42" FontId="3" TabStop="yes" HideWhenDisabled="yes">#(loc.FailureHyperlinkLogText)</Hypertext>
98
+ <Hypertext Name="FailureMessageText" X="22" Y="163" Width="-11" Height="51" FontId="3" TabStop="yes" HideWhenDisabled="yes" />
99
+ <Label X="-11" Y="-51" Width="400" Height="34" FontId="3" DisablePrefix="yes" VisibleCondition="WixStdBARestartRequired">#(loc.FailureRestartText)</Label>
100
+ <Button Name="FailureRestartButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.FailureRestartButton)</Button>
101
+ <Button Name="FailureCloseButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">
102
+ <Text>#(loc.FailureCloseButton)</Text>
103
+ <CloseWindowAction />
104
+ </Button>
105
+ </Page>
106
+ </Window>
107
+</Theme>