diff options
| author | Rob Mensching <rob@firegiant.com> | 2021-05-03 09:55:22 -0700 |
|---|---|---|
| committer | Rob Mensching <rob@firegiant.com> | 2021-05-03 09:55:22 -0700 |
| commit | ff659159e041bf6c083e6b7fcb9b726065a9dd73 (patch) | |
| tree | ea95bf3d3e031edcee65de33b9e6954178be669c /src/ext/Util/ca/test.cpp | |
| parent | 8a8a25695351ee542f08886a9d0957c78c6af366 (diff) | |
| download | wix-ff659159e041bf6c083e6b7fcb9b726065a9dd73.tar.gz wix-ff659159e041bf6c083e6b7fcb9b726065a9dd73.tar.bz2 wix-ff659159e041bf6c083e6b7fcb9b726065a9dd73.zip | |
Move Util.wixext into ext
Diffstat (limited to 'src/ext/Util/ca/test.cpp')
| -rw-r--r-- | src/ext/Util/ca/test.cpp | 269 |
1 files changed, 269 insertions, 0 deletions
diff --git a/src/ext/Util/ca/test.cpp b/src/ext/Util/ca/test.cpp new file mode 100644 index 00000000..c4d215f0 --- /dev/null +++ b/src/ext/Util/ca/test.cpp | |||
| @@ -0,0 +1,269 @@ | |||
| 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 | #define WIXCA_UITHREAD_CLASS_WINDOW L"WixCaMessageWindow" | ||
| 6 | |||
| 7 | extern HMODULE g_hInstCADLL; | ||
| 8 | |||
| 9 | |||
| 10 | // structs | ||
| 11 | |||
| 12 | struct UITHREAD_CONTEXT | ||
| 13 | { | ||
| 14 | HANDLE hInitializedEvent; | ||
| 15 | HINSTANCE hInstance; | ||
| 16 | HWND hWnd; | ||
| 17 | }; | ||
| 18 | |||
| 19 | |||
| 20 | // internal function declarations | ||
| 21 | |||
| 22 | static HRESULT CreateMessageWindow( | ||
| 23 | __out HWND* phWnd | ||
| 24 | ); | ||
| 25 | |||
| 26 | static void CloseMessageWindow( | ||
| 27 | __in HWND hWnd | ||
| 28 | ); | ||
| 29 | |||
| 30 | static DWORD WINAPI ThreadProc( | ||
| 31 | __in LPVOID pvContext | ||
| 32 | ); | ||
| 33 | |||
| 34 | static LRESULT CALLBACK WndProc( | ||
| 35 | __in HWND hWnd, | ||
| 36 | __in UINT uMsg, | ||
| 37 | __in WPARAM wParam, | ||
| 38 | __in LPARAM lParam | ||
| 39 | ); | ||
| 40 | |||
| 41 | |||
| 42 | /****************************************************************** | ||
| 43 | WixFailWhenDeferred - entry point for WixFailWhenDeferred | ||
| 44 | custom action which always fails when running as a deferred | ||
| 45 | custom action (otherwise it blindly succeeds). It's useful when | ||
| 46 | testing the rollback of deferred custom actions: Schedule it | ||
| 47 | immediately after the rollback/deferred CA pair you're testing | ||
| 48 | and it will fail, causing your rollback CA to get invoked. | ||
| 49 | ********************************************************************/ | ||
| 50 | extern "C" UINT __stdcall WixFailWhenDeferred( | ||
| 51 | __in MSIHANDLE hInstall | ||
| 52 | ) | ||
| 53 | { | ||
| 54 | return ::MsiGetMode(hInstall, MSIRUNMODE_SCHEDULED) ? ERROR_INSTALL_FAILURE : ERROR_SUCCESS; | ||
| 55 | } | ||
| 56 | |||
| 57 | /****************************************************************** | ||
| 58 | WixWaitForEvent - entry point for WixWaitForEvent custom action | ||
| 59 | which waits for either the WixWaitForEventFail or | ||
| 60 | WixWaitForEventSucceed named auto reset events. Signaling the | ||
| 61 | WixWaitForEventFail event will return ERROR_INSTALL_FAILURE or | ||
| 62 | signaling the WixWaitForEventSucceed event will return | ||
| 63 | ERROR_SUCCESS. Both events are declared in the Global\ namespace. | ||
| 64 | ********************************************************************/ | ||
| 65 | extern "C" UINT __stdcall WixWaitForEvent( | ||
| 66 | __in MSIHANDLE hInstall | ||
| 67 | ) | ||
| 68 | { | ||
| 69 | HRESULT hr = S_OK; | ||
| 70 | UINT er = ERROR_SUCCESS; | ||
| 71 | HWND hMessageWindow = NULL; | ||
| 72 | LPCWSTR wzSDDL = L"D:(A;;GA;;;WD)"; | ||
| 73 | OS_VERSION version = OS_VERSION_UNKNOWN; | ||
| 74 | DWORD dwServicePack = 0; | ||
| 75 | PSECURITY_DESCRIPTOR pSD = NULL; | ||
| 76 | SECURITY_ATTRIBUTES sa = { }; | ||
| 77 | HANDLE rghEvents[2]; | ||
| 78 | |||
| 79 | hr = WcaInitialize(hInstall, "WixWaitForEvent"); | ||
| 80 | ExitOnFailure(hr, "Failed to initialize."); | ||
| 81 | |||
| 82 | // Create a window to prevent shutdown requests. | ||
| 83 | hr = CreateMessageWindow(&hMessageWindow); | ||
| 84 | ExitOnFailure(hr, "Failed to create message window."); | ||
| 85 | |||
| 86 | // If running on Vista/2008 or newer use integrity enhancements. | ||
| 87 | OsGetVersion(&version, &dwServicePack); | ||
| 88 | if (OS_VERSION_VISTA <= version) | ||
| 89 | { | ||
| 90 | // Add SACL to allow Everyone to signal from a medium integrity level. | ||
| 91 | wzSDDL = L"D:(A;;GA;;;WD)S:(ML;;NW;;;ME)"; | ||
| 92 | } | ||
| 93 | |||
| 94 | // Create the security descriptor and attributes for the events. | ||
| 95 | if (!::ConvertStringSecurityDescriptorToSecurityDescriptorW(wzSDDL, SDDL_REVISION_1, &pSD, NULL)) | ||
| 96 | { | ||
| 97 | ExitWithLastError(hr, "Failed to create the security descriptor for the events."); | ||
| 98 | } | ||
| 99 | |||
| 100 | sa.nLength = sizeof(sa); | ||
| 101 | sa.lpSecurityDescriptor = pSD; | ||
| 102 | sa.bInheritHandle = FALSE; | ||
| 103 | |||
| 104 | rghEvents[0] = ::CreateEventW(&sa, FALSE, FALSE, L"Global\\WixWaitForEventFail"); | ||
| 105 | ExitOnNullWithLastError(rghEvents[0], hr, "Failed to create the Global\\WixWaitForEventFail event."); | ||
| 106 | |||
| 107 | rghEvents[1] = ::CreateEventW(&sa, FALSE, FALSE, L"Global\\WixWaitForEventSucceed"); | ||
| 108 | ExitOnNullWithLastError(rghEvents[1], hr, "Failed to create the Global\\WixWaitForEventSucceed event."); | ||
| 109 | |||
| 110 | // Wait for either of the events to be signaled and handle accordingly. | ||
| 111 | er = ::WaitForMultipleObjects(countof(rghEvents), rghEvents, FALSE, INFINITE); | ||
| 112 | switch (er) | ||
| 113 | { | ||
| 114 | case WAIT_OBJECT_0 + 0: | ||
| 115 | er = ERROR_INSTALL_FAILURE; | ||
| 116 | break; | ||
| 117 | case WAIT_OBJECT_0 + 1: | ||
| 118 | er = ERROR_SUCCESS; | ||
| 119 | break; | ||
| 120 | default: | ||
| 121 | ExitOnWin32Error(er, hr, "Unexpected failure."); | ||
| 122 | } | ||
| 123 | |||
| 124 | LExit: | ||
| 125 | ReleaseHandle(rghEvents[1]); | ||
| 126 | ReleaseHandle(rghEvents[0]); | ||
| 127 | |||
| 128 | if (pSD) | ||
| 129 | { | ||
| 130 | ::LocalFree(pSD); | ||
| 131 | } | ||
| 132 | |||
| 133 | if (hMessageWindow) | ||
| 134 | { | ||
| 135 | CloseMessageWindow(hMessageWindow); | ||
| 136 | } | ||
| 137 | |||
| 138 | if (FAILED(hr)) | ||
| 139 | { | ||
| 140 | er = ERROR_INSTALL_FAILURE; | ||
| 141 | } | ||
| 142 | |||
| 143 | return WcaFinalize(er); | ||
| 144 | } | ||
| 145 | |||
| 146 | |||
| 147 | // internal function definitions | ||
| 148 | |||
| 149 | static HRESULT CreateMessageWindow( | ||
| 150 | __out HWND* phWnd | ||
| 151 | ) | ||
| 152 | { | ||
| 153 | HRESULT hr = S_OK; | ||
| 154 | HANDLE rgWaitHandles[2] = { }; | ||
| 155 | UITHREAD_CONTEXT context = { }; | ||
| 156 | |||
| 157 | // Create event to signal after the UI thread / window is initialized. | ||
| 158 | rgWaitHandles[0] = ::CreateEventW(NULL, TRUE, FALSE, NULL); | ||
| 159 | ExitOnNullWithLastError(rgWaitHandles[0], hr, "Failed to create initialization event."); | ||
| 160 | |||
| 161 | // Pass necessary information to create the window. | ||
| 162 | context.hInitializedEvent = rgWaitHandles[0]; | ||
| 163 | context.hInstance = (HINSTANCE)g_hInstCADLL; | ||
| 164 | |||
| 165 | // Create our separate UI thread. | ||
| 166 | rgWaitHandles[1] = ::CreateThread(NULL, 0, ThreadProc, &context, 0, NULL); | ||
| 167 | ExitOnNullWithLastError(rgWaitHandles[1], hr, "Failed to create the UI thread."); | ||
| 168 | |||
| 169 | // Wait for either the thread to be initialized or the window to exit / fail prematurely. | ||
| 170 | ::WaitForMultipleObjects(countof(rgWaitHandles), rgWaitHandles, FALSE, INFINITE); | ||
| 171 | |||
| 172 | // Pass the window back to the caller. | ||
| 173 | *phWnd = context.hWnd; | ||
| 174 | |||
| 175 | LExit: | ||
| 176 | ReleaseHandle(rgWaitHandles[1]); | ||
| 177 | ReleaseHandle(rgWaitHandles[0]); | ||
| 178 | |||
| 179 | return hr; | ||
| 180 | } | ||
| 181 | |||
| 182 | static void CloseMessageWindow( | ||
| 183 | __in HWND hWnd | ||
| 184 | ) | ||
| 185 | { | ||
| 186 | if (::IsWindow(hWnd)) | ||
| 187 | { | ||
| 188 | ::PostMessageW(hWnd, WM_CLOSE, 0, 0); | ||
| 189 | } | ||
| 190 | } | ||
| 191 | |||
| 192 | static DWORD WINAPI ThreadProc( | ||
| 193 | __in LPVOID pvContext | ||
| 194 | ) | ||
| 195 | { | ||
| 196 | HRESULT hr = S_OK; | ||
| 197 | UITHREAD_CONTEXT* pContext = static_cast<UITHREAD_CONTEXT*>(pvContext); | ||
| 198 | |||
| 199 | WNDCLASSW wc = { }; | ||
| 200 | BOOL fRegistered = TRUE; | ||
| 201 | HWND hWnd = NULL; | ||
| 202 | |||
| 203 | BOOL fRet = FALSE; | ||
| 204 | MSG msg = { }; | ||
| 205 | |||
| 206 | wc.lpfnWndProc = WndProc; | ||
| 207 | wc.hInstance = pContext->hInstance; | ||
| 208 | wc.lpszClassName = WIXCA_UITHREAD_CLASS_WINDOW; | ||
| 209 | |||
| 210 | if (!::RegisterClassW(&wc)) | ||
| 211 | { | ||
| 212 | ExitWithLastError(hr, "Failed to register window."); | ||
| 213 | } | ||
| 214 | |||
| 215 | fRegistered = TRUE; | ||
| 216 | |||
| 217 | // Create the window to handle reboots without activating it. | ||
| 218 | hWnd = ::CreateWindowExW(WS_EX_TOOLWINDOW, wc.lpszClassName, NULL, WS_POPUP | WS_VISIBLE, CW_USEDEFAULT, SW_SHOWNA, 0, 0, HWND_DESKTOP, NULL, pContext->hInstance, NULL); | ||
| 219 | ExitOnNullWithLastError(hWnd, hr, "Failed to create window."); | ||
| 220 | |||
| 221 | // Persist the window handle and let the caller know we've initialized. | ||
| 222 | pContext->hWnd = hWnd; | ||
| 223 | ::SetEvent(pContext->hInitializedEvent); | ||
| 224 | |||
| 225 | // Pump messages until the window is closed. | ||
| 226 | while (0 != (fRet = ::GetMessageW(&msg, NULL, 0, 0))) | ||
| 227 | { | ||
| 228 | if (-1 == fRet) | ||
| 229 | { | ||
| 230 | hr = E_UNEXPECTED; | ||
| 231 | ExitOnFailure(hr, "Unexpected return value from message pump."); | ||
| 232 | } | ||
| 233 | else if (!::IsDialogMessageW(msg.hwnd, &msg)) | ||
| 234 | { | ||
| 235 | ::TranslateMessage(&msg); | ||
| 236 | ::DispatchMessageW(&msg); | ||
| 237 | } | ||
| 238 | } | ||
| 239 | |||
| 240 | LExit: | ||
| 241 | if (fRegistered) | ||
| 242 | { | ||
| 243 | ::UnregisterClassW(WIXCA_UITHREAD_CLASS_WINDOW, pContext->hInstance); | ||
| 244 | } | ||
| 245 | |||
| 246 | return hr; | ||
| 247 | } | ||
| 248 | |||
| 249 | static LRESULT CALLBACK WndProc( | ||
| 250 | __in HWND hWnd, | ||
| 251 | __in UINT uMsg, | ||
| 252 | __in WPARAM wParam, | ||
| 253 | __in LPARAM lParam | ||
| 254 | ) | ||
| 255 | { | ||
| 256 | switch (uMsg) | ||
| 257 | { | ||
| 258 | case WM_QUERYENDSESSION: | ||
| 259 | // Prevent the process from being shut down. | ||
| 260 | WcaLog(LOGMSG_VERBOSE, "Disallowed system request to shut down the custom action server."); | ||
| 261 | return FALSE; | ||
| 262 | |||
| 263 | case WM_DESTROY: | ||
| 264 | ::PostQuitMessage(0); | ||
| 265 | return 0; | ||
| 266 | } | ||
| 267 | |||
| 268 | return ::DefWindowProcW(hWnd, uMsg, wParam, lParam); | ||
| 269 | } | ||
