aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSean Hall <r.sean.hall@gmail.com>2021-10-31 14:20:44 -0500
committerSean Hall <r.sean.hall@gmail.com>2021-11-01 16:34:09 -0500
commit7e60078d4a7fe748a39c135def9e84a2421ab474 (patch)
tree51dbe5067ca9596f99107719734c4946e4c080b4 /src
parentc092722a147940532b08f62403e182ef279f2c74 (diff)
downloadwix-7e60078d4a7fe748a39c135def9e84a2421ab474.tar.gz
wix-7e60078d4a7fe748a39c135def9e84a2421ab474.tar.bz2
wix-7e60078d4a7fe748a39c135def9e84a2421ab474.zip
Avoid using control ids inside of thmutil.
Diffstat (limited to 'src')
-rw-r--r--src/ext/Bal/wixstdba/WixStandardBootstrapperApplication.cpp314
-rw-r--r--src/ext/Bal/wixstdba/precomp.h1
-rw-r--r--src/libs/dutil/WixToolset.DUtil/dutil.vcxproj2
-rw-r--r--src/libs/dutil/WixToolset.DUtil/dutil.vcxproj.filters6
-rw-r--r--src/libs/dutil/WixToolset.DUtil/inc/dutilsources.h1
-rw-r--r--src/libs/dutil/WixToolset.DUtil/inc/thmutil.h117
-rw-r--r--src/libs/dutil/WixToolset.DUtil/inc/wndutil.h41
-rw-r--r--src/libs/dutil/WixToolset.DUtil/precomp.h1
-rw-r--r--src/libs/dutil/WixToolset.DUtil/thmutil.cpp650
-rw-r--r--src/libs/dutil/WixToolset.DUtil/wndutil.cpp206
-rw-r--r--src/samples/thmviewer/display.cpp8
-rw-r--r--src/samples/thmviewer/precomp.h1
-rw-r--r--src/samples/thmviewer/thmviewer.cpp37
-rw-r--r--src/test/burn/TestData/Manual/BafThmutilTesting/BafThmUtilTesting.cpp11
14 files changed, 845 insertions, 551 deletions
diff --git a/src/ext/Bal/wixstdba/WixStandardBootstrapperApplication.cpp b/src/ext/Bal/wixstdba/WixStandardBootstrapperApplication.cpp
index 23158a1c..d1b18cb3 100644
--- a/src/ext/Bal/wixstdba/WixStandardBootstrapperApplication.cpp
+++ b/src/ext/Bal/wixstdba/WixStandardBootstrapperApplication.cpp
@@ -80,7 +80,7 @@ static LPCWSTR vrgwzPageNames[] = {
80// The range [0, 100) is unused to avoid collisions with system ids, 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, 81// the range [100, 0x4000) is unused to avoid collisions with thmutil,
82// the range [0x4000, 0x8000) is unused to avoid collisions with BAFunctions. 82// the range [0x4000, 0x8000) is unused to avoid collisions with BAFunctions.
83const WORD WIXSTDBA_FIRST_ASSIGN_CONTROL_ID = 0x8000; 83const WORD WIXSTDBA_FIRST_ASSIGN_CONTROL_ID = 0x8000;
84 84
85enum WIXSTDBA_CONTROL 85enum WIXSTDBA_CONTROL
86{ 86{
@@ -119,36 +119,8 @@ enum WIXSTDBA_CONTROL
119 WIXSTDBA_CONTROL_FAILURE_LOGFILE_LINK, 119 WIXSTDBA_CONTROL_FAILURE_LOGFILE_LINK,
120 WIXSTDBA_CONTROL_FAILURE_MESSAGE_TEXT, 120 WIXSTDBA_CONTROL_FAILURE_MESSAGE_TEXT,
121 WIXSTDBA_CONTROL_FAILURE_RESTART_BUTTON, 121 WIXSTDBA_CONTROL_FAILURE_RESTART_BUTTON,
122};
123 122
124static THEME_ASSIGN_CONTROL_ID vrgInitControls[] = { 123 LAST_WIXSTDBA_CONTROL,
125 { WIXSTDBA_CONTROL_INSTALL_BUTTON, L"InstallButton" },
126 { WIXSTDBA_CONTROL_EULA_RICHEDIT, L"EulaRichedit" },
127 { WIXSTDBA_CONTROL_EULA_LINK, L"EulaHyperlink" },
128 { WIXSTDBA_CONTROL_EULA_ACCEPT_CHECKBOX, L"EulaAcceptCheckbox" },
129
130 { WIXSTDBA_CONTROL_REPAIR_BUTTON, L"RepairButton" },
131 { WIXSTDBA_CONTROL_UNINSTALL_BUTTON, L"UninstallButton" },
132
133 { WIXSTDBA_CONTROL_CACHE_PROGRESS_PACKAGE_TEXT, L"CacheProgressPackageText" },
134 { WIXSTDBA_CONTROL_CACHE_PROGRESS_BAR, L"CacheProgressbar" },
135 { WIXSTDBA_CONTROL_CACHE_PROGRESS_TEXT, L"CacheProgressText" },
136 { WIXSTDBA_CONTROL_EXECUTE_PROGRESS_PACKAGE_TEXT, L"ExecuteProgressPackageText" },
137 { WIXSTDBA_CONTROL_EXECUTE_PROGRESS_BAR, L"ExecuteProgressbar" },
138 { WIXSTDBA_CONTROL_EXECUTE_PROGRESS_TEXT, L"ExecuteProgressText" },
139 { WIXSTDBA_CONTROL_EXECUTE_PROGRESS_ACTIONDATA_TEXT, L"ExecuteProgressActionDataText"},
140 { WIXSTDBA_CONTROL_OVERALL_PROGRESS_PACKAGE_TEXT, L"OverallProgressPackageText" },
141 { WIXSTDBA_CONTROL_OVERALL_PROGRESS_BAR, L"OverallProgressbar" },
142 { WIXSTDBA_CONTROL_OVERALL_CALCULATED_PROGRESS_BAR, L"OverallCalculatedProgressbar" },
143 { WIXSTDBA_CONTROL_OVERALL_PROGRESS_TEXT, L"OverallProgressText" },
144 { WIXSTDBA_CONTROL_PROGRESS_CANCEL_BUTTON, L"ProgressCancelButton" },
145
146 { WIXSTDBA_CONTROL_LAUNCH_BUTTON, L"LaunchButton" },
147 { WIXSTDBA_CONTROL_SUCCESS_RESTART_BUTTON, L"SuccessRestartButton" },
148
149 { WIXSTDBA_CONTROL_FAILURE_LOGFILE_LINK, L"FailureLogFileLink" },
150 { WIXSTDBA_CONTROL_FAILURE_MESSAGE_TEXT, L"FailureMessageText" },
151 { WIXSTDBA_CONTROL_FAILURE_RESTART_BUTTON, L"FailureRestartButton" },
152}; 124};
153 125
154typedef struct _WIXSTDBA_PACKAGE_INFO 126typedef struct _WIXSTDBA_PACKAGE_INFO
@@ -589,7 +561,7 @@ public: // IBootstrapperApplication
589 561
590 wz = sczFormattedString ? sczFormattedString : L"Pausing Windows automatic updates"; 562 wz = sczFormattedString ? sczFormattedString : L"Pausing Windows automatic updates";
591 563
592 ThemeSetTextControl(m_pTheme, WIXSTDBA_CONTROL_OVERALL_PROGRESS_PACKAGE_TEXT, wz); 564 ThemeSetTextControl(m_pControlOverallProgressPackageText, wz);
593 565
594 ReleaseStr(sczFormattedString); 566 ReleaseStr(sczFormattedString);
595 return hr; 567 return hr;
@@ -615,7 +587,7 @@ public: // IBootstrapperApplication
615 587
616 wz = sczFormattedString ? sczFormattedString : L"Creating system restore point"; 588 wz = sczFormattedString ? sczFormattedString : L"Creating system restore point";
617 589
618 ThemeSetTextControl(m_pTheme, WIXSTDBA_CONTROL_OVERALL_PROGRESS_PACKAGE_TEXT, wz); 590 ThemeSetTextControl(m_pControlOverallProgressPackageText, wz);
619 591
620 ReleaseStr(sczFormattedString); 592 ReleaseStr(sczFormattedString);
621 return hr; 593 return hr;
@@ -635,12 +607,12 @@ public: // IBootstrapperApplication
635 HRESULT hr = BalInfoFindPackageById(&m_Bundle.packages, wzPackageId, &pPackage); 607 HRESULT hr = BalInfoFindPackageById(&m_Bundle.packages, wzPackageId, &pPackage);
636 LPCWSTR wz = (SUCCEEDED(hr) && pPackage->sczDisplayName) ? pPackage->sczDisplayName : wzPackageId; 608 LPCWSTR wz = (SUCCEEDED(hr) && pPackage->sczDisplayName) ? pPackage->sczDisplayName : wzPackageId;
637 609
638 ThemeSetTextControl(m_pTheme, WIXSTDBA_CONTROL_CACHE_PROGRESS_PACKAGE_TEXT, wz); 610 ThemeSetTextControl(m_pControlCacheProgressPackageText, wz);
639 611
640 // If something started executing, leave it in the overall progress text. 612 // If something started executing, leave it in the overall progress text.
641 if (!m_fStartedExecution) 613 if (!m_fStartedExecution)
642 { 614 {
643 ThemeSetTextControl(m_pTheme, WIXSTDBA_CONTROL_OVERALL_PROGRESS_PACKAGE_TEXT, wz); 615 ThemeSetTextControl(m_pControlOverallProgressPackageText, wz);
644 } 616 }
645 } 617 }
646 618
@@ -778,7 +750,7 @@ public: // IBootstrapperApplication
778 ) 750 )
779 { 751 {
780 UpdateCacheProgress(SUCCEEDED(hrStatus) ? 100 : 0); 752 UpdateCacheProgress(SUCCEEDED(hrStatus) ? 100 : 0);
781 ThemeSetTextControl(m_pTheme, WIXSTDBA_CONTROL_CACHE_PROGRESS_PACKAGE_TEXT, L""); 753 ThemeSetTextControl(m_pControlCacheProgressPackageText, L"");
782 SetState(WIXSTDBA_STATE_CACHED, S_OK); // we always return success here and let OnApplyComplete() deal with the error. 754 SetState(WIXSTDBA_STATE_CACHED, S_OK); // we always return success here and let OnApplyComplete() deal with the error.
783 return __super::OnCacheComplete(hrStatus); 755 return __super::OnCacheComplete(hrStatus);
784 } 756 }
@@ -891,7 +863,7 @@ public: // IBootstrapperApplication
891 863
892 if (INSTALLMESSAGE_ACTIONSTART == messageType) 864 if (INSTALLMESSAGE_ACTIONSTART == messageType)
893 { 865 {
894 ThemeSetTextControl(m_pTheme, WIXSTDBA_CONTROL_EXECUTE_PROGRESS_ACTIONDATA_TEXT, wzMessage); 866 ThemeSetTextControl(m_pControlExecuteProgressActionDataText, wzMessage);
895 } 867 }
896 868
897 return __super::OnExecuteMsiMessage(wzPackageId, messageType, dwUIHint, wzMessage, cData, rgwzData, nRecommendation, pResult); 869 return __super::OnExecuteMsiMessage(wzPackageId, messageType, dwUIHint, wzMessage, cData, rgwzData, nRecommendation, pResult);
@@ -911,9 +883,9 @@ public: // IBootstrapperApplication
911#endif 883#endif
912 884
913 ::StringCchPrintfW(wzProgress, countof(wzProgress), L"%u%%", dwOverallProgressPercentage); 885 ::StringCchPrintfW(wzProgress, countof(wzProgress), L"%u%%", dwOverallProgressPercentage);
914 ThemeSetTextControl(m_pTheme, WIXSTDBA_CONTROL_OVERALL_PROGRESS_TEXT, wzProgress); 886 ThemeSetTextControl(m_pControlOverallProgressText, wzProgress);
915 887
916 ThemeSetProgressControl(m_pTheme, WIXSTDBA_CONTROL_OVERALL_PROGRESS_BAR, dwOverallProgressPercentage); 888 ThemeSetProgressControl(m_pControlOverallProgressbar, dwOverallProgressPercentage);
917 SetTaskbarButtonProgress(dwOverallProgressPercentage); 889 SetTaskbarButtonProgress(dwOverallProgressPercentage);
918 890
919 return __super::OnProgress(dwProgressPercentage, dwOverallProgressPercentage, pfCancel); 891 return __super::OnProgress(dwProgressPercentage, dwOverallProgressPercentage, pfCancel);
@@ -972,8 +944,8 @@ public: // IBootstrapperApplication
972 944
973 fShowingInternalUiThisPackage = INSTALLUILEVEL_NONE != (INSTALLUILEVEL_NONE & uiLevel); 945 fShowingInternalUiThisPackage = INSTALLUILEVEL_NONE != (INSTALLUILEVEL_NONE & uiLevel);
974 946
975 ThemeSetTextControl(m_pTheme, WIXSTDBA_CONTROL_EXECUTE_PROGRESS_PACKAGE_TEXT, wz); 947 ThemeSetTextControl(m_pControlExecuteProgressPackageText, wz);
976 ThemeSetTextControl(m_pTheme, WIXSTDBA_CONTROL_OVERALL_PROGRESS_PACKAGE_TEXT, wz); 948 ThemeSetTextControl(m_pControlOverallProgressPackageText, wz);
977 } 949 }
978 950
979 ::EnterCriticalSection(&m_csShowingInternalUiThisPackage); 951 ::EnterCriticalSection(&m_csShowingInternalUiThisPackage);
@@ -1000,12 +972,12 @@ public: // IBootstrapperApplication
1000#endif 972#endif
1001 973
1002 ::StringCchPrintfW(wzProgress, countof(wzProgress), L"%u%%", dwOverallProgressPercentage); 974 ::StringCchPrintfW(wzProgress, countof(wzProgress), L"%u%%", dwOverallProgressPercentage);
1003 ThemeSetTextControl(m_pTheme, WIXSTDBA_CONTROL_EXECUTE_PROGRESS_TEXT, wzProgress); 975 ThemeSetTextControl(m_pControlExecuteProgressText, wzProgress);
1004 976
1005 ThemeSetProgressControl(m_pTheme, WIXSTDBA_CONTROL_EXECUTE_PROGRESS_BAR, dwOverallProgressPercentage); 977 ThemeSetProgressControl(m_pControlExecuteProgressbar, dwOverallProgressPercentage);
1006 978
1007 m_dwCalculatedExecuteProgress = dwOverallProgressPercentage * (100 - WIXSTDBA_ACQUIRE_PERCENTAGE) / 100; 979 m_dwCalculatedExecuteProgress = dwOverallProgressPercentage * (100 - WIXSTDBA_ACQUIRE_PERCENTAGE) / 100;
1008 ThemeSetProgressControl(m_pTheme, WIXSTDBA_CONTROL_OVERALL_CALCULATED_PROGRESS_BAR, m_dwCalculatedCacheProgress + m_dwCalculatedExecuteProgress); 980 ThemeSetProgressControl(m_pControlOverallCalculatedProgressbar, m_dwCalculatedCacheProgress + m_dwCalculatedExecuteProgress);
1009 981
1010 SetTaskbarButtonProgress(m_dwCalculatedCacheProgress + m_dwCalculatedExecuteProgress); 982 SetTaskbarButtonProgress(m_dwCalculatedCacheProgress + m_dwCalculatedExecuteProgress);
1011 983
@@ -1051,10 +1023,10 @@ public: // IBootstrapperApplication
1051 { 1023 {
1052 HRESULT hr = S_OK; 1024 HRESULT hr = S_OK;
1053 1025
1054 ThemeSetTextControl(m_pTheme, WIXSTDBA_CONTROL_EXECUTE_PROGRESS_PACKAGE_TEXT, L""); 1026 ThemeSetTextControl(m_pControlExecuteProgressPackageText, L"");
1055 ThemeSetTextControl(m_pTheme, WIXSTDBA_CONTROL_EXECUTE_PROGRESS_ACTIONDATA_TEXT, L""); 1027 ThemeSetTextControl(m_pControlExecuteProgressActionDataText, L"");
1056 ThemeSetTextControl(m_pTheme, WIXSTDBA_CONTROL_OVERALL_PROGRESS_PACKAGE_TEXT, L""); 1028 ThemeSetTextControl(m_pControlOverallProgressPackageText, L"");
1057 ThemeControlEnable(m_pTheme, WIXSTDBA_CONTROL_PROGRESS_CANCEL_BUTTON, FALSE); // no more cancel. 1029 ThemeControlEnable(m_pControlProgressCancelButton, FALSE); // no more cancel.
1058 m_fShowingInternalUiThisPackage = FALSE; 1030 m_fShowingInternalUiThisPackage = FALSE;
1059 1031
1060 SetState(WIXSTDBA_STATE_EXECUTED, S_OK); // we always return success here and let OnApplyComplete() deal with the error. 1032 SetState(WIXSTDBA_STATE_EXECUTED, S_OK); // we always return success here and let OnApplyComplete() deal with the error.
@@ -2933,12 +2905,27 @@ private:
2933 BA_FUNCTIONS_ONTHEMECONTROLLOADING_ARGS themeControlLoadingArgs = { }; 2905 BA_FUNCTIONS_ONTHEMECONTROLLOADING_ARGS themeControlLoadingArgs = { };
2934 BA_FUNCTIONS_ONTHEMECONTROLLOADING_RESULTS themeControlLoadingResults = { }; 2906 BA_FUNCTIONS_ONTHEMECONTROLLOADING_RESULTS themeControlLoadingResults = { };
2935 2907
2936 for (DWORD iAssignControl = 0; iAssignControl < countof(vrgInitControls); ++iAssignControl) 2908 for (DWORD iAssignControl = 0; iAssignControl < countof(m_rgInitControls); ++iAssignControl)
2937 { 2909 {
2938 if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, pArgs->pThemeControl->sczName, -1, vrgInitControls[iAssignControl].wzName, -1)) 2910 THEME_ASSIGN_CONTROL_ID* pAssignControl = m_rgInitControls + iAssignControl;
2911 if (CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, pArgs->pThemeControl->sczName, -1, pAssignControl->wzName, -1))
2939 { 2912 {
2913 if (!pAssignControl->ppControl)
2914 {
2915 BalExitWithRootFailure(hr, E_INVALIDSTATE, "Control '%ls' has no member variable", pAssignControl->wzName);
2916 }
2917
2918 if (*pAssignControl->ppControl)
2919 {
2920 BalLog(BOOTSTRAPPER_LOG_LEVEL_ERROR, "Duplicate control name: %ls", pAssignControl->wzName);
2921 }
2922 else
2923 {
2924 *pAssignControl->ppControl = pArgs->pThemeControl;
2925 }
2926
2940 fProcessed = TRUE; 2927 fProcessed = TRUE;
2941 pResults->wId = vrgInitControls[iAssignControl].wId; 2928 pResults->wId = pAssignControl->wId;
2942 ExitFunction(); 2929 ExitFunction();
2943 } 2930 }
2944 } 2931 }
@@ -3059,7 +3046,7 @@ private:
3059 hr = LocProbeForFile(sczLicenseDirectory, sczLicenseFilename, m_sczLanguage, &sczLicensePath); 3046 hr = LocProbeForFile(sczLicenseDirectory, sczLicenseFilename, m_sczLanguage, &sczLicensePath);
3060 ExitOnFailure(hr, "Failed to probe for localized license file."); 3047 ExitOnFailure(hr, "Failed to probe for localized license file.");
3061 3048
3062 hr = ThemeLoadRichEditFromFile(m_pTheme, pThemeControl->wId, sczLicensePath, m_hModule); 3049 hr = ThemeLoadRichEditFromFile(pThemeControl, sczLicensePath, m_hModule);
3063 ExitOnFailure(hr, "Failed to load license file into richedit control."); 3050 ExitOnFailure(hr, "Failed to load license file into richedit control.");
3064 3051
3065 LExit: 3052 LExit:
@@ -3178,7 +3165,7 @@ private:
3178 hr = m_pEngine->Apply(m_hWnd); 3165 hr = m_pEngine->Apply(m_hWnd);
3179 BalExitOnFailure(hr, "Failed to start applying packages."); 3166 BalExitOnFailure(hr, "Failed to start applying packages.");
3180 3167
3181 ThemeControlEnable(m_pTheme, WIXSTDBA_CONTROL_PROGRESS_CANCEL_BUTTON, TRUE); // ensure the cancel button is enabled before starting. 3168 ThemeControlEnable(m_pControlProgressCancelButton, TRUE); // ensure the cancel button is enabled before starting.
3182 3169
3183 LExit: 3170 LExit:
3184 if (FAILED(hr)) 3171 if (FAILED(hr))
@@ -3229,22 +3216,22 @@ private:
3229 { 3216 {
3230 BalGetNumericVariable(WIXBUNDLE_VARIABLE_ELEVATED, &llElevated); 3217 BalGetNumericVariable(WIXBUNDLE_VARIABLE_ELEVATED, &llElevated);
3231 } 3218 }
3232 ThemeControlElevates(m_pTheme, WIXSTDBA_CONTROL_INSTALL_BUTTON, (m_Bundle.fPerMachine && !llElevated)); 3219 ThemeControlElevates(m_pControlInstallButton, (m_Bundle.fPerMachine && !llElevated));
3233 3220
3234 // If the EULA control exists, show it only if a license URL is provided as well. 3221 // If the EULA control exists, show it only if a license URL is provided as well.
3235 if (ThemeControlExists(m_pTheme, WIXSTDBA_CONTROL_EULA_LINK)) 3222 if (m_pControlEulaHyperlink)
3236 { 3223 {
3237 BOOL fEulaLink = (m_sczLicenseUrl && *m_sczLicenseUrl); 3224 BOOL fEulaLink = (m_sczLicenseUrl && *m_sczLicenseUrl);
3238 ThemeControlEnable(m_pTheme, WIXSTDBA_CONTROL_EULA_LINK, fEulaLink); 3225 ThemeControlEnable(m_pControlEulaHyperlink, fEulaLink);
3239 ThemeControlEnable(m_pTheme, WIXSTDBA_CONTROL_EULA_ACCEPT_CHECKBOX, fEulaLink); 3226 ThemeControlEnable(m_pControlEulaAcceptCheckbox, fEulaLink);
3240 } 3227 }
3241 3228
3242 BOOL fAcceptedLicense = !ThemeControlExists(m_pTheme, WIXSTDBA_CONTROL_EULA_ACCEPT_CHECKBOX) || !ThemeControlEnabled(m_pTheme, WIXSTDBA_CONTROL_EULA_ACCEPT_CHECKBOX) || ThemeIsControlChecked(m_pTheme, WIXSTDBA_CONTROL_EULA_ACCEPT_CHECKBOX); 3229 BOOL fAcceptedLicense = !m_pControlEulaAcceptCheckbox || !ThemeControlEnabled(m_pControlEulaAcceptCheckbox) || ThemeIsControlChecked(m_pControlEulaAcceptCheckbox);
3243 ThemeControlEnable(m_pTheme, WIXSTDBA_CONTROL_INSTALL_BUTTON, fAcceptedLicense); 3230 ThemeControlEnable(m_pControlInstallButton, fAcceptedLicense);
3244 } 3231 }
3245 else if (m_rgdwPageIds[WIXSTDBA_PAGE_MODIFY] == dwNewPageId) 3232 else if (m_rgdwPageIds[WIXSTDBA_PAGE_MODIFY] == dwNewPageId)
3246 { 3233 {
3247 ThemeControlEnable(m_pTheme, WIXSTDBA_CONTROL_REPAIR_BUTTON, !m_fSuppressRepair); 3234 ThemeControlEnable(m_pControlRepairButton, !m_fSuppressRepair);
3248 } 3235 }
3249 else if (m_rgdwPageIds[WIXSTDBA_PAGE_SUCCESS] == dwNewPageId) // on the "Success" page, check if the restart or launch button should be enabled. 3236 else if (m_rgdwPageIds[WIXSTDBA_PAGE_SUCCESS] == dwNewPageId) // on the "Success" page, check if the restart or launch button should be enabled.
3250 { 3237 {
@@ -3257,13 +3244,13 @@ private:
3257 fEnableRestartButton = TRUE; 3244 fEnableRestartButton = TRUE;
3258 } 3245 }
3259 } 3246 }
3260 else if (ThemeControlExists(m_pTheme, WIXSTDBA_CONTROL_LAUNCH_BUTTON)) 3247 else if (m_pControlLaunchButton)
3261 { 3248 {
3262 fLaunchTargetExists = BalVariableExists(WIXSTDBA_VARIABLE_LAUNCH_TARGET_PATH); 3249 fLaunchTargetExists = BalVariableExists(WIXSTDBA_VARIABLE_LAUNCH_TARGET_PATH);
3263 } 3250 }
3264 3251
3265 ThemeControlEnable(m_pTheme, WIXSTDBA_CONTROL_LAUNCH_BUTTON, fLaunchTargetExists && BOOTSTRAPPER_ACTION_UNINSTALL < m_plannedAction); 3252 ThemeControlEnable(m_pControlLaunchButton, fLaunchTargetExists && BOOTSTRAPPER_ACTION_UNINSTALL < m_plannedAction);
3266 ThemeControlEnable(m_pTheme, WIXSTDBA_CONTROL_SUCCESS_RESTART_BUTTON, fEnableRestartButton); 3253 ThemeControlEnable(m_pControlSuccessRestartButton, fEnableRestartButton);
3267 } 3254 }
3268 else if (m_rgdwPageIds[WIXSTDBA_PAGE_FAILURE] == dwNewPageId) // on the "Failure" page, show error message and check if the restart button should be enabled. 3255 else if (m_rgdwPageIds[WIXSTDBA_PAGE_FAILURE] == dwNewPageId) // on the "Failure" page, show error message and check if the restart button should be enabled.
3269 { 3256 {
@@ -3347,7 +3334,7 @@ private:
3347 StrAllocFormatted(&sczText, L"0x%08x - %ls", m_hrFinal, sczUnformattedText); 3334 StrAllocFormatted(&sczText, L"0x%08x - %ls", m_hrFinal, sczUnformattedText);
3348 } 3335 }
3349 3336
3350 ThemeSetTextControl(m_pTheme, WIXSTDBA_CONTROL_FAILURE_MESSAGE_TEXT, sczText); 3337 ThemeSetTextControl(m_pControlFailureMessageText, sczText);
3351 fShowErrorMessage = TRUE; 3338 fShowErrorMessage = TRUE;
3352 } 3339 }
3353 3340
@@ -3359,9 +3346,9 @@ private:
3359 } 3346 }
3360 } 3347 }
3361 3348
3362 ThemeControlEnable(m_pTheme, WIXSTDBA_CONTROL_FAILURE_LOGFILE_LINK, fShowLogLink); 3349 ThemeControlEnable(m_pControlFailureLogFileLink, fShowLogLink);
3363 ThemeControlEnable(m_pTheme, WIXSTDBA_CONTROL_FAILURE_MESSAGE_TEXT, fShowErrorMessage); 3350 ThemeControlEnable(m_pControlFailureMessageText, fShowErrorMessage);
3364 ThemeControlEnable(m_pTheme, WIXSTDBA_CONTROL_FAILURE_RESTART_BUTTON, fEnableRestartButton); 3351 ThemeControlEnable(m_pControlFailureRestartButton, fEnableRestartButton);
3365 } 3352 }
3366 3353
3367 HRESULT hr = ThemeShowPage(m_pTheme, dwOldPageId, SW_HIDE); 3354 HRESULT hr = ThemeShowPage(m_pTheme, dwOldPageId, SW_HIDE);
@@ -3379,7 +3366,7 @@ private:
3379 // On the install page set the focus to the install button or the next enabled control if install is disabled. 3366 // On the install page set the focus to the install button or the next enabled control if install is disabled.
3380 if (m_rgdwPageIds[WIXSTDBA_PAGE_INSTALL] == dwNewPageId) 3367 if (m_rgdwPageIds[WIXSTDBA_PAGE_INSTALL] == dwNewPageId)
3381 { 3368 {
3382 ThemeSetFocus(m_pTheme, WIXSTDBA_CONTROL_INSTALL_BUTTON); 3369 ThemeSetFocus(m_pControlInstallButton);
3383 } 3370 }
3384 } 3371 }
3385 } 3372 }
@@ -3423,7 +3410,7 @@ private:
3423 // If we canceled, disable cancel button since clicking it again is silly. 3410 // If we canceled, disable cancel button since clicking it again is silly.
3424 if (fClose) 3411 if (fClose)
3425 { 3412 {
3426 ThemeControlEnable(m_pTheme, WIXSTDBA_CONTROL_PROGRESS_CANCEL_BUTTON, FALSE); 3413 ThemeControlEnable(m_pControlProgressCancelButton, FALSE);
3427 } 3414 }
3428 3415
3429 fClose = FALSE; 3416 fClose = FALSE;
@@ -3447,8 +3434,8 @@ private:
3447 // 3434 //
3448 void OnClickAcceptCheckbox() 3435 void OnClickAcceptCheckbox()
3449 { 3436 {
3450 BOOL fAcceptedLicense = ThemeIsControlChecked(m_pTheme, WIXSTDBA_CONTROL_EULA_ACCEPT_CHECKBOX); 3437 BOOL fAcceptedLicense = ThemeIsControlChecked(m_pControlEulaAcceptCheckbox);
3451 ThemeControlEnable(m_pTheme, WIXSTDBA_CONTROL_INSTALL_BUTTON, fAcceptedLicense); 3438 ThemeControlEnable(m_pControlInstallButton, fAcceptedLicense);
3452 } 3439 }
3453 3440
3454 3441
@@ -3954,12 +3941,12 @@ LExit:
3954 WCHAR wzProgress[5] = { }; 3941 WCHAR wzProgress[5] = { };
3955 3942
3956 ::StringCchPrintfW(wzProgress, countof(wzProgress), L"%u%%", dwOverallPercentage); 3943 ::StringCchPrintfW(wzProgress, countof(wzProgress), L"%u%%", dwOverallPercentage);
3957 ThemeSetTextControl(m_pTheme, WIXSTDBA_CONTROL_CACHE_PROGRESS_TEXT, wzProgress); 3944 ThemeSetTextControl(m_pControlCacheProgressText, wzProgress);
3958 3945
3959 ThemeSetProgressControl(m_pTheme, WIXSTDBA_CONTROL_CACHE_PROGRESS_BAR, dwOverallPercentage); 3946 ThemeSetProgressControl(m_pControlCacheProgressbar, dwOverallPercentage);
3960 3947
3961 m_dwCalculatedCacheProgress = dwOverallPercentage * WIXSTDBA_ACQUIRE_PERCENTAGE / 100; 3948 m_dwCalculatedCacheProgress = dwOverallPercentage * WIXSTDBA_ACQUIRE_PERCENTAGE / 100;
3962 ThemeSetProgressControl(m_pTheme, WIXSTDBA_CONTROL_OVERALL_CALCULATED_PROGRESS_BAR, m_dwCalculatedCacheProgress + m_dwCalculatedExecuteProgress); 3949 ThemeSetProgressControl(m_pControlOverallCalculatedProgressbar, m_dwCalculatedCacheProgress + m_dwCalculatedExecuteProgress);
3963 3950
3964 SetTaskbarButtonProgress(m_dwCalculatedCacheProgress + m_dwCalculatedExecuteProgress); 3951 SetTaskbarButtonProgress(m_dwCalculatedCacheProgress + m_dwCalculatedExecuteProgress);
3965 } 3952 }
@@ -4088,6 +4075,8 @@ public:
4088 __in IBootstrapperEngine* pEngine 4075 __in IBootstrapperEngine* pEngine
4089 ) : CBalBaseBootstrapperApplication(pEngine, 3, 3000) 4076 ) : CBalBaseBootstrapperApplication(pEngine, 3, 3000)
4090 { 4077 {
4078 THEME_ASSIGN_CONTROL_ID* pAssignControl = NULL;
4079
4091 m_hModule = hModule; 4080 m_hModule = hModule;
4092 m_command = { }; 4081 m_command = { };
4093 m_createArgs = { }; 4082 m_createArgs = { };
@@ -4141,6 +4130,148 @@ public:
4141 m_hBAFModule = NULL; 4130 m_hBAFModule = NULL;
4142 m_pfnBAFunctionsProc = NULL; 4131 m_pfnBAFunctionsProc = NULL;
4143 m_pvBAFunctionsProcContext = NULL; 4132 m_pvBAFunctionsProcContext = NULL;
4133
4134 C_ASSERT(0 == WIXSTDBA_CONTROL_INSTALL_BUTTON - WIXSTDBA_FIRST_ASSIGN_CONTROL_ID);
4135 pAssignControl = m_rgInitControls;
4136
4137 pAssignControl->wId = WIXSTDBA_CONTROL_INSTALL_BUTTON;
4138 pAssignControl->wzName = L"InstallButton";
4139 pAssignControl->ppControl = &m_pControlInstallButton;
4140 m_pControlInstallButton = NULL;
4141 ++pAssignControl;
4142
4143 pAssignControl->wId = WIXSTDBA_CONTROL_EULA_RICHEDIT;
4144 pAssignControl->wzName = L"EulaRichedit";
4145 pAssignControl->ppControl = &m_pControlEulaRichedit;
4146 m_pControlEulaRichedit = NULL;
4147 ++pAssignControl;
4148
4149 pAssignControl->wId = WIXSTDBA_CONTROL_EULA_LINK;
4150 pAssignControl->wzName = L"EulaHyperlink";
4151 pAssignControl->ppControl = &m_pControlEulaHyperlink;
4152 m_pControlEulaHyperlink = NULL;
4153 ++pAssignControl;
4154
4155 pAssignControl->wId = WIXSTDBA_CONTROL_EULA_ACCEPT_CHECKBOX;
4156 pAssignControl->wzName = L"EulaAcceptCheckbox";
4157 pAssignControl->ppControl = &m_pControlEulaAcceptCheckbox;
4158 m_pControlEulaAcceptCheckbox = NULL;
4159 ++pAssignControl;
4160
4161 pAssignControl->wId = WIXSTDBA_CONTROL_REPAIR_BUTTON;
4162 pAssignControl->wzName = L"RepairButton";
4163 pAssignControl->ppControl = &m_pControlRepairButton;
4164 m_pControlRepairButton = NULL;
4165 ++pAssignControl;
4166
4167 pAssignControl->wId = WIXSTDBA_CONTROL_UNINSTALL_BUTTON;
4168 pAssignControl->wzName = L"UninstallButton";
4169 pAssignControl->ppControl = &m_pControlUninstallButton;
4170 m_pControlUninstallButton = NULL;
4171 ++pAssignControl;
4172
4173 pAssignControl->wId = WIXSTDBA_CONTROL_CACHE_PROGRESS_PACKAGE_TEXT;
4174 pAssignControl->wzName = L"CacheProgressPackageText";
4175 pAssignControl->ppControl = &m_pControlCacheProgressPackageText;
4176 m_pControlCacheProgressPackageText = NULL;
4177 ++pAssignControl;
4178
4179 pAssignControl->wId = WIXSTDBA_CONTROL_CACHE_PROGRESS_BAR;
4180 pAssignControl->wzName = L"CacheProgressbar";
4181 pAssignControl->ppControl = &m_pControlCacheProgressbar;
4182 m_pControlCacheProgressbar = NULL;
4183 ++pAssignControl;
4184
4185 pAssignControl->wId = WIXSTDBA_CONTROL_CACHE_PROGRESS_TEXT;
4186 pAssignControl->wzName = L"CacheProgressText";
4187 pAssignControl->ppControl = &m_pControlCacheProgressText;
4188 m_pControlCacheProgressText = NULL;
4189 ++pAssignControl;
4190
4191 pAssignControl->wId = WIXSTDBA_CONTROL_EXECUTE_PROGRESS_PACKAGE_TEXT;
4192 pAssignControl->wzName = L"ExecuteProgressPackageText";
4193 pAssignControl->ppControl = &m_pControlExecuteProgressPackageText;
4194 m_pControlExecuteProgressPackageText = NULL;
4195 ++pAssignControl;
4196
4197 pAssignControl->wId = WIXSTDBA_CONTROL_EXECUTE_PROGRESS_BAR;
4198 pAssignControl->wzName = L"ExecuteProgressbar";
4199 pAssignControl->ppControl = &m_pControlExecuteProgressbar;
4200 m_pControlExecuteProgressbar = NULL;
4201 ++pAssignControl;
4202
4203 pAssignControl->wId = WIXSTDBA_CONTROL_EXECUTE_PROGRESS_TEXT;
4204 pAssignControl->wzName = L"ExecuteProgressText";
4205 pAssignControl->ppControl = &m_pControlExecuteProgressText;
4206 m_pControlExecuteProgressText = NULL;
4207 ++pAssignControl;
4208
4209 pAssignControl->wId = WIXSTDBA_CONTROL_EXECUTE_PROGRESS_ACTIONDATA_TEXT;
4210 pAssignControl->wzName = L"ExecuteProgressActionDataText";
4211 pAssignControl->ppControl = &m_pControlExecuteProgressActionDataText;
4212 m_pControlExecuteProgressActionDataText = NULL;
4213 ++pAssignControl;
4214
4215 pAssignControl->wId = WIXSTDBA_CONTROL_OVERALL_PROGRESS_PACKAGE_TEXT;
4216 pAssignControl->wzName = L"OverallProgressPackageText";
4217 pAssignControl->ppControl = &m_pControlOverallProgressPackageText;
4218 m_pControlOverallProgressPackageText = NULL;
4219 ++pAssignControl;
4220
4221 pAssignControl->wId = WIXSTDBA_CONTROL_OVERALL_PROGRESS_BAR;
4222 pAssignControl->wzName = L"OverallProgressbar";
4223 pAssignControl->ppControl = &m_pControlOverallProgressbar;
4224 m_pControlOverallProgressbar = NULL;
4225 ++pAssignControl;
4226
4227 pAssignControl->wId = WIXSTDBA_CONTROL_OVERALL_CALCULATED_PROGRESS_BAR;
4228 pAssignControl->wzName = L"OverallCalculatedProgressbar";
4229 pAssignControl->ppControl = &m_pControlOverallCalculatedProgressbar;
4230 m_pControlOverallCalculatedProgressbar = NULL;
4231 ++pAssignControl;
4232
4233 pAssignControl->wId = WIXSTDBA_CONTROL_OVERALL_PROGRESS_TEXT;
4234 pAssignControl->wzName = L"OverallProgressText";
4235 pAssignControl->ppControl = &m_pControlOverallProgressText;
4236 m_pControlOverallProgressText = NULL;
4237 ++pAssignControl;
4238
4239 pAssignControl->wId = WIXSTDBA_CONTROL_PROGRESS_CANCEL_BUTTON;
4240 pAssignControl->wzName = L"ProgressCancelButton";
4241 pAssignControl->ppControl = &m_pControlProgressCancelButton;
4242 m_pControlProgressCancelButton = NULL;
4243 ++pAssignControl;
4244
4245 pAssignControl->wId = WIXSTDBA_CONTROL_LAUNCH_BUTTON;
4246 pAssignControl->wzName = L"LaunchButton";
4247 pAssignControl->ppControl = &m_pControlLaunchButton;
4248 m_pControlLaunchButton = NULL;
4249 ++pAssignControl;
4250
4251 pAssignControl->wId = WIXSTDBA_CONTROL_SUCCESS_RESTART_BUTTON;
4252 pAssignControl->wzName = L"SuccessRestartButton";
4253 pAssignControl->ppControl = &m_pControlSuccessRestartButton;
4254 m_pControlSuccessRestartButton = NULL;
4255 ++pAssignControl;
4256
4257 pAssignControl->wId = WIXSTDBA_CONTROL_FAILURE_LOGFILE_LINK;
4258 pAssignControl->wzName = L"FailureLogFileLink";
4259 pAssignControl->ppControl = &m_pControlFailureLogFileLink;
4260 m_pControlFailureLogFileLink = NULL;
4261 ++pAssignControl;
4262
4263 pAssignControl->wId = WIXSTDBA_CONTROL_FAILURE_MESSAGE_TEXT;
4264 pAssignControl->wzName = L"FailureMessageText";
4265 pAssignControl->ppControl = &m_pControlFailureMessageText;
4266 m_pControlFailureMessageText = NULL;
4267 ++pAssignControl;
4268
4269 pAssignControl->wId = WIXSTDBA_CONTROL_FAILURE_RESTART_BUTTON;
4270 pAssignControl->wzName = L"FailureRestartButton";
4271 pAssignControl->ppControl = &m_pControlFailureRestartButton;
4272 m_pControlFailureRestartButton = NULL;
4273
4274 C_ASSERT(LAST_WIXSTDBA_CONTROL == WIXSTDBA_CONTROL_FAILURE_RESTART_BUTTON + 1);
4144 } 4275 }
4145 4276
4146 4277
@@ -4201,11 +4332,48 @@ private:
4201 4332
4202 LPWSTR m_sczLanguage; 4333 LPWSTR m_sczLanguage;
4203 THEME* m_pTheme; 4334 THEME* m_pTheme;
4335 THEME_ASSIGN_CONTROL_ID m_rgInitControls[LAST_WIXSTDBA_CONTROL - WIXSTDBA_FIRST_ASSIGN_CONTROL_ID];
4204 DWORD m_rgdwPageIds[countof(vrgwzPageNames)]; 4336 DWORD m_rgdwPageIds[countof(vrgwzPageNames)];
4205 HANDLE m_hUiThread; 4337 HANDLE m_hUiThread;
4206 BOOL m_fRegistered; 4338 BOOL m_fRegistered;
4207 HWND m_hWnd; 4339 HWND m_hWnd;
4208 4340
4341 // Welcome page
4342 const THEME_CONTROL* m_pControlInstallButton;
4343 const THEME_CONTROL* m_pControlEulaRichedit;
4344 const THEME_CONTROL* m_pControlEulaHyperlink;
4345 const THEME_CONTROL* m_pControlEulaAcceptCheckbox;
4346
4347 // Modify page
4348 const THEME_CONTROL* m_pControlRepairButton;
4349 const THEME_CONTROL* m_pControlUninstallButton;
4350
4351 // Progress page
4352 const THEME_CONTROL* m_pControlCacheProgressPackageText;
4353 const THEME_CONTROL* m_pControlCacheProgressbar;
4354 const THEME_CONTROL* m_pControlCacheProgressText;
4355
4356 const THEME_CONTROL* m_pControlExecuteProgressPackageText;
4357 const THEME_CONTROL* m_pControlExecuteProgressbar;
4358 const THEME_CONTROL* m_pControlExecuteProgressText;
4359 const THEME_CONTROL* m_pControlExecuteProgressActionDataText;
4360
4361 const THEME_CONTROL* m_pControlOverallProgressPackageText;
4362 const THEME_CONTROL* m_pControlOverallProgressbar;
4363 const THEME_CONTROL* m_pControlOverallCalculatedProgressbar;
4364 const THEME_CONTROL* m_pControlOverallProgressText;
4365
4366 const THEME_CONTROL* m_pControlProgressCancelButton;
4367
4368 // Success page
4369 const THEME_CONTROL* m_pControlLaunchButton;
4370 const THEME_CONTROL* m_pControlSuccessRestartButton;
4371
4372 // Failure page
4373 const THEME_CONTROL* m_pControlFailureLogFileLink;
4374 const THEME_CONTROL* m_pControlFailureMessageText;
4375 const THEME_CONTROL* m_pControlFailureRestartButton;
4376
4209 WIXSTDBA_STATE m_state; 4377 WIXSTDBA_STATE m_state;
4210 HRESULT m_hrFinal; 4378 HRESULT m_hrFinal;
4211 4379
diff --git a/src/ext/Bal/wixstdba/precomp.h b/src/ext/Bal/wixstdba/precomp.h
index 547183bd..ba56ae6d 100644
--- a/src/ext/Bal/wixstdba/precomp.h
+++ b/src/ext/Bal/wixstdba/precomp.h
@@ -29,6 +29,7 @@
29#include "resrutil.h" 29#include "resrutil.h"
30#include "shelutil.h" 30#include "shelutil.h"
31#include "strutil.h" 31#include "strutil.h"
32#include "wndutil.h"
32#include "thmutil.h" 33#include "thmutil.h"
33#include "verutil.h" 34#include "verutil.h"
34#include "uriutil.h" 35#include "uriutil.h"
diff --git a/src/libs/dutil/WixToolset.DUtil/dutil.vcxproj b/src/libs/dutil/WixToolset.DUtil/dutil.vcxproj
index a02e638a..3ab8285f 100644
--- a/src/libs/dutil/WixToolset.DUtil/dutil.vcxproj
+++ b/src/libs/dutil/WixToolset.DUtil/dutil.vcxproj
@@ -107,6 +107,7 @@
107 <ClCompile Include="userutil.cpp" /> 107 <ClCompile Include="userutil.cpp" />
108 <ClCompile Include="verutil.cpp" /> 108 <ClCompile Include="verutil.cpp" />
109 <ClCompile Include="wiutil.cpp" /> 109 <ClCompile Include="wiutil.cpp" />
110 <ClCompile Include="wndutil.cpp" />
110 <ClCompile Include="wuautil.cpp" /> 111 <ClCompile Include="wuautil.cpp" />
111 <ClCompile Include="xmlutil.cpp" /> 112 <ClCompile Include="xmlutil.cpp" />
112 </ItemGroup> 113 </ItemGroup>
@@ -164,6 +165,7 @@
164 <ClInclude Include="inc\userutil.h" /> 165 <ClInclude Include="inc\userutil.h" />
165 <ClInclude Include="inc\verutil.h" /> 166 <ClInclude Include="inc\verutil.h" />
166 <ClInclude Include="inc\wiutil.h" /> 167 <ClInclude Include="inc\wiutil.h" />
168 <ClInclude Include="inc\wndutil.h" />
167 <ClInclude Include="inc\wuautil.h" /> 169 <ClInclude Include="inc\wuautil.h" />
168 <ClInclude Include="inc\xmlutil.h" /> 170 <ClInclude Include="inc\xmlutil.h" />
169 <ClInclude Include="precomp.h" /> 171 <ClInclude Include="precomp.h" />
diff --git a/src/libs/dutil/WixToolset.DUtil/dutil.vcxproj.filters b/src/libs/dutil/WixToolset.DUtil/dutil.vcxproj.filters
index b93d166b..6444b19c 100644
--- a/src/libs/dutil/WixToolset.DUtil/dutil.vcxproj.filters
+++ b/src/libs/dutil/WixToolset.DUtil/dutil.vcxproj.filters
@@ -165,6 +165,9 @@
165 <ClCompile Include="wiutil.cpp"> 165 <ClCompile Include="wiutil.cpp">
166 <Filter>Source Files</Filter> 166 <Filter>Source Files</Filter>
167 </ClCompile> 167 </ClCompile>
168 <ClCompile Include="wndutil.cpp">
169 <Filter>Source Files</Filter>
170 </ClCompile>
168 <ClCompile Include="xmlutil.cpp"> 171 <ClCompile Include="xmlutil.cpp">
169 <Filter>Source Files</Filter> 172 <Filter>Source Files</Filter>
170 </ClCompile> 173 </ClCompile>
@@ -338,6 +341,9 @@
338 <ClInclude Include="inc\wiutil.h"> 341 <ClInclude Include="inc\wiutil.h">
339 <Filter>Header Files</Filter> 342 <Filter>Header Files</Filter>
340 </ClInclude> 343 </ClInclude>
344 <ClInclude Include="inc\wndutil.h">
345 <Filter>Header Files</Filter>
346 </ClInclude>
341 <ClInclude Include="inc\xmlutil.h"> 347 <ClInclude Include="inc\xmlutil.h">
342 <Filter>Header Files</Filter> 348 <Filter>Header Files</Filter>
343 </ClInclude> 349 </ClInclude>
diff --git a/src/libs/dutil/WixToolset.DUtil/inc/dutilsources.h b/src/libs/dutil/WixToolset.DUtil/inc/dutilsources.h
index 7d512cb3..6affb392 100644
--- a/src/libs/dutil/WixToolset.DUtil/inc/dutilsources.h
+++ b/src/libs/dutil/WixToolset.DUtil/inc/dutilsources.h
@@ -61,6 +61,7 @@ typedef enum DUTIL_SOURCE
61 DUTIL_SOURCE_WUAUTIL, 61 DUTIL_SOURCE_WUAUTIL,
62 DUTIL_SOURCE_XMLUTIL, 62 DUTIL_SOURCE_XMLUTIL,
63 DUTIL_SOURCE_VERUTIL, 63 DUTIL_SOURCE_VERUTIL,
64 DUTIL_SOURCE_WNDUTIL,
64 65
65 DUTIL_SOURCE_EXTERNAL = 256, 66 DUTIL_SOURCE_EXTERNAL = 256,
66} DUTIL_SOURCE; 67} DUTIL_SOURCE;
diff --git a/src/libs/dutil/WixToolset.DUtil/inc/thmutil.h b/src/libs/dutil/WixToolset.DUtil/inc/thmutil.h
index cd286854..2f0bfeac 100644
--- a/src/libs/dutil/WixToolset.DUtil/inc/thmutil.h
+++ b/src/libs/dutil/WixToolset.DUtil/inc/thmutil.h
@@ -8,6 +8,7 @@ extern "C" {
8 8
9// forward declare 9// forward declare
10 10
11typedef struct _THEME_CONTROL THEME_CONTROL;
11typedef struct _THEME THEME; 12typedef struct _THEME THEME;
12 13
13#define ReleaseTheme(p) if (p) { ThemeFree(p); p = NULL; } 14#define ReleaseTheme(p) if (p) { ThemeFree(p); p = NULL; }
@@ -194,11 +195,12 @@ struct THEME_ASSIGN_CONTROL_ID
194{ 195{
195 WORD wId; // id to apply to control 196 WORD wId; // id to apply to control
196 LPCWSTR wzName; // name of control to match 197 LPCWSTR wzName; // name of control to match
198 const THEME_CONTROL** ppControl;
197}; 199};
198 200
199const WORD THEME_FIRST_ASSIGN_CONTROL_ID = 0x4000; // Recommended first control id to be assigned. 201const WORD THEME_FIRST_ASSIGN_CONTROL_ID = 0x4000; // Recommended first control id to be assigned.
200 202
201struct THEME_CONTROL 203typedef struct _THEME_CONTROL
202{ 204{
203 THEME_CONTROL_TYPE type; 205 THEME_CONTROL_TYPE type;
204 206
@@ -296,7 +298,7 @@ struct THEME_CONTROL
296 HWND hWnd; 298 HWND hWnd;
297 DWORD dwData; // type specific data 299 DWORD dwData; // type specific data
298 THEME* pTheme; 300 THEME* pTheme;
299}; 301} THEME_CONTROL;
300 302
301 303
302struct THEME_IMAGELIST 304struct THEME_IMAGELIST
@@ -580,8 +582,7 @@ HRESULT DAPI ThemeLoadStrings(
580 582
581 *******************************************************************/ 583 *******************************************************************/
582HRESULT DAPI ThemeLoadRichEditFromFile( 584HRESULT DAPI ThemeLoadRichEditFromFile(
583 __in THEME* pTheme, 585 __in const THEME_CONTROL* pThemeControl,
584 __in DWORD dwControl,
585 __in_z LPCWSTR wzFileName, 586 __in_z LPCWSTR wzFileName,
586 __in HMODULE hModule 587 __in HMODULE hModule
587 ); 588 );
@@ -591,19 +592,7 @@ HRESULT DAPI ThemeLoadRichEditFromFile(
591 592
592 *******************************************************************/ 593 *******************************************************************/
593HRESULT DAPI ThemeLoadRichEditFromResource( 594HRESULT DAPI ThemeLoadRichEditFromResource(
594 __in THEME* pTheme, 595 __in const THEME_CONTROL* pThemeControl,
595 __in DWORD dwControl,
596 __in_z LPCSTR szResourceName,
597 __in HMODULE hModule
598 );
599
600/********************************************************************
601 ThemeLoadRichEditFromResourceToHWnd - Attach a richedit control (by
602 HWND) to resource data.
603
604 *******************************************************************/
605HRESULT DAPI ThemeLoadRichEditFromResourceToHWnd(
606 __in HWND hWnd,
607 __in_z LPCSTR szResourceName, 596 __in_z LPCSTR szResourceName,
608 __in HMODULE hModule 597 __in HMODULE hModule
609 ); 598 );
@@ -682,18 +671,28 @@ ThemeShowChild - shows a control's specified child control, hiding the rest.
682 671
683*******************************************************************/ 672*******************************************************************/
684void DAPI ThemeShowChild( 673void DAPI ThemeShowChild(
685 __in THEME* pTheme,
686 __in THEME_CONTROL* pParentControl, 674 __in THEME_CONTROL* pParentControl,
687 __in DWORD dwIndex 675 __in DWORD dwIndex
688 ); 676 );
689 677
690/******************************************************************** 678/********************************************************************
691 ThemeControlExists - check if a control with the specified id exists. 679 ThemeControlExistsByHwnd - check if a control with the specified hWnd exists.
680
681 *******************************************************************/
682BOOL DAPI ThemeControlExistsByHWnd(
683 __in const THEME* pTheme,
684 __in HWND hWnd,
685 __out_opt const THEME_CONTROL** ppThemeControl
686 );
687
688/********************************************************************
689 ThemeControlExistsById - check if a control with the specified id exists.
692 690
693 *******************************************************************/ 691 *******************************************************************/
694BOOL DAPI ThemeControlExists( 692BOOL DAPI ThemeControlExistsById(
695 __in const THEME* pTheme, 693 __in const THEME* pTheme,
696 __in DWORD dwControl 694 __in WORD wId,
695 __out_opt const THEME_CONTROL** ppThemeControl
697 ); 696 );
698 697
699/******************************************************************** 698/********************************************************************
@@ -701,8 +700,7 @@ BOOL DAPI ThemeControlExists(
701 700
702 *******************************************************************/ 701 *******************************************************************/
703void DAPI ThemeControlEnable( 702void DAPI ThemeControlEnable(
704 __in THEME* pTheme, 703 __in const THEME_CONTROL* pThemeControl,
705 __in DWORD dwControl,
706 __in BOOL fEnable 704 __in BOOL fEnable
707 ); 705 );
708 706
@@ -711,8 +709,7 @@ void DAPI ThemeControlEnable(
711 709
712 *******************************************************************/ 710 *******************************************************************/
713BOOL DAPI ThemeControlEnabled( 711BOOL DAPI ThemeControlEnabled(
714 __in THEME* pTheme, 712 __in const THEME_CONTROL* pThemeControl
715 __in DWORD dwControl
716 ); 713 );
717 714
718/******************************************************************** 715/********************************************************************
@@ -720,8 +717,7 @@ BOOL DAPI ThemeControlEnabled(
720 717
721 *******************************************************************/ 718 *******************************************************************/
722void DAPI ThemeControlElevates( 719void DAPI ThemeControlElevates(
723 __in THEME* pTheme, 720 __in const THEME_CONTROL* pThemeControl,
724 __in DWORD dwControl,
725 __in BOOL fElevates 721 __in BOOL fElevates
726 ); 722 );
727 723
@@ -730,8 +726,7 @@ void DAPI ThemeControlElevates(
730 726
731 *******************************************************************/ 727 *******************************************************************/
732void DAPI ThemeShowControl( 728void DAPI ThemeShowControl(
733 __in THEME* pTheme, 729 __in const THEME_CONTROL* pThemeControl,
734 __in DWORD dwControl,
735 __in int nCmdShow 730 __in int nCmdShow
736 ); 731 );
737 732
@@ -741,8 +736,7 @@ conditional text and notes.
741 736
742*******************************************************************/ 737*******************************************************************/
743void DAPI ThemeShowControlEx( 738void DAPI ThemeShowControlEx(
744 __in THEME* pTheme, 739 __in const THEME_CONTROL* pThemeControl,
745 __in DWORD dwControl,
746 __in int nCmdShow 740 __in int nCmdShow
747 ); 741 );
748 742
@@ -751,24 +745,7 @@ void DAPI ThemeShowControlEx(
751 745
752 *******************************************************************/ 746 *******************************************************************/
753BOOL DAPI ThemeControlVisible( 747BOOL DAPI ThemeControlVisible(
754 __in THEME* pTheme, 748 __in const THEME_CONTROL* pThemeControl
755 __in DWORD dwControl
756 );
757
758BOOL DAPI ThemePostControlMessage(
759 __in THEME* pTheme,
760 __in DWORD dwControl,
761 __in UINT Msg,
762 __in WPARAM wParam,
763 __in LPARAM lParam
764 );
765
766LRESULT DAPI ThemeSendControlMessage(
767 __in const THEME* pTheme,
768 __in DWORD dwControl,
769 __in UINT Msg,
770 __in WPARAM wParam,
771 __in LPARAM lParam
772 ); 749 );
773 750
774/******************************************************************** 751/********************************************************************
@@ -790,34 +767,12 @@ HRESULT DAPI ThemeDrawControl(
790 ); 767 );
791 768
792/******************************************************************** 769/********************************************************************
793 ThemeHoverControl - mark a control as hover.
794
795*******************************************************************/
796BOOL DAPI ThemeHoverControl(
797 __in THEME* pTheme,
798 __in HWND hwndParent,
799 __in HWND hwndControl
800 );
801
802/********************************************************************
803 ThemeIsControlChecked - gets whether a control is checked. Only 770 ThemeIsControlChecked - gets whether a control is checked. Only
804 really useful for checkbox controls. 771 really useful for checkbox controls.
805 772
806*******************************************************************/ 773*******************************************************************/
807BOOL DAPI ThemeIsControlChecked( 774BOOL DAPI ThemeIsControlChecked(
808 __in THEME* pTheme, 775 __in const THEME_CONTROL* pThemeControl
809 __in DWORD dwControl
810 );
811
812/********************************************************************
813 ThemeSetControlColor - sets the color of text for a control.
814
815*******************************************************************/
816BOOL DAPI ThemeSetControlColor(
817 __in THEME* pTheme,
818 __in HDC hdc,
819 __in HWND hWnd,
820 __out HBRUSH* phBackgroundBrush
821 ); 776 );
822 777
823/******************************************************************** 778/********************************************************************
@@ -826,8 +781,7 @@ BOOL DAPI ThemeSetControlColor(
826 781
827*******************************************************************/ 782*******************************************************************/
828HRESULT DAPI ThemeSetProgressControl( 783HRESULT DAPI ThemeSetProgressControl(
829 __in THEME* pTheme, 784 __in const THEME_CONTROL* pThemeControl,
830 __in DWORD dwControl,
831 __in DWORD dwProgressPercentage 785 __in DWORD dwProgressPercentage
832 ); 786 );
833 787
@@ -837,8 +791,7 @@ HRESULT DAPI ThemeSetProgressControl(
837 791
838*******************************************************************/ 792*******************************************************************/
839HRESULT DAPI ThemeSetProgressControlColor( 793HRESULT DAPI ThemeSetProgressControlColor(
840 __in THEME* pTheme, 794 __in const THEME_CONTROL* pThemeControl,
841 __in DWORD dwControl,
842 __in DWORD dwColorIndex 795 __in DWORD dwColorIndex
843 ); 796 );
844 797
@@ -847,8 +800,7 @@ HRESULT DAPI ThemeSetProgressControlColor(
847 800
848*******************************************************************/ 801*******************************************************************/
849HRESULT DAPI ThemeSetTextControl( 802HRESULT DAPI ThemeSetTextControl(
850 __in const THEME* pTheme, 803 __in const THEME_CONTROL* pThemeControl,
851 __in DWORD dwControl,
852 __in_z_opt LPCWSTR wzText 804 __in_z_opt LPCWSTR wzText
853 ); 805 );
854 806
@@ -858,8 +810,7 @@ ThemeSetTextControl - sets the text of a control and optionally
858 810
859*******************************************************************/ 811*******************************************************************/
860HRESULT DAPI ThemeSetTextControlEx( 812HRESULT DAPI ThemeSetTextControlEx(
861 __in const THEME* pTheme, 813 __in const THEME_CONTROL* pThemeControl,
862 __in DWORD dwControl,
863 __in BOOL fUpdate, 814 __in BOOL fUpdate,
864 __in_z_opt LPCWSTR wzText 815 __in_z_opt LPCWSTR wzText
865 ); 816 );
@@ -869,8 +820,7 @@ HRESULT DAPI ThemeSetTextControlEx(
869 820
870*******************************************************************/ 821*******************************************************************/
871HRESULT DAPI ThemeGetTextControl( 822HRESULT DAPI ThemeGetTextControl(
872 __in const THEME* pTheme, 823 __in const THEME_CONTROL* pThemeControl,
873 __in DWORD dwControl,
874 __inout_z LPWSTR* psczText 824 __inout_z LPWSTR* psczText
875 ); 825 );
876 826
@@ -889,8 +839,7 @@ HRESULT DAPI ThemeUpdateCaption(
889 839
890*******************************************************************/ 840*******************************************************************/
891void DAPI ThemeSetFocus( 841void DAPI ThemeSetFocus(
892 __in THEME* pTheme, 842 __in const THEME_CONTROL* pThemeControl
893 __in DWORD dwControl
894 ); 843 );
895 844
896#ifdef __cplusplus 845#ifdef __cplusplus
diff --git a/src/libs/dutil/WixToolset.DUtil/inc/wndutil.h b/src/libs/dutil/WixToolset.DUtil/inc/wndutil.h
new file mode 100644
index 00000000..8de77f6e
--- /dev/null
+++ b/src/libs/dutil/WixToolset.DUtil/inc/wndutil.h
@@ -0,0 +1,41 @@
1#pragma once
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#ifdef __cplusplus
6extern "C" {
7#endif
8
9/********************************************************************
10 WnduLoadRichEditFromFile - Attach a richedit control to a RTF file.
11
12 *******************************************************************/
13HRESULT DAPI WnduLoadRichEditFromFile(
14 __in HWND hWnd,
15 __in_z LPCWSTR wzFileName,
16 __in HMODULE hModule
17 );
18
19/********************************************************************
20 WnduLoadRichEditFromResource - Attach a richedit control to resource data.
21
22 *******************************************************************/
23HRESULT DAPI WnduLoadRichEditFromResource(
24 __in HWND hWnd,
25 __in_z LPCSTR szResourceName,
26 __in HMODULE hModule
27 );
28
29/********************************************************************
30 WnduGetControlText - gets the text of a control.
31
32*******************************************************************/
33HRESULT DAPI WnduGetControlText(
34 __in HWND hWnd,
35 __inout_z LPWSTR* psczText
36 );
37
38#ifdef __cplusplus
39}
40#endif
41
diff --git a/src/libs/dutil/WixToolset.DUtil/precomp.h b/src/libs/dutil/WixToolset.DUtil/precomp.h
index 46d29f21..093c16a2 100644
--- a/src/libs/dutil/WixToolset.DUtil/precomp.h
+++ b/src/libs/dutil/WixToolset.DUtil/precomp.h
@@ -87,6 +87,7 @@
87#include "strutil.h" 87#include "strutil.h"
88#include "timeutil.h" 88#include "timeutil.h"
89#include "timeutil.h" 89#include "timeutil.h"
90#include "wndutil.h"
90#include "thmutil.h" 91#include "thmutil.h"
91#include "uncutil.h" 92#include "uncutil.h"
92#include "uriutil.h" 93#include "uriutil.h"
diff --git a/src/libs/dutil/WixToolset.DUtil/thmutil.cpp b/src/libs/dutil/WixToolset.DUtil/thmutil.cpp
index e8c23b6c..9adc2ddd 100644
--- a/src/libs/dutil/WixToolset.DUtil/thmutil.cpp
+++ b/src/libs/dutil/WixToolset.DUtil/thmutil.cpp
@@ -44,7 +44,6 @@ const DWORD THEME_INVALID_ID = 0xFFFFFFFF;
44const COLORREF THEME_INVISIBLE_COLORREF = 0xFFFFFFFF; 44const COLORREF THEME_INVISIBLE_COLORREF = 0xFFFFFFFF;
45const DWORD GROW_FONT_INSTANCES = 3; 45const DWORD GROW_FONT_INSTANCES = 3;
46const DWORD GROW_IMAGE_INSTANCES = 5; 46const DWORD GROW_IMAGE_INSTANCES = 5;
47const DWORD GROW_WINDOW_TEXT = 250;
48 47
49static Gdiplus::GdiplusStartupInput vgsi; 48static Gdiplus::GdiplusStartupInput vgsi;
50static Gdiplus::GdiplusStartupOutput vgso = { }; 49static Gdiplus::GdiplusStartupOutput vgso = { };
@@ -70,16 +69,29 @@ enum INTERNAL_CONTROL_STYLE
70 INTERNAL_CONTROL_STYLE_OWNER_DRAW = 0x0010, 69 INTERNAL_CONTROL_STYLE_OWNER_DRAW = 0x0010,
71}; 70};
72 71
73struct MEMBUFFER_FOR_RICHEDIT
74{
75 BYTE* rgbData;
76 DWORD cbData;
77 72
78 DWORD iData; 73// prototypes
79}; 74/********************************************************************
75 ThemeHoverControl - mark a control as hover.
76
77*******************************************************************/
78static BOOL ThemeHoverControl(
79 __in THEME* pTheme,
80 __in HWND hwndParent,
81 __in HWND hwndControl
82 );
80 83
84/********************************************************************
85 ThemeSetControlColor - sets the color of text for a control.
86
87*******************************************************************/
88static BOOL ThemeSetControlColor(
89 __in THEME* pTheme,
90 __in HDC hdc,
91 __in HWND hWnd,
92 __out HBRUSH* phBackgroundBrush
93 );
81 94
82// prototypes
83static HRESULT RegisterWindowClasses( 95static HRESULT RegisterWindowClasses(
84 __in_opt HMODULE hModule 96 __in_opt HMODULE hModule
85 ); 97 );
@@ -258,11 +270,11 @@ static HRESULT ParseNotes(
258 ); 270 );
259static HRESULT StopBillboard( 271static HRESULT StopBillboard(
260 __in THEME* pTheme, 272 __in THEME* pTheme,
261 __in DWORD dwControl 273 __in THEME_CONTROL* pControl
262 ); 274 );
263static HRESULT StartBillboard( 275static HRESULT StartBillboard(
264 __in THEME* pTheme, 276 __in THEME* pTheme,
265 __in DWORD dwControl 277 __in THEME_CONTROL* pControl
266 ); 278 );
267static HRESULT EnsureFontInstance( 279static HRESULT EnsureFontInstance(
268 __in THEME* pTheme, 280 __in THEME* pTheme,
@@ -290,7 +302,6 @@ static HRESULT LoadControls(
290 __in_opt THEME_CONTROL* pParentControl 302 __in_opt THEME_CONTROL* pParentControl
291 ); 303 );
292static HRESULT ShowControl( 304static HRESULT ShowControl(
293 __in THEME* pTheme,
294 __in THEME_CONTROL* pControl, 305 __in THEME_CONTROL* pControl,
295 __in int nCmdShow, 306 __in int nCmdShow,
296 __in BOOL fSaveEditboxes, 307 __in BOOL fSaveEditboxes,
@@ -376,18 +387,6 @@ static BOOL DrawHoverControl(
376 __in THEME* pTheme, 387 __in THEME* pTheme,
377 __in BOOL fHover 388 __in BOOL fHover
378 ); 389 );
379static DWORD CALLBACK RichEditStreamFromFileHandleCallback(
380 __in DWORD_PTR dwCookie,
381 __in_bcount(cb) LPBYTE pbBuff,
382 __in LONG cb,
383 __in LONG *pcb
384 );
385static DWORD CALLBACK RichEditStreamFromMemoryCallback(
386 __in DWORD_PTR dwCookie,
387 __in_bcount(cb) LPBYTE pbBuff,
388 __in LONG cb,
389 __in LONG *pcb
390 );
391static void FreeFontInstance( 390static void FreeFontInstance(
392 __in THEME_FONT_INSTANCE* pFontInstance 391 __in THEME_FONT_INSTANCE* pFontInstance
393 ); 392 );
@@ -475,6 +474,11 @@ static BOOL OnWmNotify(
475 __in const THEME_CONTROL* pThemeControl, 474 __in const THEME_CONTROL* pThemeControl,
476 __inout LRESULT* plResult 475 __inout LRESULT* plResult
477 ); 476 );
477static const THEME_CONTROL* FindControlFromId(
478 __in const THEME* pTheme,
479 __in WORD wId,
480 __in_opt const THEME_CONTROL* pParentControl = NULL
481 );
478static const THEME_CONTROL* FindControlFromHWnd( 482static const THEME_CONTROL* FindControlFromHWnd(
479 __in const THEME* pTheme, 483 __in const THEME* pTheme,
480 __in HWND hWnd, 484 __in HWND hWnd,
@@ -974,83 +978,39 @@ LExit:
974 978
975 979
976DAPI_(HRESULT) ThemeLoadRichEditFromFile( 980DAPI_(HRESULT) ThemeLoadRichEditFromFile(
977 __in THEME* pTheme, 981 __in const THEME_CONTROL* pThemeControl,
978 __in DWORD dwControl,
979 __in_z LPCWSTR wzFileName, 982 __in_z LPCWSTR wzFileName,
980 __in HMODULE hModule 983 __in HMODULE hModule
981 ) 984 )
982{ 985{
983 HRESULT hr = S_OK; 986 HRESULT hr = E_INVALIDARG;
984 LPWSTR sczFile = NULL;
985 HANDLE hFile = INVALID_HANDLE_VALUE;
986 HWND hWnd = ::GetDlgItem(pTheme->hwndParent, dwControl);
987
988 hr = PathRelativeToModule(&sczFile, wzFileName, hModule);
989 ThmExitOnFailure(hr, "Failed to read resource data.");
990 987
991 hFile = ::CreateFileW(sczFile, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); 988 if (pThemeControl)
992 if (INVALID_HANDLE_VALUE == hFile)
993 { 989 {
994 ThmExitWithLastError(hr, "Failed to open RTF file."); 990 AssertSz(THEME_CONTROL_TYPE_RICHEDIT == pThemeControl->type, "ThemeLoadRichEditFromFile called for non-RichEdit control.");
995 }
996 else
997 {
998 LONGLONG llRtfSize;
999 hr = FileSizeByHandle(hFile, &llRtfSize);
1000 if (SUCCEEDED(hr))
1001 {
1002 ::SendMessageW(hWnd, EM_EXLIMITTEXT, 0, static_cast<LPARAM>(llRtfSize));
1003 }
1004
1005 EDITSTREAM es = { };
1006 es.pfnCallback = RichEditStreamFromFileHandleCallback;
1007 es.dwCookie = reinterpret_cast<DWORD_PTR>(hFile);
1008 991
1009 ::SendMessageW(hWnd, EM_STREAMIN, SF_RTF, reinterpret_cast<LPARAM>(&es)); 992 hr = WnduLoadRichEditFromFile(pThemeControl->hWnd, wzFileName, hModule);
1010 hr = es.dwError;
1011 ThmExitOnFailure(hr, "Failed to update RTF stream.");
1012 } 993 }
1013 994
1014LExit:
1015 ReleaseStr(sczFile);
1016 ReleaseFile(hFile);
1017
1018 return hr; 995 return hr;
1019} 996}
1020 997
1021 998
1022DAPI_(HRESULT) ThemeLoadRichEditFromResource( 999DAPI_(HRESULT) ThemeLoadRichEditFromResource(
1023 __in THEME* pTheme, 1000 __in const THEME_CONTROL* pThemeControl,
1024 __in DWORD dwControl,
1025 __in_z LPCSTR szResourceName,
1026 __in HMODULE hModule
1027 )
1028{
1029 HWND hWnd = ::GetDlgItem(pTheme->hwndParent, dwControl);
1030 return ThemeLoadRichEditFromResourceToHWnd(hWnd, szResourceName, hModule);
1031}
1032
1033DAPI_(HRESULT) ThemeLoadRichEditFromResourceToHWnd(
1034 __in HWND hWnd,
1035 __in_z LPCSTR szResourceName, 1001 __in_z LPCSTR szResourceName,
1036 __in HMODULE hModule 1002 __in HMODULE hModule
1037 ) 1003 )
1038{ 1004{
1039 HRESULT hr = S_OK; 1005 HRESULT hr = E_INVALIDARG;
1040 MEMBUFFER_FOR_RICHEDIT buffer = { };
1041 EDITSTREAM es = { };
1042
1043 hr = ResReadData(hModule, szResourceName, reinterpret_cast<LPVOID*>(&buffer.rgbData), &buffer.cbData);
1044 ThmExitOnFailure(hr, "Failed to read resource data.");
1045 1006
1046 es.pfnCallback = RichEditStreamFromMemoryCallback; 1007 if (pThemeControl)
1047 es.dwCookie = reinterpret_cast<DWORD_PTR>(&buffer); 1008 {
1009 AssertSz(THEME_CONTROL_TYPE_RICHEDIT == pThemeControl->type, "ThemeLoadRichEditFromResource called for non-RichEdit control.");
1048 1010
1049 ::SendMessageW(hWnd, EM_STREAMIN, SF_RTF, reinterpret_cast<LPARAM>(&es)); 1011 hr = WnduLoadRichEditFromResource(pThemeControl->hWnd, szResourceName, hModule);
1050 hr = es.dwError; 1012 }
1051 ThmExitOnFailure(hr, "Failed to update RTF stream.");
1052 1013
1053LExit:
1054 return hr; 1014 return hr;
1055} 1015}
1056 1016
@@ -1293,141 +1253,127 @@ LExit:
1293} 1253}
1294 1254
1295 1255
1296DAPI_(BOOL) ThemeControlExists( 1256DAPI_(BOOL) ThemeControlExistsByHWnd(
1297 __in const THEME* pTheme, 1257 __in const THEME* pTheme,
1298 __in DWORD dwControl 1258 __in HWND hWnd,
1259 __out_opt const THEME_CONTROL** ppThemeControl
1299 ) 1260 )
1300{ 1261{
1301 BOOL fExists = FALSE; 1262 const THEME_CONTROL* pControl = FindControlFromHWnd(pTheme, hWnd);
1302 HWND hWnd = ::GetDlgItem(pTheme->hwndParent, dwControl); 1263
1303 if (hWnd) 1264 if (ppThemeControl)
1304 { 1265 {
1305 const THEME_CONTROL* pControl = FindControlFromHWnd(pTheme, hWnd); 1266 *ppThemeControl = pControl;
1306 fExists = (pControl && hWnd == pControl->hWnd);
1307 } 1267 }
1308 1268
1309 return fExists; 1269 return NULL != pControl;
1270}
1271
1272
1273DAPI_(BOOL) ThemeControlExistsById(
1274 __in const THEME* pTheme,
1275 __in WORD wId,
1276 __out_opt const THEME_CONTROL** ppThemeControl
1277 )
1278{
1279 const THEME_CONTROL* pControl = FindControlFromId(pTheme, wId);
1280
1281 if (ppThemeControl)
1282 {
1283 *ppThemeControl = pControl;
1284 }
1285
1286 return NULL != pControl;
1310} 1287}
1311 1288
1312 1289
1313DAPI_(void) ThemeControlEnable( 1290DAPI_(void) ThemeControlEnable(
1314 __in THEME* pTheme, 1291 __in const THEME_CONTROL* pThemeControl,
1315 __in DWORD dwControl,
1316 __in BOOL fEnable 1292 __in BOOL fEnable
1317 ) 1293 )
1318{ 1294{
1319 HWND hWnd = ::GetDlgItem(pTheme->hwndParent, dwControl); 1295 if (pThemeControl)
1320 THEME_CONTROL* pControl = const_cast<THEME_CONTROL*>(FindControlFromHWnd(pTheme, hWnd));
1321 if (pControl)
1322 { 1296 {
1297 THEME_CONTROL* pControl = const_cast<THEME_CONTROL*>(pThemeControl);
1323 pControl->dwInternalStyle = fEnable ? (pControl->dwInternalStyle & ~INTERNAL_CONTROL_STYLE_DISABLED) : (pControl->dwInternalStyle | INTERNAL_CONTROL_STYLE_DISABLED); 1298 pControl->dwInternalStyle = fEnable ? (pControl->dwInternalStyle & ~INTERNAL_CONTROL_STYLE_DISABLED) : (pControl->dwInternalStyle | INTERNAL_CONTROL_STYLE_DISABLED);
1324 ::EnableWindow(hWnd, fEnable); 1299 ::EnableWindow(pControl->hWnd, fEnable);
1325 1300
1326 if (pControl->dwInternalStyle & INTERNAL_CONTROL_STYLE_HIDE_WHEN_DISABLED) 1301 if (pControl->dwInternalStyle & INTERNAL_CONTROL_STYLE_HIDE_WHEN_DISABLED)
1327 { 1302 {
1328 ::ShowWindow(hWnd, fEnable ? SW_SHOW : SW_HIDE); 1303 ::ShowWindow(pControl->hWnd, fEnable ? SW_SHOW : SW_HIDE);
1329 } 1304 }
1330 } 1305 }
1331} 1306}
1332 1307
1333 1308
1334DAPI_(BOOL) ThemeControlEnabled( 1309DAPI_(BOOL) ThemeControlEnabled(
1335 __in THEME* pTheme, 1310 __in const THEME_CONTROL* pThemeControl
1336 __in DWORD dwControl
1337 ) 1311 )
1338{ 1312{
1339 HWND hWnd = ::GetDlgItem(pTheme->hwndParent, dwControl); 1313 BOOL fEnabled = FALSE;
1340 const THEME_CONTROL* pControl = FindControlFromHWnd(pTheme, hWnd); 1314
1341 return pControl && !(pControl->dwInternalStyle & INTERNAL_CONTROL_STYLE_DISABLED); 1315 if (pThemeControl)
1316 {
1317 fEnabled = !(pThemeControl->dwInternalStyle & INTERNAL_CONTROL_STYLE_DISABLED);
1318 }
1319
1320 return fEnabled;
1342} 1321}
1343 1322
1344 1323
1345DAPI_(void) ThemeControlElevates( 1324DAPI_(void) ThemeControlElevates(
1346 __in THEME* pTheme, 1325 __in const THEME_CONTROL* pThemeControl,
1347 __in DWORD dwControl,
1348 __in BOOL fElevates 1326 __in BOOL fElevates
1349 ) 1327 )
1350{ 1328{
1351 HWND hWnd = ::GetDlgItem(pTheme->hwndParent, dwControl); 1329 if (pThemeControl)
1352 ::SendMessageW(hWnd, BCM_SETSHIELD, 0, fElevates); 1330 {
1331 ::SendMessageW(pThemeControl->hWnd, BCM_SETSHIELD, 0, fElevates);
1332 }
1353} 1333}
1354 1334
1355 1335
1356DAPI_(void) ThemeShowControl( 1336DAPI_(void) ThemeShowControl(
1357 __in THEME* pTheme, 1337 __in const THEME_CONTROL* pThemeControl,
1358 __in DWORD dwControl,
1359 __in int nCmdShow 1338 __in int nCmdShow
1360 ) 1339 )
1361{ 1340{
1362 HWND hWnd = ::GetDlgItem(pTheme->hwndParent, dwControl); 1341 if (pThemeControl)
1363 ::ShowWindow(hWnd, nCmdShow);
1364
1365 // Save the control's visible state.
1366 THEME_CONTROL* pControl = const_cast<THEME_CONTROL*>(FindControlFromHWnd(pTheme, hWnd));
1367 if (pControl)
1368 { 1342 {
1343 THEME_CONTROL* pControl = const_cast<THEME_CONTROL*>(pThemeControl);
1344 ::ShowWindow(pControl->hWnd, nCmdShow);
1345
1346 // Save the control's visible state.
1369 pControl->dwInternalStyle = (SW_HIDE == nCmdShow) ? (pControl->dwInternalStyle | INTERNAL_CONTROL_STYLE_HIDDEN) : (pControl->dwInternalStyle & ~INTERNAL_CONTROL_STYLE_HIDDEN); 1347 pControl->dwInternalStyle = (SW_HIDE == nCmdShow) ? (pControl->dwInternalStyle | INTERNAL_CONTROL_STYLE_HIDDEN) : (pControl->dwInternalStyle & ~INTERNAL_CONTROL_STYLE_HIDDEN);
1370 } 1348 }
1371} 1349}
1372 1350
1373 1351
1374DAPI_(void) ThemeShowControlEx( 1352DAPI_(void) ThemeShowControlEx(
1375 __in THEME* pTheme, 1353 __in const THEME_CONTROL* pThemeControl,
1376 __in DWORD dwControl,
1377 __in int nCmdShow 1354 __in int nCmdShow
1378 ) 1355 )
1379{ 1356{
1380 HWND hWnd = ::GetDlgItem(pTheme->hwndParent, dwControl); 1357 if (pThemeControl)
1381 THEME_CONTROL* pControl = const_cast<THEME_CONTROL*>(FindControlFromHWnd(pTheme, hWnd));
1382 if (pControl)
1383 { 1358 {
1384 ShowControl(pTheme, pControl, nCmdShow, THEME_CONTROL_TYPE_EDITBOX == pControl->type, THEME_SHOW_PAGE_REASON_REFRESH, 0, NULL); 1359 THEME_CONTROL* pControl = const_cast<THEME_CONTROL*>(pThemeControl);
1360 ShowControl(pControl, nCmdShow, THEME_CONTROL_TYPE_EDITBOX == pControl->type, THEME_SHOW_PAGE_REASON_REFRESH, 0, NULL);
1385 } 1361 }
1386} 1362}
1387 1363
1388 1364
1389DAPI_(BOOL) ThemeControlVisible( 1365DAPI_(BOOL) ThemeControlVisible(
1390 __in THEME* pTheme, 1366 __in const THEME_CONTROL* pThemeControl
1391 __in DWORD dwControl
1392 ) 1367 )
1393{ 1368{
1394 HWND hWnd = ::GetDlgItem(pTheme->hwndParent, dwControl); 1369 BOOL fVisible = FALSE;
1395 return ::IsWindowVisible(hWnd);
1396}
1397
1398 1370
1399DAPI_(BOOL) ThemePostControlMessage( 1371 if (pThemeControl)
1400 __in THEME* pTheme,
1401 __in DWORD dwControl,
1402 __in UINT Msg,
1403 __in WPARAM wParam,
1404 __in LPARAM lParam
1405 )
1406{
1407 HRESULT hr = S_OK;
1408 UINT er = ERROR_SUCCESS;
1409 HWND hWnd = ::GetDlgItem(pTheme->hwndParent, dwControl);
1410
1411 if (!::PostMessageW(hWnd, Msg, wParam, lParam))
1412 { 1372 {
1413 er = ::GetLastError(); 1373 fVisible = ::IsWindowVisible(pThemeControl->hWnd);
1414 hr = HRESULT_FROM_WIN32(er);
1415 } 1374 }
1416 1375
1417 return SUCCEEDED(hr); 1376 return fVisible;
1418}
1419
1420
1421DAPI_(LRESULT) ThemeSendControlMessage(
1422 __in const THEME* pTheme,
1423 __in DWORD dwControl,
1424 __in UINT Msg,
1425 __in WPARAM wParam,
1426 __in LPARAM lParam
1427 )
1428{
1429 HWND hWnd = ::GetDlgItem(pTheme->hwndParent, dwControl);
1430 return ::SendMessageW(hWnd, Msg, wParam, lParam);
1431} 1377}
1432 1378
1433 1379
@@ -1453,9 +1399,15 @@ DAPI_(HRESULT) ThemeDrawControl(
1453 ) 1399 )
1454{ 1400{
1455 HRESULT hr = S_OK; 1401 HRESULT hr = S_OK;
1456 const THEME_CONTROL* pControl = FindControlFromHWnd(pTheme, pdis->hwndItem); 1402 const THEME_CONTROL* pControl = NULL;
1403 BOOL fExists = ThemeControlExistsByHWnd(pTheme, pdis->hwndItem, &pControl);
1404
1405 AssertSz(fExists, "Expected control window from owner draw window.");
1406 if (!fExists)
1407 {
1408 ExitFunction1(hr = E_INVALIDARG);
1409 }
1457 1410
1458 AssertSz(pControl, "Expected control window from owner draw window.");
1459 AssertSz(pControl->hWnd == pdis->hwndItem, "Expected control window to match owner draw window."); 1411 AssertSz(pControl->hWnd == pdis->hwndItem, "Expected control window to match owner draw window.");
1460 AssertSz(pControl->nWidth < 1 || pControl->nWidth == pdis->rcItem.right - pdis->rcItem.left, "Expected control window width to match owner draw window width."); 1412 AssertSz(pControl->nWidth < 1 || pControl->nWidth == pdis->rcItem.right - pdis->rcItem.left, "Expected control window width to match owner draw window width.");
1461 AssertSz(pControl->nHeight < 1 || pControl->nHeight == pdis->rcItem.bottom - pdis->rcItem.top, "Expected control window height to match owner draw window height."); 1413 AssertSz(pControl->nHeight < 1 || pControl->nHeight == pdis->rcItem.bottom - pdis->rcItem.top, "Expected control window height to match owner draw window height.");
@@ -1492,7 +1444,7 @@ LExit:
1492} 1444}
1493 1445
1494 1446
1495DAPI_(BOOL) ThemeHoverControl( 1447static BOOL ThemeHoverControl(
1496 __in THEME* pTheme, 1448 __in THEME* pTheme,
1497 __in HWND hwndParent, 1449 __in HWND hwndParent,
1498 __in HWND hwndControl 1450 __in HWND hwndControl
@@ -1519,16 +1471,21 @@ DAPI_(BOOL) ThemeHoverControl(
1519 1471
1520 1472
1521DAPI_(BOOL) ThemeIsControlChecked( 1473DAPI_(BOOL) ThemeIsControlChecked(
1522 __in THEME* pTheme, 1474 __in const THEME_CONTROL* pThemeControl
1523 __in DWORD dwControl
1524 ) 1475 )
1525{ 1476{
1526 HWND hWnd = ::GetDlgItem(pTheme->hwndParent, dwControl); 1477 BOOL fChecked = FALSE;
1527 return BST_CHECKED == ::SendMessageW(hWnd, BM_GETCHECK, 0, 0); 1478
1479 if (pThemeControl)
1480 {
1481 fChecked = BST_CHECKED == ::SendMessageW(pThemeControl->hWnd, BM_GETCHECK, 0, 0);
1482 }
1483
1484 return fChecked;
1528} 1485}
1529 1486
1530 1487
1531DAPI_(BOOL) ThemeSetControlColor( 1488static BOOL ThemeSetControlColor(
1532 __in THEME* pTheme, 1489 __in THEME* pTheme,
1533 __in HDC hdc, 1490 __in HDC hdc,
1534 __in HWND hWnd, 1491 __in HWND hWnd,
@@ -1537,6 +1494,7 @@ DAPI_(BOOL) ThemeSetControlColor(
1537{ 1494{
1538 THEME_FONT* pFont = NULL; 1495 THEME_FONT* pFont = NULL;
1539 BOOL fHasBackground = FALSE; 1496 BOOL fHasBackground = FALSE;
1497 const THEME_CONTROL* pControl = NULL;
1540 1498
1541 *phBackgroundBrush = NULL; 1499 *phBackgroundBrush = NULL;
1542 1500
@@ -1544,10 +1502,9 @@ DAPI_(BOOL) ThemeSetControlColor(
1544 { 1502 {
1545 pFont = (THEME_INVALID_ID == pTheme->dwFontId) ? NULL : pTheme->rgFonts + pTheme->dwFontId; 1503 pFont = (THEME_INVALID_ID == pTheme->dwFontId) ? NULL : pTheme->rgFonts + pTheme->dwFontId;
1546 } 1504 }
1547 else 1505 else if (ThemeControlExistsByHWnd(pTheme, hWnd, &pControl))
1548 { 1506 {
1549 const THEME_CONTROL* pControl = FindControlFromHWnd(pTheme, hWnd); 1507 pFont = THEME_INVALID_ID == pControl->dwFontId ? NULL : pTheme->rgFonts + pControl->dwFontId;
1550 pFont = (!pControl || THEME_INVALID_ID == pControl->dwFontId) ? NULL : pTheme->rgFonts + pControl->dwFontId;
1551 } 1508 }
1552 1509
1553 if (pFont) 1510 if (pFont)
@@ -1577,44 +1534,40 @@ DAPI_(BOOL) ThemeSetControlColor(
1577 1534
1578 1535
1579DAPI_(HRESULT) ThemeSetProgressControl( 1536DAPI_(HRESULT) ThemeSetProgressControl(
1580 __in THEME* pTheme, 1537 __in const THEME_CONTROL* pThemeControl,
1581 __in DWORD dwControl,
1582 __in DWORD dwProgressPercentage 1538 __in DWORD dwProgressPercentage
1583 ) 1539 )
1584{ 1540{
1585 HRESULT hr = E_NOTFOUND; 1541 HRESULT hr = E_INVALIDARG;
1586 HWND hWnd = ::GetDlgItem(pTheme->hwndParent, dwControl);
1587 1542
1588 if (hWnd) 1543 if (pThemeControl && THEME_CONTROL_TYPE_PROGRESSBAR == pThemeControl->type)
1589 { 1544 {
1590 THEME_CONTROL* pControl = const_cast<THEME_CONTROL*>(FindControlFromHWnd(pTheme, hWnd)); 1545 THEME_CONTROL* pControl = const_cast<THEME_CONTROL*>(pThemeControl);
1591 if (pControl && THEME_CONTROL_TYPE_PROGRESSBAR == pControl->type) 1546
1547 DWORD dwCurrentProgress = LOWORD(pControl->dwData);
1548
1549 if (dwCurrentProgress != dwProgressPercentage)
1592 { 1550 {
1593 DWORD dwCurrentProgress = LOWORD(pControl->dwData); 1551 DWORD dwColor = HIWORD(pControl->dwData);
1552 pControl->dwData = MAKEDWORD(dwProgressPercentage, dwColor);
1594 1553
1595 if (dwCurrentProgress != dwProgressPercentage) 1554 if (pControl->dwInternalStyle & INTERNAL_CONTROL_STYLE_OWNER_DRAW)
1596 { 1555 {
1597 DWORD dwColor = HIWORD(pControl->dwData); 1556 if (!::InvalidateRect(pControl->hWnd, NULL, FALSE))
1598 pControl->dwData = MAKEDWORD(dwProgressPercentage, dwColor);
1599
1600 if (pControl->dwInternalStyle & INTERNAL_CONTROL_STYLE_OWNER_DRAW)
1601 { 1557 {
1602 if (!::InvalidateRect(hWnd, NULL, FALSE)) 1558 ThmExitWithLastError(hr, "Failed to invalidate progress bar window.");
1603 {
1604 ThmExitWithLastError(hr, "Failed to invalidate progress bar window.");
1605 }
1606 }
1607 else
1608 {
1609 ::SendMessageW(hWnd, PBM_SETPOS, dwProgressPercentage, 0);
1610 } 1559 }
1611
1612 hr = S_OK;
1613 } 1560 }
1614 else 1561 else
1615 { 1562 {
1616 hr = S_FALSE; 1563 ::SendMessageW(pControl->hWnd, PBM_SETPOS, dwProgressPercentage, 0);
1617 } 1564 }
1565
1566 hr = S_OK;
1567 }
1568 else
1569 {
1570 hr = S_FALSE;
1618 } 1571 }
1619 } 1572 }
1620 1573
@@ -1624,37 +1577,37 @@ LExit:
1624 1577
1625 1578
1626DAPI_(HRESULT) ThemeSetProgressControlColor( 1579DAPI_(HRESULT) ThemeSetProgressControlColor(
1627 __in THEME* pTheme, 1580 __in const THEME_CONTROL* pThemeControl,
1628 __in DWORD dwControl,
1629 __in DWORD dwColorIndex 1581 __in DWORD dwColorIndex
1630 ) 1582 )
1631{ 1583{
1632 HRESULT hr = S_FALSE; 1584 HRESULT hr = E_INVALIDARG;
1633 HWND hWnd = ::GetDlgItem(pTheme->hwndParent, dwControl); 1585
1634 if (hWnd) 1586 // Only set color on owner draw progress bars.
1587 if (pThemeControl && THEME_CONTROL_TYPE_PROGRESSBAR == pThemeControl->type && (pThemeControl->dwInternalStyle & INTERNAL_CONTROL_STYLE_OWNER_DRAW))
1635 { 1588 {
1636 THEME_CONTROL* pControl = const_cast<THEME_CONTROL*>(FindControlFromHWnd(pTheme, hWnd)); 1589 THEME_CONTROL* pControl = const_cast<THEME_CONTROL*>(pThemeControl);
1637 1590
1638 // Only set color on owner draw progress bars. 1591 if (pControl->ProgressBar.cImageRef <= dwColorIndex)
1639 if (pControl && (pControl->dwInternalStyle & INTERNAL_CONTROL_STYLE_OWNER_DRAW) && THEME_CONTROL_TYPE_PROGRESSBAR == pControl->type)
1640 { 1592 {
1641 if (pControl->ProgressBar.cImageRef <= dwColorIndex) 1593 ThmExitWithRootFailure(hr, E_INVALIDARG, "Invalid progress bar color index: %u", dwColorIndex);
1642 { 1594 }
1643 ThmExitWithRootFailure(hr, E_INVALIDARG, "Invalid progress bar color index: %u", dwColorIndex);
1644 }
1645
1646 if (HIWORD(pControl->dwData) != dwColorIndex)
1647 {
1648 DWORD dwCurrentProgress = LOWORD(pControl->dwData);
1649 pControl->dwData = MAKEDWORD(dwCurrentProgress, dwColorIndex);
1650 1595
1651 if (!::InvalidateRect(hWnd, NULL, FALSE)) 1596 if (HIWORD(pControl->dwData) != dwColorIndex)
1652 { 1597 {
1653 ThmExitWithLastError(hr, "Failed to invalidate progress bar window."); 1598 DWORD dwCurrentProgress = LOWORD(pControl->dwData);
1654 } 1599 pControl->dwData = MAKEDWORD(dwCurrentProgress, dwColorIndex);
1655 1600
1656 hr = S_OK; 1601 if (!::InvalidateRect(pControl->hWnd, NULL, FALSE))
1602 {
1603 ThmExitWithLastError(hr, "Failed to invalidate progress bar window.");
1657 } 1604 }
1605
1606 hr = S_OK;
1607 }
1608 else
1609 {
1610 hr = S_FALSE;
1658 } 1611 }
1659 } 1612 }
1660 1613
@@ -1664,41 +1617,40 @@ LExit:
1664 1617
1665 1618
1666DAPI_(HRESULT) ThemeSetTextControl( 1619DAPI_(HRESULT) ThemeSetTextControl(
1667 __in const THEME* pTheme, 1620 __in const THEME_CONTROL* pThemeControl,
1668 __in DWORD dwControl,
1669 __in_z_opt LPCWSTR wzText 1621 __in_z_opt LPCWSTR wzText
1670 ) 1622 )
1671{ 1623{
1672 return ThemeSetTextControlEx(pTheme, dwControl, FALSE, wzText); 1624 return ThemeSetTextControlEx(pThemeControl, FALSE, wzText);
1673} 1625}
1674 1626
1675 1627
1676DAPI_(HRESULT) ThemeSetTextControlEx( 1628DAPI_(HRESULT) ThemeSetTextControlEx(
1677 __in const THEME* pTheme, 1629 __in const THEME_CONTROL* pThemeControl,
1678 __in DWORD dwControl,
1679 __in BOOL fUpdate, 1630 __in BOOL fUpdate,
1680 __in_z_opt LPCWSTR wzText 1631 __in_z_opt LPCWSTR wzText
1681 ) 1632 )
1682{ 1633{
1683 HRESULT hr = S_OK; 1634 HRESULT hr = E_INVALIDARG;
1684 HWND hWnd = ::GetDlgItem(pTheme->hwndParent, dwControl);
1685 1635
1686 if (hWnd) 1636 if (pThemeControl)
1687 { 1637 {
1688 if (fUpdate) 1638 if (fUpdate)
1689 { 1639 {
1690 ::ShowWindow(hWnd, SW_HIDE); 1640 ::ShowWindow(pThemeControl->hWnd, SW_HIDE);
1691 } 1641 }
1692 1642
1693 if (!::SetWindowTextW(hWnd, wzText)) 1643 if (!::SetWindowTextW(pThemeControl->hWnd, wzText))
1694 { 1644 {
1695 ThmExitWithLastError(hr, "Failed to set control text."); 1645 ThmExitWithLastError(hr, "Failed to set control text.");
1696 } 1646 }
1697 1647
1698 if (fUpdate) 1648 if (fUpdate)
1699 { 1649 {
1700 ::ShowWindow(hWnd, SW_SHOW); 1650 ::ShowWindow(pThemeControl->hWnd, SW_SHOW);
1701 } 1651 }
1652
1653 hr = S_OK;
1702 } 1654 }
1703 1655
1704LExit: 1656LExit:
@@ -1707,50 +1659,17 @@ LExit:
1707 1659
1708 1660
1709DAPI_(HRESULT) ThemeGetTextControl( 1661DAPI_(HRESULT) ThemeGetTextControl(
1710 __in const THEME* pTheme, 1662 __in const THEME_CONTROL* pThemeControl,
1711 __in DWORD dwControl,
1712 __inout_z LPWSTR* psczText 1663 __inout_z LPWSTR* psczText
1713 ) 1664 )
1714{ 1665{
1715 HRESULT hr = S_OK; 1666 HRESULT hr = E_INVALIDARG;
1716 HWND hWnd = ::GetDlgItem(pTheme->hwndParent, dwControl);
1717 SIZE_T cbSize = 0;
1718 DWORD cchText = 0;
1719 DWORD cchTextRead = 0;
1720
1721 // Ensure the string has room for at least one character.
1722 hr = StrMaxLength(*psczText, &cbSize);
1723 ThmExitOnFailure(hr, "Failed to get text buffer length.");
1724 1667
1725 cchText = (DWORD)min(DWORD_MAX, cbSize); 1668 if (pThemeControl)
1726
1727 if (!cchText)
1728 { 1669 {
1729 cchText = GROW_WINDOW_TEXT; 1670 hr = WnduGetControlText(pThemeControl->hWnd, psczText);
1730
1731 hr = StrAlloc(psczText, cchText);
1732 ThmExitOnFailure(hr, "Failed to grow text buffer.");
1733 } 1671 }
1734 1672
1735 // Read (and keep growing buffer) until we finally read less than there
1736 // is room in the buffer.
1737 for (;;)
1738 {
1739 cchTextRead = ::GetWindowTextW(hWnd, *psczText, cchText);
1740 if (cchTextRead + 1 < cchText)
1741 {
1742 break;
1743 }
1744 else
1745 {
1746 cchText = cchTextRead + GROW_WINDOW_TEXT;
1747
1748 hr = StrAlloc(psczText, cchText);
1749 ThmExitOnFailure(hr, "Failed to grow text buffer again.");
1750 }
1751 }
1752
1753LExit:
1754 return hr; 1673 return hr;
1755} 1674}
1756 1675
@@ -1771,25 +1690,26 @@ LExit:
1771 1690
1772 1691
1773DAPI_(void) ThemeSetFocus( 1692DAPI_(void) ThemeSetFocus(
1774 __in THEME* pTheme, 1693 __in const THEME_CONTROL* pThemeControl
1775 __in DWORD dwControl
1776 ) 1694 )
1777{ 1695{
1778 HWND hwndFocus = ::GetDlgItem(pTheme->hwndParent, dwControl); 1696 if (pThemeControl)
1779 if (hwndFocus && !ThemeControlEnabled(pTheme, dwControl)) 1697 {
1780 { 1698 HWND hwndFocus = pThemeControl->hWnd;
1781 hwndFocus = ::GetNextDlgTabItem(pTheme->hwndParent, hwndFocus, FALSE); 1699 if (hwndFocus && !ThemeControlEnabled(pThemeControl))
1782 } 1700 {
1701 hwndFocus = ::GetNextDlgTabItem(pThemeControl->pTheme->hwndParent, hwndFocus, FALSE);
1702 }
1783 1703
1784 if (hwndFocus) 1704 if (hwndFocus)
1785 { 1705 {
1786 ::SetFocus(hwndFocus); 1706 ::SetFocus(hwndFocus);
1707 }
1787 } 1708 }
1788} 1709}
1789 1710
1790 1711
1791DAPI_(void) ThemeShowChild( 1712DAPI_(void) ThemeShowChild(
1792 __in THEME* pTheme,
1793 __in THEME_CONTROL* pParentControl, 1713 __in THEME_CONTROL* pParentControl,
1794 __in DWORD dwIndex 1714 __in DWORD dwIndex
1795 ) 1715 )
@@ -1798,7 +1718,7 @@ DAPI_(void) ThemeShowChild(
1798 for (DWORD i = 0; i < pParentControl->cControls; ++i) 1718 for (DWORD i = 0; i < pParentControl->cControls; ++i)
1799 { 1719 {
1800 THEME_CONTROL* pControl = pParentControl->rgControls + i; 1720 THEME_CONTROL* pControl = pParentControl->rgControls + i;
1801 ShowControl(pTheme, pControl, dwIndex == i ? SW_SHOW : SW_HIDE, FALSE, THEME_SHOW_PAGE_REASON_DEFAULT, 0, NULL); 1721 ShowControl(pControl, dwIndex == i ? SW_SHOW : SW_HIDE, FALSE, THEME_SHOW_PAGE_REASON_DEFAULT, 0, NULL);
1802 } 1722 }
1803} 1723}
1804 1724
@@ -4322,28 +4242,24 @@ LExit:
4322 4242
4323static HRESULT StartBillboard( 4243static HRESULT StartBillboard(
4324 __in THEME* pTheme, 4244 __in THEME* pTheme,
4325 __in DWORD dwControl 4245 __in THEME_CONTROL* pControl
4326 ) 4246 )
4327{ 4247{
4328 HRESULT hr = E_NOTFOUND; 4248 HRESULT hr = E_NOTFOUND;
4329 HWND hWnd = ::GetDlgItem(pTheme->hwndParent, dwControl); 4249 UINT_PTR idEvent = reinterpret_cast<UINT_PTR>(pControl);
4330 4250
4331 if (hWnd) 4251 if (THEME_CONTROL_TYPE_BILLBOARD == pControl->type)
4332 { 4252 {
4333 THEME_CONTROL* pControl = const_cast<THEME_CONTROL*>(FindControlFromHWnd(pTheme, hWnd)); 4253 // kick off
4334 if (pControl && THEME_CONTROL_TYPE_BILLBOARD == pControl->type) 4254 pControl->dwData = 0;
4335 { 4255 OnBillboardTimer(pTheme, pTheme->hwndParent, idEvent);
4336 // kick off
4337 pControl->dwData = 0;
4338 OnBillboardTimer(pTheme, pTheme->hwndParent, dwControl);
4339 4256
4340 if (!::SetTimer(pTheme->hwndParent, pControl->wId, pControl->wBillboardInterval, NULL)) 4257 if (!::SetTimer(pTheme->hwndParent, idEvent, pControl->wBillboardInterval, NULL))
4341 { 4258 {
4342 ThmExitWithLastError(hr, "Failed to start billboard."); 4259 ThmExitWithLastError(hr, "Failed to start billboard.");
4343 }
4344
4345 hr = S_OK;
4346 } 4260 }
4261
4262 hr = S_OK;
4347 } 4263 }
4348 4264
4349LExit: 4265LExit:
@@ -4353,23 +4269,19 @@ LExit:
4353 4269
4354static HRESULT StopBillboard( 4270static HRESULT StopBillboard(
4355 __in THEME* pTheme, 4271 __in THEME* pTheme,
4356 __in DWORD dwControl 4272 __in THEME_CONTROL* pControl
4357 ) 4273 )
4358{ 4274{
4359 HRESULT hr = E_NOTFOUND; 4275 HRESULT hr = E_NOTFOUND;
4360 HWND hWnd = ::GetDlgItem(pTheme->hwndParent, dwControl); 4276 UINT_PTR idEvent = reinterpret_cast<UINT_PTR>(pControl);
4361 4277
4362 if (hWnd) 4278 if (THEME_CONTROL_TYPE_BILLBOARD == pControl->type)
4363 { 4279 {
4364 const THEME_CONTROL* pControl = FindControlFromHWnd(pTheme, hWnd); 4280 ThemeControlEnable(pControl, FALSE);
4365 if (pControl && THEME_CONTROL_TYPE_BILLBOARD == pControl->type)
4366 {
4367 ThemeControlEnable(pTheme, dwControl, FALSE);
4368 4281
4369 if (::KillTimer(pTheme->hwndParent, pControl->wId)) 4282 if (::KillTimer(pTheme->hwndParent, idEvent))
4370 { 4283 {
4371 hr = S_OK; 4284 hr = S_OK;
4372 }
4373 } 4285 }
4374 } 4286 }
4375 4287
@@ -5039,81 +4951,33 @@ static void FreeImageInstance(
5039} 4951}
5040 4952
5041 4953
5042static DWORD CALLBACK RichEditStreamFromFileHandleCallback(
5043 __in DWORD_PTR dwCookie,
5044 __in_bcount(cb) LPBYTE pbBuff,
5045 __in LONG cb,
5046 __in LONG* pcb
5047 )
5048{
5049 HRESULT hr = S_OK;
5050 HANDLE hFile = reinterpret_cast<HANDLE>(dwCookie);
5051
5052 if (!::ReadFile(hFile, pbBuff, cb, reinterpret_cast<DWORD*>(pcb), NULL))
5053 {
5054 ThmExitWithLastError(hr, "Failed to read file");
5055 }
5056
5057LExit:
5058 return hr;
5059}
5060
5061
5062static DWORD CALLBACK RichEditStreamFromMemoryCallback(
5063 __in DWORD_PTR dwCookie,
5064 __in_bcount(cb) LPBYTE pbBuff,
5065 __in LONG cb,
5066 __in LONG* pcb
5067 )
5068{
5069 HRESULT hr = S_OK;
5070 MEMBUFFER_FOR_RICHEDIT* pBuffer = reinterpret_cast<MEMBUFFER_FOR_RICHEDIT*>(dwCookie);
5071 DWORD cbCopy = 0;
5072
5073 if (pBuffer->iData < pBuffer->cbData)
5074 {
5075 cbCopy = min(static_cast<DWORD>(cb), pBuffer->cbData - pBuffer->iData);
5076 memcpy(pbBuff, pBuffer->rgbData + pBuffer->iData, cbCopy);
5077
5078 pBuffer->iData += cbCopy;
5079 Assert(pBuffer->iData <= pBuffer->cbData);
5080 }
5081
5082 *pcb = cbCopy;
5083 return hr;
5084}
5085
5086
5087static void CALLBACK OnBillboardTimer( 4954static void CALLBACK OnBillboardTimer(
5088 __in THEME* pTheme, 4955 __in THEME* /*pTheme*/,
5089 __in HWND hwnd, 4956 __in HWND hwnd,
5090 __in UINT_PTR idEvent 4957 __in UINT_PTR idEvent
5091 ) 4958 )
5092{ 4959{
5093 HWND hwndControl = ::GetDlgItem(hwnd, static_cast<int>(idEvent)); 4960 THEME_CONTROL* pControl = reinterpret_cast<THEME_CONTROL*>(idEvent);
5094 if (hwndControl) 4961
4962 if (pControl)
5095 { 4963 {
5096 THEME_CONTROL* pControl = const_cast<THEME_CONTROL*>(FindControlFromHWnd(pTheme, hwndControl)); 4964 AssertSz(THEME_CONTROL_TYPE_BILLBOARD == pControl->type, "Only billboard controls should get billboard timer messages.");
5097 AssertSz(pControl && THEME_CONTROL_TYPE_BILLBOARD == pControl->type, "Only billboard controls should get billboard timer messages.");
5098 4965
5099 if (pControl) 4966 if (pControl->dwData < pControl->cControls)
5100 { 4967 {
5101 if (pControl->dwData < pControl->cControls) 4968 ThemeShowChild(pControl, pControl->dwData);
5102 {
5103 ThemeShowChild(pTheme, pControl, pControl->dwData);
5104 }
5105 else if (pControl->fBillboardLoops)
5106 {
5107 pControl->dwData = 0;
5108 ThemeShowChild(pTheme, pControl, pControl->dwData);
5109 }
5110 else // no more looping
5111 {
5112 ::KillTimer(hwnd, idEvent);
5113 }
5114
5115 ++pControl->dwData;
5116 } 4969 }
4970 else if (pControl->fBillboardLoops)
4971 {
4972 pControl->dwData = 0;
4973 ThemeShowChild(pControl, pControl->dwData);
4974 }
4975 else // no more looping
4976 {
4977 ::KillTimer(hwnd, idEvent);
4978 }
4979
4980 ++pControl->dwData;
5117 } 4981 }
5118} 4982}
5119 4983
@@ -5151,7 +5015,7 @@ static void OnBrowseDirectory(
5151 5015
5152 if (pTargetControl && THEME_CONTROL_TYPE_EDITBOX == pTargetControl->type && !pTargetControl->fDisableVariableFunctionality) 5016 if (pTargetControl && THEME_CONTROL_TYPE_EDITBOX == pTargetControl->type && !pTargetControl->fDisableVariableFunctionality)
5153 { 5017 {
5154 hr = ThemeSetTextControl(pTheme, pTargetControl->wId, wzPath); 5018 hr = ThemeSetTextControl(pTargetControl, wzPath);
5155 ThmExitOnFailure(hr, "Failed to set text on editbox: %ls", pTargetControl->sczName); 5019 ThmExitOnFailure(hr, "Failed to set text on editbox: %ls", pTargetControl->sczName);
5156 } 5020 }
5157 else if (pTheme->pfnSetStringVariable) 5021 else if (pTheme->pfnSetStringVariable)
@@ -5161,7 +5025,7 @@ static void OnBrowseDirectory(
5161 } 5025 }
5162 else if (pTargetControl) 5026 else if (pTargetControl)
5163 { 5027 {
5164 hr = ThemeSetTextControl(pTheme, pTargetControl->wId, wzPath); 5028 hr = ThemeSetTextControl(pTargetControl, wzPath);
5165 ThmExitOnFailure(hr, "Failed to set text on control: %ls", pTargetControl->sczName); 5029 ThmExitOnFailure(hr, "Failed to set text on control: %ls", pTargetControl->sczName);
5166 } 5030 }
5167 5031
@@ -5252,13 +5116,13 @@ static BOOL OnButtonClicked(
5252 case THEME_CONTROL_TYPE_CHECKBOX: 5116 case THEME_CONTROL_TYPE_CHECKBOX:
5253 if (pTheme->pfnSetNumericVariable && pControl->sczName && *pControl->sczName) 5117 if (pTheme->pfnSetNumericVariable && pControl->sczName && *pControl->sczName)
5254 { 5118 {
5255 BOOL fChecked = ThemeIsControlChecked(pTheme, pControl->wId); 5119 BOOL fChecked = ThemeIsControlChecked(pControl);
5256 pTheme->pfnSetNumericVariable(pControl->sczName, fChecked ? 1 : 0, pTheme->pvVariableContext); 5120 pTheme->pfnSetNumericVariable(pControl->sczName, fChecked ? 1 : 0, pTheme->pvVariableContext);
5257 fRefresh = TRUE; 5121 fRefresh = TRUE;
5258 } 5122 }
5259 break; 5123 break;
5260 case THEME_CONTROL_TYPE_RADIOBUTTON: 5124 case THEME_CONTROL_TYPE_RADIOBUTTON:
5261 if (pTheme->pfnSetStringVariable && pControl->sczVariable && *pControl->sczVariable && ThemeIsControlChecked(pTheme, pControl->wId)) 5125 if (pTheme->pfnSetStringVariable && pControl->sczVariable && *pControl->sczVariable && ThemeIsControlChecked(pControl))
5262 { 5126 {
5263 pTheme->pfnSetStringVariable(pControl->sczVariable, pControl->sczValue, FALSE, pTheme->pvVariableContext); 5127 pTheme->pfnSetStringVariable(pControl->sczVariable, pControl->sczValue, FALSE, pTheme->pvVariableContext);
5264 fRefresh = TRUE; 5128 fRefresh = TRUE;
@@ -5386,6 +5250,42 @@ LExit:
5386 return fProcessed; 5250 return fProcessed;
5387} 5251}
5388 5252
5253static const THEME_CONTROL* FindControlFromId(
5254 __in const THEME* pTheme,
5255 __in WORD wId,
5256 __in_opt const THEME_CONTROL* pParentControl
5257 )
5258{
5259 DWORD cControls = 0;
5260 THEME_CONTROL* rgControls = NULL;
5261 const THEME_CONTROL* pChildControl = NULL;
5262
5263 GetControls(pTheme, pParentControl, cControls, rgControls);
5264
5265 // Breadth first search since control ids are technically only valid for direct child windows of a specific parent window.
5266 for (DWORD i = 0; i < cControls; ++i)
5267 {
5268 if (wId == rgControls[i].wId)
5269 {
5270 return rgControls + i;
5271 }
5272 }
5273
5274 for (DWORD i = 0; i < cControls; ++i)
5275 {
5276 if (0 < rgControls[i].cControls)
5277 {
5278 pChildControl = FindControlFromId(pTheme, wId, rgControls + i);
5279 if (pChildControl)
5280 {
5281 return pChildControl;
5282 }
5283 }
5284 }
5285
5286 return NULL;
5287}
5288
5389static BOOL OnNotifyEnMsgFilter( 5289static BOOL OnNotifyEnMsgFilter(
5390 __in THEME* pTheme, 5290 __in THEME* pTheme,
5391 __in const THEME_CONTROL* pThemeControl, 5291 __in const THEME_CONTROL* pThemeControl,
@@ -5638,7 +5538,6 @@ LExit:
5638 5538
5639 5539
5640static HRESULT ShowControl( 5540static HRESULT ShowControl(
5641 __in THEME* pTheme,
5642 __in THEME_CONTROL* pControl, 5541 __in THEME_CONTROL* pControl,
5643 __in int nCmdShow, 5542 __in int nCmdShow,
5644 __in BOOL fSaveEditboxes, 5543 __in BOOL fSaveEditboxes,
@@ -5654,13 +5553,14 @@ static HRESULT ShowControl(
5654 LPWSTR sczText = NULL; 5553 LPWSTR sczText = NULL;
5655 THEME_SAVEDVARIABLE* pSavedVariable = NULL; 5554 THEME_SAVEDVARIABLE* pSavedVariable = NULL;
5656 BOOL fHide = SW_HIDE == nCmdShow; 5555 BOOL fHide = SW_HIDE == nCmdShow;
5556 THEME* pTheme = pControl->pTheme;
5657 THEME_PAGE* pPage = ThemeGetPage(pTheme, dwPageId); 5557 THEME_PAGE* pPage = ThemeGetPage(pTheme, dwPageId);
5658 5558
5659 // Save the editbox value if necessary (other control types save their values immediately). 5559 // Save the editbox value if necessary (other control types save their values immediately).
5660 if (pTheme->pfnSetStringVariable && !pControl->fDisableVariableFunctionality && 5560 if (pTheme->pfnSetStringVariable && !pControl->fDisableVariableFunctionality &&
5661 fSaveEditboxes && THEME_CONTROL_TYPE_EDITBOX == pControl->type && pControl->sczName && *pControl->sczName) 5561 fSaveEditboxes && THEME_CONTROL_TYPE_EDITBOX == pControl->type && pControl->sczName && *pControl->sczName)
5662 { 5562 {
5663 hr = ThemeGetTextControl(pTheme, pControl->wId, &sczText); 5563 hr = ThemeGetTextControl(pControl, &sczText);
5664 ThmExitOnFailure(hr, "Failed to get the text for control: %ls", pControl->sczName); 5564 ThmExitOnFailure(hr, "Failed to get the text for control: %ls", pControl->sczName);
5665 5565
5666 hr = pTheme->pfnSetStringVariable(pControl->sczName, sczText, FALSE, pTheme->pvVariableContext); 5566 hr = pTheme->pfnSetStringVariable(pControl->sczName, sczText, FALSE, pTheme->pvVariableContext);
@@ -5675,7 +5575,7 @@ static HRESULT ShowControl(
5675 5575
5676 if (THEME_CONTROL_TYPE_BILLBOARD == pControl->type) 5576 if (THEME_CONTROL_TYPE_BILLBOARD == pControl->type)
5677 { 5577 {
5678 StopBillboard(pTheme, pControl->wId); 5578 StopBillboard(pTheme, pControl);
5679 } 5579 }
5680 5580
5681 ExitFunction(); 5581 ExitFunction();
@@ -5767,7 +5667,7 @@ static HRESULT ShowControl(
5767 ReleaseNullStr(sczText); 5667 ReleaseNullStr(sczText);
5768 } 5668 }
5769 5669
5770 ThemeSetTextControl(pTheme, pControl->wId, sczText); 5670 ThemeSetTextControl(pControl, sczText);
5771 5671
5772 if (wzNote && *wzNote) 5672 if (wzNote && *wzNote)
5773 { 5673 {
@@ -5811,7 +5711,7 @@ static HRESULT ShowControl(
5811 ++iPageControl; 5711 ++iPageControl;
5812 } 5712 }
5813 5713
5814 ThemeSendControlMessage(pTheme, pControl->wId, BM_SETCHECK, SUCCEEDED(hr) && llValue ? BST_CHECKED : BST_UNCHECKED, 0); 5714 ::SendMessageW(pControl->hWnd, BM_SETCHECK, SUCCEEDED(hr) && llValue ? BST_CHECKED : BST_UNCHECKED, 0);
5815 } 5715 }
5816 5716
5817 // If this is an editbox control, 5717 // If this is an editbox control,
@@ -5838,7 +5738,7 @@ static HRESULT ShowControl(
5838 ++iPageControl; 5738 ++iPageControl;
5839 } 5739 }
5840 5740
5841 ThemeSetTextControl(pTheme, pControl->wId, sczText); 5741 ThemeSetTextControl(pControl, sczText);
5842 } 5742 }
5843 } 5743 }
5844 5744
@@ -5901,11 +5801,11 @@ static HRESULT ShowControl(
5901 { 5801 {
5902 if (fEnabled) 5802 if (fEnabled)
5903 { 5803 {
5904 StartBillboard(pTheme, pControl->wId); 5804 StartBillboard(pTheme, pControl);
5905 } 5805 }
5906 else 5806 else
5907 { 5807 {
5908 StopBillboard(pTheme, pControl->wId); 5808 StopBillboard(pTheme, pControl);
5909 } 5809 }
5910 } 5810 }
5911 5811
@@ -5944,7 +5844,7 @@ static HRESULT ShowControls(
5944 // Only look at non-page controls and the specified page's controls. 5844 // Only look at non-page controls and the specified page's controls.
5945 if (!pControl->wPageId || pControl->wPageId == dwPageId) 5845 if (!pControl->wPageId || pControl->wPageId == dwPageId)
5946 { 5846 {
5947 hr = ShowControl(pTheme, pControl, nCmdShow, fSaveEditboxes, reason, dwPageId, &hwndFocus); 5847 hr = ShowControl(pControl, nCmdShow, fSaveEditboxes, reason, dwPageId, &hwndFocus);
5948 ThmExitOnFailure(hr, "Failed to show control '%ls' at index %d.", pControl->sczName, i); 5848 ThmExitOnFailure(hr, "Failed to show control '%ls' at index %d.", pControl->sczName, i);
5949 } 5849 }
5950 } 5850 }
@@ -6509,7 +6409,7 @@ static HRESULT LoadControls(
6509 HRESULT hrFormat = pTheme->pfnFormatString(pControl->sczText, &sczText, pTheme->pvVariableContext); 6409 HRESULT hrFormat = pTheme->pfnFormatString(pControl->sczText, &sczText, pTheme->pvVariableContext);
6510 if (SUCCEEDED(hrFormat)) 6410 if (SUCCEEDED(hrFormat))
6511 { 6411 {
6512 ThemeSetTextControl(pTheme, pControl->wId, sczText); 6412 ThemeSetTextControl(pControl, sczText);
6513 } 6413 }
6514 } 6414 }
6515 6415
diff --git a/src/libs/dutil/WixToolset.DUtil/wndutil.cpp b/src/libs/dutil/WixToolset.DUtil/wndutil.cpp
new file mode 100644
index 00000000..b75b0491
--- /dev/null
+++ b/src/libs/dutil/WixToolset.DUtil/wndutil.cpp
@@ -0,0 +1,206 @@
1// 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.
2
3#include "precomp.h"
4
5
6// Exit macros
7#define WnduExitOnLastError(x, s, ...) ExitOnLastErrorSource(DUTIL_SOURCE_WNDUTIL, x, s, __VA_ARGS__)
8#define WnduExitOnLastErrorDebugTrace(x, s, ...) ExitOnLastErrorDebugTraceSource(DUTIL_SOURCE_WNDUTIL, x, s, __VA_ARGS__)
9#define WnduExitWithLastError(x, s, ...) ExitWithLastErrorSource(DUTIL_SOURCE_WNDUTIL, x, s, __VA_ARGS__)
10#define WnduExitOnFailure(x, s, ...) ExitOnFailureSource(DUTIL_SOURCE_WNDUTIL, x, s, __VA_ARGS__)
11#define WnduExitOnRootFailure(x, s, ...) ExitOnRootFailureSource(DUTIL_SOURCE_WNDUTIL, x, s, __VA_ARGS__)
12#define WnduExitWithRootFailure(x, e, s, ...) ExitWithRootFailureSource(DUTIL_SOURCE_WNDUTIL, x, e, s, __VA_ARGS__)
13#define WnduExitOnFailureDebugTrace(x, s, ...) ExitOnFailureDebugTraceSource(DUTIL_SOURCE_WNDUTIL, x, s, __VA_ARGS__)
14#define WnduExitOnNull(p, x, e, s, ...) ExitOnNullSource(DUTIL_SOURCE_WNDUTIL, p, x, e, s, __VA_ARGS__)
15#define WnduExitOnNullWithLastError(p, x, s, ...) ExitOnNullWithLastErrorSource(DUTIL_SOURCE_WNDUTIL, p, x, s, __VA_ARGS__)
16#define WnduExitOnNullDebugTrace(p, x, e, s, ...) ExitOnNullDebugTraceSource(DUTIL_SOURCE_WNDUTIL, p, x, e, s, __VA_ARGS__)
17#define WnduExitOnInvalidHandleWithLastError(p, x, s, ...) ExitOnInvalidHandleWithLastErrorSource(DUTIL_SOURCE_WNDUTIL, p, x, s, __VA_ARGS__)
18#define WnduExitOnWin32Error(e, x, s, ...) ExitOnWin32ErrorSource(DUTIL_SOURCE_WNDUTIL, e, x, s, __VA_ARGS__)
19#define WnduExitOnOptionalXmlQueryFailure(x, b, s, ...) ExitOnOptionalXmlQueryFailureSource(DUTIL_SOURCE_WNDUTIL, x, b, s, __VA_ARGS__)
20#define WnduExitOnRequiredXmlQueryFailure(x, s, ...) ExitOnRequiredXmlQueryFailureSource(DUTIL_SOURCE_WNDUTIL, x, s, __VA_ARGS__)
21#define WnduExitOnGdipFailure(g, x, s, ...) ExitOnGdipFailureSource(DUTIL_SOURCE_WNDUTIL, g, x, s, __VA_ARGS__)
22
23struct MEMBUFFER_FOR_RICHEDIT
24{
25 BYTE* rgbData;
26 DWORD cbData;
27
28 DWORD iData;
29};
30
31const DWORD GROW_WINDOW_TEXT = 250;
32
33
34// prototypes
35static DWORD CALLBACK RichEditStreamFromFileHandleCallback(
36 __in DWORD_PTR dwCookie,
37 __in_bcount(cb) LPBYTE pbBuff,
38 __in LONG cb,
39 __in LONG *pcb
40 );
41static DWORD CALLBACK RichEditStreamFromMemoryCallback(
42 __in DWORD_PTR dwCookie,
43 __in_bcount(cb) LPBYTE pbBuff,
44 __in LONG cb,
45 __in LONG *pcb
46 );
47
48
49DAPI_(HRESULT) WnduLoadRichEditFromFile(
50 __in HWND hWnd,
51 __in_z LPCWSTR wzFileName,
52 __in HMODULE hModule
53 )
54{
55 HRESULT hr = S_OK;
56 LPWSTR sczFile = NULL;
57 HANDLE hFile = INVALID_HANDLE_VALUE;
58
59 hr = PathRelativeToModule(&sczFile, wzFileName, hModule);
60 WnduExitOnFailure(hr, "Failed to read resource data.");
61
62 hFile = ::CreateFileW(sczFile, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
63 if (INVALID_HANDLE_VALUE == hFile)
64 {
65 WnduExitWithLastError(hr, "Failed to open RTF file.");
66 }
67 else
68 {
69 LONGLONG llRtfSize;
70 hr = FileSizeByHandle(hFile, &llRtfSize);
71 if (SUCCEEDED(hr))
72 {
73 ::SendMessageW(hWnd, EM_EXLIMITTEXT, 0, static_cast<LPARAM>(llRtfSize));
74 }
75
76 EDITSTREAM es = { };
77 es.pfnCallback = RichEditStreamFromFileHandleCallback;
78 es.dwCookie = reinterpret_cast<DWORD_PTR>(hFile);
79
80 ::SendMessageW(hWnd, EM_STREAMIN, SF_RTF, reinterpret_cast<LPARAM>(&es));
81 hr = es.dwError;
82 WnduExitOnFailure(hr, "Failed to update RTF stream.");
83 }
84
85LExit:
86 ReleaseStr(sczFile);
87 ReleaseFile(hFile);
88
89 return hr;
90}
91
92DAPI_(HRESULT) WnduLoadRichEditFromResource(
93 __in HWND hWnd,
94 __in_z LPCSTR szResourceName,
95 __in HMODULE hModule
96 )
97{
98 HRESULT hr = S_OK;
99 MEMBUFFER_FOR_RICHEDIT buffer = { };
100 EDITSTREAM es = { };
101
102 hr = ResReadData(hModule, szResourceName, reinterpret_cast<LPVOID*>(&buffer.rgbData), &buffer.cbData);
103 WnduExitOnFailure(hr, "Failed to read resource data.");
104
105 es.pfnCallback = RichEditStreamFromMemoryCallback;
106 es.dwCookie = reinterpret_cast<DWORD_PTR>(&buffer);
107
108 ::SendMessageW(hWnd, EM_STREAMIN, SF_RTF, reinterpret_cast<LPARAM>(&es));
109 hr = es.dwError;
110 WnduExitOnFailure(hr, "Failed to update RTF stream.");
111
112LExit:
113 return hr;
114}
115
116
117DAPI_(HRESULT) WnduGetControlText(
118 __in HWND hWnd,
119 __inout_z LPWSTR* psczText
120 )
121{
122 HRESULT hr = S_OK;
123 SIZE_T cbSize = 0;
124 DWORD cchText = 0;
125 DWORD cchTextRead = 0;
126
127 // Ensure the string has room for at least one character.
128 hr = StrMaxLength(*psczText, &cbSize);
129 WnduExitOnFailure(hr, "Failed to get text buffer length.");
130
131 cchText = (DWORD)min(DWORD_MAX, cbSize);
132
133 if (!cchText)
134 {
135 cchText = GROW_WINDOW_TEXT;
136
137 hr = StrAlloc(psczText, cchText);
138 WnduExitOnFailure(hr, "Failed to grow text buffer.");
139 }
140
141 // Read (and keep growing buffer) until we finally read less than there
142 // is room in the buffer.
143 for (;;)
144 {
145 cchTextRead = ::GetWindowTextW(hWnd, *psczText, cchText);
146 if (cchTextRead + 1 < cchText)
147 {
148 break;
149 }
150 else
151 {
152 cchText = cchTextRead + GROW_WINDOW_TEXT;
153
154 hr = StrAlloc(psczText, cchText);
155 WnduExitOnFailure(hr, "Failed to grow text buffer again.");
156 }
157 }
158
159LExit:
160 return hr;
161}
162
163
164static DWORD CALLBACK RichEditStreamFromFileHandleCallback(
165 __in DWORD_PTR dwCookie,
166 __in_bcount(cb) LPBYTE pbBuff,
167 __in LONG cb,
168 __in LONG* pcb
169 )
170{
171 HRESULT hr = S_OK;
172 HANDLE hFile = reinterpret_cast<HANDLE>(dwCookie);
173
174 if (!::ReadFile(hFile, pbBuff, cb, reinterpret_cast<DWORD*>(pcb), NULL))
175 {
176 WnduExitWithLastError(hr, "Failed to read file");
177 }
178
179LExit:
180 return hr;
181}
182
183
184static DWORD CALLBACK RichEditStreamFromMemoryCallback(
185 __in DWORD_PTR dwCookie,
186 __in_bcount(cb) LPBYTE pbBuff,
187 __in LONG cb,
188 __in LONG* pcb
189 )
190{
191 HRESULT hr = S_OK;
192 MEMBUFFER_FOR_RICHEDIT* pBuffer = reinterpret_cast<MEMBUFFER_FOR_RICHEDIT*>(dwCookie);
193 DWORD cbCopy = 0;
194
195 if (pBuffer->iData < pBuffer->cbData)
196 {
197 cbCopy = min(static_cast<DWORD>(cb), pBuffer->cbData - pBuffer->iData);
198 memcpy(pbBuff, pBuffer->rgbData + pBuffer->iData, cbCopy);
199
200 pBuffer->iData += cbCopy;
201 Assert(pBuffer->iData <= pBuffer->cbData);
202 }
203
204 *pcb = cbCopy;
205 return hr;
206}
diff --git a/src/samples/thmviewer/display.cpp b/src/samples/thmviewer/display.cpp
index 9ef88018..f40b50b5 100644
--- a/src/samples/thmviewer/display.cpp
+++ b/src/samples/thmviewer/display.cpp
@@ -188,7 +188,7 @@ static DWORD WINAPI DisplayThreadProc(
188 THEME_CONTROL* pControl = pCurrentHandle->pTheme->rgControls + i; 188 THEME_CONTROL* pControl = pCurrentHandle->pTheme->rgControls + i;
189 if (!pControl->wPageId) 189 if (!pControl->wPageId)
190 { 190 {
191 ThemeShowControl(pCurrentHandle->pTheme, pControl->wId, nCmdShow); 191 ThemeShowControl(pControl, nCmdShow);
192 } 192 }
193 } 193 }
194 194
@@ -264,7 +264,7 @@ static LRESULT CALLBACK DisplayWndProc(
264 break; 264 break;
265 265
266 case WM_TIMER: 266 case WM_TIMER:
267 if (!lParam && SUCCEEDED(ThemeSetProgressControl(pHandleTheme->pTheme, wParam, dwProgress))) 267 if (!lParam && SUCCEEDED(ThemeSetProgressControl(reinterpret_cast<THEME_CONTROL*>(wParam), dwProgress)))
268 { 268 {
269 dwProgress += rand() % 10 + 1; 269 dwProgress += rand() % 10 + 1;
270 if (dwProgress > 100) 270 if (dwProgress > 100)
@@ -322,12 +322,12 @@ static BOOL DisplayOnThmLoadedControl(
322 // Pre-populate some control types with data. 322 // Pre-populate some control types with data.
323 if (THEME_CONTROL_TYPE_RICHEDIT == pControl->type) 323 if (THEME_CONTROL_TYPE_RICHEDIT == pControl->type)
324 { 324 {
325 hr = ThemeLoadRichEditFromResource(pTheme, pControl->wId, MAKEINTRESOURCEA(THMVWR_RES_RICHEDIT_FILE), ::GetModuleHandleW(NULL)); 325 hr = WnduLoadRichEditFromResource(pControl->hWnd, MAKEINTRESOURCEA(THMVWR_RES_RICHEDIT_FILE), ::GetModuleHandleW(NULL));
326 ExitOnFailure(hr, "Failed to load richedit text."); 326 ExitOnFailure(hr, "Failed to load richedit text.");
327 } 327 }
328 else if (THEME_CONTROL_TYPE_PROGRESSBAR == pControl->type) 328 else if (THEME_CONTROL_TYPE_PROGRESSBAR == pControl->type)
329 { 329 {
330 DWORD dwId = ::SetTimer(pTheme->hwndParent, pControl->wId, 500, NULL); 330 DWORD dwId = ::SetTimer(pTheme->hwndParent, reinterpret_cast<UINT_PTR>(pControl), 500, NULL);
331 dwId = dwId; // prevents warning in "ship" build. 331 dwId = dwId; // prevents warning in "ship" build.
332 Assert(dwId == pControl->wId); 332 Assert(dwId == pControl->wId);
333 } 333 }
diff --git a/src/samples/thmviewer/precomp.h b/src/samples/thmviewer/precomp.h
index f11d3534..762a0623 100644
--- a/src/samples/thmviewer/precomp.h
+++ b/src/samples/thmviewer/precomp.h
@@ -28,6 +28,7 @@
28#include "shelutil.h" 28#include "shelutil.h"
29#include "strutil.h" 29#include "strutil.h"
30#include "thmutil.h" 30#include "thmutil.h"
31#include "wndutil.h"
31 32
32#include "resource.h" 33#include "resource.h"
33 34
diff --git a/src/samples/thmviewer/thmviewer.cpp b/src/samples/thmviewer/thmviewer.cpp
index 94b1ef55..38f3c4dc 100644
--- a/src/samples/thmviewer/thmviewer.cpp
+++ b/src/samples/thmviewer/thmviewer.cpp
@@ -390,6 +390,12 @@ static void OnThemeLoadError(
390 LPWSTR* psczErrors = NULL; 390 LPWSTR* psczErrors = NULL;
391 UINT cErrors = 0; 391 UINT cErrors = 0;
392 TVINSERTSTRUCTW tvi = { }; 392 TVINSERTSTRUCTW tvi = { };
393 const THEME_CONTROL* pTreeControl = NULL;
394
395 if (!ThemeControlExistsById(pTheme, THMVWR_CONTROL_TREE, &pTreeControl))
396 {
397 ExitWithRootFailure(hr, E_INVALIDSTATE, "THMVWR_CONTROL_TREE control doesn't exist.");
398 }
393 399
394 // Add the application node. 400 // Add the application node.
395 tvi.hParent = NULL; 401 tvi.hParent = NULL;
@@ -397,7 +403,7 @@ static void OnThemeLoadError(
397 tvi.item.mask = TVIF_TEXT | TVIF_PARAM; 403 tvi.item.mask = TVIF_TEXT | TVIF_PARAM;
398 tvi.item.lParam = 0; 404 tvi.item.lParam = 0;
399 tvi.item.pszText = L"Failed to load theme."; 405 tvi.item.pszText = L"Failed to load theme.";
400 tvi.hParent = reinterpret_cast<HTREEITEM>(ThemeSendControlMessage(pTheme, THMVWR_CONTROL_TREE, TVM_INSERTITEMW, 0, reinterpret_cast<LPARAM>(&tvi))); 406 tvi.hParent = reinterpret_cast<HTREEITEM>(::SendMessage(pTreeControl->hWnd, TVM_INSERTITEMW, 0, reinterpret_cast<LPARAM>(&tvi)));
401 407
402 if (!vsczThemeLoadErrors) 408 if (!vsczThemeLoadErrors)
403 { 409 {
@@ -405,13 +411,13 @@ static void OnThemeLoadError(
405 ExitOnFailure(hr, "Failed to format error message."); 411 ExitOnFailure(hr, "Failed to format error message.");
406 412
407 tvi.item.pszText = sczMessage; 413 tvi.item.pszText = sczMessage;
408 ThemeSendControlMessage(pTheme, THMVWR_CONTROL_TREE, TVM_INSERTITEMW, 0, reinterpret_cast<LPARAM>(&tvi)); 414 ::SendMessage(pTreeControl->hWnd, TVM_INSERTITEMW, 0, reinterpret_cast<LPARAM>(&tvi));
409 415
410 hr = StrAllocFromError(&sczMessage, hrFailure, NULL); 416 hr = StrAllocFromError(&sczMessage, hrFailure, NULL);
411 ExitOnFailure(hr, "Failed to format error message text."); 417 ExitOnFailure(hr, "Failed to format error message text.");
412 418
413 tvi.item.pszText = sczMessage; 419 tvi.item.pszText = sczMessage;
414 ThemeSendControlMessage(pTheme, THMVWR_CONTROL_TREE, TVM_INSERTITEMW, 0, reinterpret_cast<LPARAM>(&tvi)); 420 ::SendMessage(pTreeControl->hWnd, TVM_INSERTITEMW, 0, reinterpret_cast<LPARAM>(&tvi));
415 } 421 }
416 else 422 else
417 { 423 {
@@ -421,11 +427,11 @@ static void OnThemeLoadError(
421 for (DWORD i = 0; i < cErrors; ++i) 427 for (DWORD i = 0; i < cErrors; ++i)
422 { 428 {
423 tvi.item.pszText = psczErrors[i]; 429 tvi.item.pszText = psczErrors[i];
424 ThemeSendControlMessage(pTheme, THMVWR_CONTROL_TREE, TVM_INSERTITEMW, 0, reinterpret_cast<LPARAM>(&tvi)); 430 ::SendMessage(pTreeControl->hWnd, TVM_INSERTITEMW, 0, reinterpret_cast<LPARAM>(&tvi));
425 } 431 }
426 } 432 }
427 433
428 ThemeSendControlMessage(pTheme, THMVWR_CONTROL_TREE, TVM_EXPAND, TVE_EXPAND, reinterpret_cast<LPARAM>(tvi.hParent)); 434 ::SendMessage(pTreeControl->hWnd, TVM_EXPAND, TVE_EXPAND, reinterpret_cast<LPARAM>(tvi.hParent));
429 435
430LExit: 436LExit:
431 ReleaseStr(sczMessage); 437 ReleaseStr(sczMessage);
@@ -439,6 +445,7 @@ static void OnNewTheme(
439 __in HANDLE_THEME* pHandle 445 __in HANDLE_THEME* pHandle
440 ) 446 )
441{ 447{
448 const THEME_CONTROL* pTreeControl = NULL;
442 HANDLE_THEME* pOldHandle = reinterpret_cast<HANDLE_THEME*>(::GetWindowLongPtrW(hWnd, GWLP_USERDATA)); 449 HANDLE_THEME* pOldHandle = reinterpret_cast<HANDLE_THEME*>(::GetWindowLongPtrW(hWnd, GWLP_USERDATA));
443 THEME* pNewTheme = pHandle->pTheme; 450 THEME* pNewTheme = pHandle->pTheme;
444 451
@@ -460,17 +467,23 @@ static void OnNewTheme(
460 467
461 ::SetWindowLongPtrW(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pHandle)); 468 ::SetWindowLongPtrW(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pHandle));
462 469
470 if (!ThemeControlExistsById(pTheme, THMVWR_CONTROL_TREE, &pTreeControl))
471 {
472 TraceError(E_INVALIDSTATE, "Tree control doesn't exist.");
473 return;
474 }
475
463 // Remember the currently selected item by name so we can try to automatically select it later. 476 // Remember the currently selected item by name so we can try to automatically select it later.
464 // Otherwise, the user would see their window destroyed after every save of their theme file and 477 // Otherwise, the user would see their window destroyed after every save of their theme file and
465 // have to click to get the window back. 478 // have to click to get the window back.
466 item.mask = TVIF_TEXT; 479 item.mask = TVIF_TEXT;
467 item.pszText = wzSelectedPage; 480 item.pszText = wzSelectedPage;
468 item.cchTextMax = countof(wzSelectedPage); 481 item.cchTextMax = countof(wzSelectedPage);
469 item.hItem = reinterpret_cast<HTREEITEM>(ThemeSendControlMessage(pTheme, THMVWR_CONTROL_TREE, TVM_GETNEXTITEM, TVGN_CARET, NULL)); 482 item.hItem = reinterpret_cast<HTREEITEM>(::SendMessage(pTreeControl->hWnd, TVM_GETNEXTITEM, TVGN_CARET, NULL));
470 ThemeSendControlMessage(pTheme, THMVWR_CONTROL_TREE, TVM_GETITEM, 0, reinterpret_cast<LPARAM>(&item)); 483 ::SendMessage(pTreeControl->hWnd, TVM_GETITEM, 0, reinterpret_cast<LPARAM>(&item));
471 484
472 // Remove the previous items in the tree. 485 // Remove the previous items in the tree.
473 ThemeSendControlMessage(pTheme, THMVWR_CONTROL_TREE, TVM_DELETEITEM, 0, reinterpret_cast<LPARAM>(TVI_ROOT)); 486 ::SendMessage(pTreeControl->hWnd, TVM_DELETEITEM, 0, reinterpret_cast<LPARAM>(TVI_ROOT));
474 487
475 // Add the application node. 488 // Add the application node.
476 tvi.hParent = NULL; 489 tvi.hParent = NULL;
@@ -480,7 +493,7 @@ static void OnNewTheme(
480 tvi.item.pszText = pHandle && pHandle->pTheme && pHandle->pTheme->sczCaption ? pHandle->pTheme->sczCaption : L"Window"; 493 tvi.item.pszText = pHandle && pHandle->pTheme && pHandle->pTheme->sczCaption ? pHandle->pTheme->sczCaption : L"Window";
481 494
482 // Add the pages. 495 // Add the pages.
483 tvi.hParent = reinterpret_cast<HTREEITEM>(ThemeSendControlMessage(pTheme, THMVWR_CONTROL_TREE, TVM_INSERTITEMW, 0, reinterpret_cast<LPARAM>(&tvi))); 496 tvi.hParent = reinterpret_cast<HTREEITEM>(::SendMessage(pTreeControl->hWnd, TVM_INSERTITEMW, 0, reinterpret_cast<LPARAM>(&tvi)));
484 tvi.hInsertAfter = TVI_SORT; 497 tvi.hInsertAfter = TVI_SORT;
485 for (DWORD i = 0; i < pNewTheme->cPages; ++i) 498 for (DWORD i = 0; i < pNewTheme->cPages; ++i)
486 { 499 {
@@ -490,7 +503,7 @@ static void OnNewTheme(
490 tvi.item.pszText = pPage->sczName; 503 tvi.item.pszText = pPage->sczName;
491 tvi.item.lParam = i + 1; //prgdwPageIds[i]; - TODO: do the right thing here by calling ThemeGetPageIds(), should not assume we know how the page ids will be calculated. 504 tvi.item.lParam = i + 1; //prgdwPageIds[i]; - TODO: do the right thing here by calling ThemeGetPageIds(), should not assume we know how the page ids will be calculated.
492 505
493 HTREEITEM hti = reinterpret_cast<HTREEITEM>(ThemeSendControlMessage(pTheme, THMVWR_CONTROL_TREE, TVM_INSERTITEMW, 0, reinterpret_cast<LPARAM>(&tvi))); 506 HTREEITEM hti = reinterpret_cast<HTREEITEM>(::SendMessage(pTreeControl->hWnd, TVM_INSERTITEMW, 0, reinterpret_cast<LPARAM>(&tvi)));
494 if (*wzSelectedPage && CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, pPage->sczName, -1, wzSelectedPage, -1)) 507 if (*wzSelectedPage && CSTR_EQUAL == ::CompareStringW(LOCALE_NEUTRAL, 0, pPage->sczName, -1, wzSelectedPage, -1))
495 { 508 {
496 htiSelected = hti; 509 htiSelected = hti;
@@ -503,10 +516,10 @@ static void OnNewTheme(
503 htiSelected = tvi.hParent; 516 htiSelected = tvi.hParent;
504 } 517 }
505 518
506 ThemeSendControlMessage(pTheme, THMVWR_CONTROL_TREE, TVM_EXPAND, TVE_EXPAND, reinterpret_cast<LPARAM>(tvi.hParent)); 519 ::SendMessage(pTreeControl->hWnd, TVM_EXPAND, TVE_EXPAND, reinterpret_cast<LPARAM>(tvi.hParent));
507 if (htiSelected) 520 if (htiSelected)
508 { 521 {
509 ThemeSendControlMessage(pTheme, THMVWR_CONTROL_TREE, TVM_SELECTITEM, TVGN_CARET, reinterpret_cast<LPARAM>(htiSelected)); 522 ::SendMessage(pTreeControl->hWnd, TVM_SELECTITEM, TVGN_CARET, reinterpret_cast<LPARAM>(htiSelected));
510 } 523 }
511} 524}
512 525
diff --git a/src/test/burn/TestData/Manual/BafThmutilTesting/BafThmUtilTesting.cpp b/src/test/burn/TestData/Manual/BafThmutilTesting/BafThmUtilTesting.cpp
index b502285f..6c37fbd8 100644
--- a/src/test/burn/TestData/Manual/BafThmutilTesting/BafThmUtilTesting.cpp
+++ b/src/test/burn/TestData/Manual/BafThmutilTesting/BafThmUtilTesting.cpp
@@ -365,18 +365,23 @@ private:
365 365
366 void UpdateProgressBarProgress() 366 void UpdateProgressBarProgress()
367 { 367 {
368 const THEME_CONTROL* pControlProgressbarImage = NULL;
369 const THEME_CONTROL* pControlProgressbarStandard = NULL;
368 static DWORD dwProgress = 0; 370 static DWORD dwProgress = 0;
369 DWORD dwCurrent = dwProgress < 100 ? dwProgress : 200 - dwProgress; 371 DWORD dwCurrent = dwProgress < 100 ? dwProgress : 200 - dwProgress;
370 372
373 ThemeControlExistsById(m_pBafTheme, BAFTHMUTILTESTING_CONTROL_PROGRESSBAR_IMAGE, &pControlProgressbarImage);
374 ThemeControlExistsById(m_pBafTheme, BAFTHMUTILTESTING_CONTROL_PROGRESSBAR_STANDARD, &pControlProgressbarStandard);
375
371 if (0 == dwProgress || 100 == dwProgress) 376 if (0 == dwProgress || 100 == dwProgress)
372 { 377 {
373 ThemeSetProgressControlColor(m_pBafTheme, BAFTHMUTILTESTING_CONTROL_PROGRESSBAR_IMAGE, 100 == dwProgress ? 1 : 0); 378 ThemeSetProgressControlColor(pControlProgressbarImage, 100 == dwProgress ? 1 : 0);
374 } 379 }
375 380
376 dwProgress = (dwProgress + 10) % 200; 381 dwProgress = (dwProgress + 10) % 200;
377 382
378 ThemeSetProgressControl(m_pBafTheme, BAFTHMUTILTESTING_CONTROL_PROGRESSBAR_IMAGE, dwCurrent); 383 ThemeSetProgressControl(pControlProgressbarImage, dwCurrent);
379 ThemeSetProgressControl(m_pBafTheme, BAFTHMUTILTESTING_CONTROL_PROGRESSBAR_STANDARD, dwCurrent); 384 ThemeSetProgressControl(pControlProgressbarStandard, dwCurrent);
380 } 385 }
381 386
382public: 387public: