summaryrefslogtreecommitdiff
path: root/src/libs
diff options
context:
space:
mode:
authorSean Hall <r.sean.hall@gmail.com>2022-06-29 10:28:53 -0500
committerSean Hall <r.sean.hall@gmail.com>2022-06-29 15:08:37 -0500
commit7cca75c8e95f129a21c33f1f4568e90e9e397f9d (patch)
treecb9890caa1ac8bc891d444b6376a5e9f997ca1e3 /src/libs
parent3ff6428a068bafd74d8ec072a5fc261c33cc2019 (diff)
downloadwix-7cca75c8e95f129a21c33f1f4568e90e9e397f9d.tar.gz
wix-7cca75c8e95f129a21c33f1f4568e90e9e397f9d.tar.bz2
wix-7cca75c8e95f129a21c33f1f4568e90e9e397f9d.zip
Add AppWaitForSingleObject/MultipleObjects, ThreadWaitForCompletion.
Diffstat (limited to 'src/libs')
-rw-r--r--src/libs/dutil/WixToolset.DUtil/apputil.cpp68
-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/apputil.h21
-rw-r--r--src/libs/dutil/WixToolset.DUtil/inc/dutil.h2
-rw-r--r--src/libs/dutil/WixToolset.DUtil/inc/dutilsources.h1
-rw-r--r--src/libs/dutil/WixToolset.DUtil/inc/procutil.h2
-rw-r--r--src/libs/dutil/WixToolset.DUtil/inc/thrdutil.h22
-rw-r--r--src/libs/dutil/WixToolset.DUtil/monutil.cpp34
-rw-r--r--src/libs/dutil/WixToolset.DUtil/precomp.h1
-rw-r--r--src/libs/dutil/WixToolset.DUtil/procutil.cpp42
-rw-r--r--src/libs/dutil/WixToolset.DUtil/thrdutil.cpp46
-rw-r--r--src/libs/dutil/test/DUtilUnitTest/AppUtilTests.cpp60
-rw-r--r--src/libs/dutil/test/DUtilUnitTest/DUtilUnitTest.vcxproj1
-rw-r--r--src/libs/dutil/test/DUtilUnitTest/DUtilUnitTest.vcxproj.filters3
-rw-r--r--src/libs/dutil/test/DUtilUnitTest/precomp.h1
16 files changed, 269 insertions, 43 deletions
diff --git a/src/libs/dutil/WixToolset.DUtil/apputil.cpp b/src/libs/dutil/WixToolset.DUtil/apputil.cpp
index 9e75082a..42f589dc 100644
--- a/src/libs/dutil/WixToolset.DUtil/apputil.cpp
+++ b/src/libs/dutil/WixToolset.DUtil/apputil.cpp
@@ -313,6 +313,74 @@ LExit:
313 return hr; 313 return hr;
314} 314}
315 315
316DAPI_(HRESULT) AppWaitForSingleObject(
317 __in HANDLE hHandle,
318 __in DWORD dwMilliseconds
319 )
320{
321 HRESULT hr = S_OK;
322 DWORD dwResult = 0;
323
324 dwResult = ::WaitForSingleObject(hHandle, dwMilliseconds);
325 if (WAIT_TIMEOUT == dwResult)
326 {
327 ExitFunction1(hr = HRESULT_FROM_WIN32(dwResult));
328 }
329 else if (WAIT_ABANDONED == dwResult)
330 {
331 AppExitOnWin32Error(dwResult, hr, "Abandoned wait for single object.");
332 }
333 else if (WAIT_OBJECT_0 != dwResult)
334 {
335 AssertSz(WAIT_FAILED == dwResult, "Unexpected return code from WaitForSingleObject.");
336 AppExitWithLastError(hr, "Failed to wait for single object.");
337 }
338
339LExit:
340 return hr;
341}
342
343DAPI_(HRESULT) AppWaitForMultipleObjects(
344 __in DWORD dwCount,
345 __in const HANDLE* rghHandles,
346 __in BOOL fWaitAll,
347 __in DWORD dwMilliseconds,
348 __out_opt DWORD* pdwSignaledIndex
349 )
350{
351 HRESULT hr = S_OK;
352 DWORD dwResult = 0;
353 DWORD dwSignaledIndex = dwCount;
354
355 dwResult = ::WaitForMultipleObjects(dwCount, rghHandles, fWaitAll, dwMilliseconds);
356 if (WAIT_TIMEOUT == dwResult)
357 {
358 ExitFunction1(hr = HRESULT_FROM_WIN32(dwResult));
359 }
360 else if (WAIT_ABANDONED_0 <= dwResult && (WAIT_ABANDONED_0 + dwCount) > dwResult)
361 {
362 dwSignaledIndex = dwResult - WAIT_ABANDONED_0;
363 AppExitOnWin32Error(dwResult, hr, "Abandoned wait for multiple objects, index: %u.", dwSignaledIndex);
364 }
365 else if (WAIT_OBJECT_0 <= dwResult && (WAIT_OBJECT_0 + dwCount) > dwResult)
366 {
367 dwSignaledIndex = dwResult - WAIT_OBJECT_0;
368 }
369 else
370 {
371 AssertSz(WAIT_FAILED == dwResult, "Unexpected return code from WaitForMultipleObjects.");
372 AppExitWithLastError(hr, "Failed to wait for multiple objects.");
373 }
374
375LExit:
376 if (pdwSignaledIndex)
377 {
378 *pdwSignaledIndex = dwSignaledIndex;
379 }
380
381 return hr;
382}
383
316static HRESULT EscapeCommandLineArgument( 384static HRESULT EscapeCommandLineArgument(
317 __in_z LPCWSTR wzArgument, 385 __in_z LPCWSTR wzArgument,
318 __out_z LPWSTR* psczEscaped 386 __out_z LPWSTR* psczEscaped
diff --git a/src/libs/dutil/WixToolset.DUtil/dutil.vcxproj b/src/libs/dutil/WixToolset.DUtil/dutil.vcxproj
index 3e3c42b7..c84b98fe 100644
--- a/src/libs/dutil/WixToolset.DUtil/dutil.vcxproj
+++ b/src/libs/dutil/WixToolset.DUtil/dutil.vcxproj
@@ -104,6 +104,7 @@
104 <ClCompile Include="strutil.cpp" /> 104 <ClCompile Include="strutil.cpp" />
105 <ClCompile Include="svcutil.cpp" /> 105 <ClCompile Include="svcutil.cpp" />
106 <ClCompile Include="thmutil.cpp" /> 106 <ClCompile Include="thmutil.cpp" />
107 <ClCompile Include="thrdutil.cpp" />
107 <ClCompile Include="timeutil.cpp" /> 108 <ClCompile Include="timeutil.cpp" />
108 <ClCompile Include="uncutil.cpp" /> 109 <ClCompile Include="uncutil.cpp" />
109 <ClCompile Include="uriutil.cpp" /> 110 <ClCompile Include="uriutil.cpp" />
@@ -164,6 +165,7 @@
164 <ClInclude Include="inc\strutil.h" /> 165 <ClInclude Include="inc\strutil.h" />
165 <ClInclude Include="inc\svcutil.h" /> 166 <ClInclude Include="inc\svcutil.h" />
166 <ClInclude Include="inc\thmutil.h" /> 167 <ClInclude Include="inc\thmutil.h" />
168 <ClInclude Include="inc\thrdutil.h" />
167 <ClInclude Include="inc\timeutil.h" /> 169 <ClInclude Include="inc\timeutil.h" />
168 <ClInclude Include="inc\uriutil.h" /> 170 <ClInclude Include="inc\uriutil.h" />
169 <ClInclude Include="inc\userutil.h" /> 171 <ClInclude Include="inc\userutil.h" />
diff --git a/src/libs/dutil/WixToolset.DUtil/dutil.vcxproj.filters b/src/libs/dutil/WixToolset.DUtil/dutil.vcxproj.filters
index 07698f9e..efadef6f 100644
--- a/src/libs/dutil/WixToolset.DUtil/dutil.vcxproj.filters
+++ b/src/libs/dutil/WixToolset.DUtil/dutil.vcxproj.filters
@@ -162,6 +162,9 @@
162 <ClCompile Include="thmutil.cpp"> 162 <ClCompile Include="thmutil.cpp">
163 <Filter>Source Files</Filter> 163 <Filter>Source Files</Filter>
164 </ClCompile> 164 </ClCompile>
165 <ClCompile Include="thrdutil.cpp">
166 <Filter>Source Files</Filter>
167 </ClCompile>
165 <ClCompile Include="timeutil.cpp"> 168 <ClCompile Include="timeutil.cpp">
166 <Filter>Source Files</Filter> 169 <Filter>Source Files</Filter>
167 </ClCompile> 170 </ClCompile>
@@ -344,6 +347,9 @@
344 <ClInclude Include="inc\thmutil.h"> 347 <ClInclude Include="inc\thmutil.h">
345 <Filter>Header Files</Filter> 348 <Filter>Header Files</Filter>
346 </ClInclude> 349 </ClInclude>
350 <ClInclude Include="inc\thrdutil.h">
351 <Filter>Header Files</Filter>
352 </ClInclude>
347 <ClInclude Include="inc\timeutil.h"> 353 <ClInclude Include="inc\timeutil.h">
348 <Filter>Header Files</Filter> 354 <Filter>Header Files</Filter>
349 </ClInclude> 355 </ClInclude>
diff --git a/src/libs/dutil/WixToolset.DUtil/inc/apputil.h b/src/libs/dutil/WixToolset.DUtil/inc/apputil.h
index 95a98e73..e2812ee4 100644
--- a/src/libs/dutil/WixToolset.DUtil/inc/apputil.h
+++ b/src/libs/dutil/WixToolset.DUtil/inc/apputil.h
@@ -84,6 +84,27 @@ HRESULT DAPI AppEscapeCommandLineArgumentFormattedArgs(
84 __in va_list args 84 __in va_list args
85 ); 85 );
86 86
87/********************************************************************
88AppWaitForSingleObject - wrapper for ::WaitForSingleObject.
89
90********************************************************************/
91HRESULT DAPI AppWaitForSingleObject(
92 __in HANDLE hHandle,
93 __in DWORD dwMilliseconds
94 );
95
96/********************************************************************
97AppWaitForMultipleObjects - wrapper for ::WaitForMultipleObjects.
98
99********************************************************************/
100HRESULT DAPI AppWaitForMultipleObjects(
101 __in DWORD dwCount,
102 __in const HANDLE* rghHandles,
103 __in BOOL fWaitAll,
104 __in DWORD dwMilliseconds,
105 __out_opt DWORD* pdwSignaledIndex
106 );
107
87#ifdef __cplusplus 108#ifdef __cplusplus
88} 109}
89#endif 110#endif
diff --git a/src/libs/dutil/WixToolset.DUtil/inc/dutil.h b/src/libs/dutil/WixToolset.DUtil/inc/dutil.h
index 6f099f35..2db64812 100644
--- a/src/libs/dutil/WixToolset.DUtil/inc/dutil.h
+++ b/src/libs/dutil/WixToolset.DUtil/inc/dutil.h
@@ -130,6 +130,7 @@ void DAPI Dutil_RootFailure(__in_z LPCSTR szFile, __in int iLine, __in HRESULT h
130#define ExitOnWin32ErrorSource(d, e, x, s, ...) if (ERROR_SUCCESS != e) { x = HRESULT_FROM_WIN32(e); if (!FAILED(x)) { x = E_FAIL; } Dutil_RootFailure(__FILE__, __LINE__, x); ExitTraceSource(d, x, s, __VA_ARGS__); goto LExit; } 130#define ExitOnWin32ErrorSource(d, e, x, s, ...) if (ERROR_SUCCESS != e) { x = HRESULT_FROM_WIN32(e); if (!FAILED(x)) { x = E_FAIL; } Dutil_RootFailure(__FILE__, __LINE__, x); ExitTraceSource(d, x, s, __VA_ARGS__); goto LExit; }
131#define ExitOnOptionalXmlQueryFailureSource(d, x, b, s, ...) { { if (S_FALSE == x || E_NOTFOUND == x) { b = FALSE; x = S_OK; } else { b = SUCCEEDED(x); } }; ExitOnRootFailureSource(d, x, s, __VA_ARGS__); } 131#define ExitOnOptionalXmlQueryFailureSource(d, x, b, s, ...) { { if (S_FALSE == x || E_NOTFOUND == x) { b = FALSE; x = S_OK; } else { b = SUCCEEDED(x); } }; ExitOnRootFailureSource(d, x, s, __VA_ARGS__); }
132#define ExitOnRequiredXmlQueryFailureSource(d, x, s, ...) { if (S_FALSE == x) { x = E_NOTFOUND; } ExitOnRootFailureSource(d, x, s, __VA_ARGS__); } 132#define ExitOnRequiredXmlQueryFailureSource(d, x, s, ...) { if (S_FALSE == x) { x = E_NOTFOUND; } ExitOnRootFailureSource(d, x, s, __VA_ARGS__); }
133#define ExitOnWaitObjectFailureSource(d, x, b, s, ...) { { if (HRESULT_FROM_WIN32(WAIT_TIMEOUT) == x) { b = TRUE; x = S_OK; } else { b = FALSE; } }; ExitOnFailureSource(d, x, s, __VA_ARGS__); }
133 134
134#define ExitOnLastError(x, s, ...) ExitOnLastErrorSource(DUTIL_SOURCE_DEFAULT, x, s, __VA_ARGS__) 135#define ExitOnLastError(x, s, ...) ExitOnLastErrorSource(DUTIL_SOURCE_DEFAULT, x, s, __VA_ARGS__)
135#define ExitOnLastErrorDebugTrace(x, s, ...) ExitOnLastErrorDebugTraceSource(DUTIL_SOURCE_DEFAULT, x, s, __VA_ARGS__) 136#define ExitOnLastErrorDebugTrace(x, s, ...) ExitOnLastErrorDebugTraceSource(DUTIL_SOURCE_DEFAULT, x, s, __VA_ARGS__)
@@ -145,6 +146,7 @@ void DAPI Dutil_RootFailure(__in_z LPCSTR szFile, __in int iLine, __in HRESULT h
145#define ExitOnWin32Error(e, x, s, ...) ExitOnWin32ErrorSource(DUTIL_SOURCE_DEFAULT, e, x, s, __VA_ARGS__) 146#define ExitOnWin32Error(e, x, s, ...) ExitOnWin32ErrorSource(DUTIL_SOURCE_DEFAULT, e, x, s, __VA_ARGS__)
146#define ExitOnOptionalXmlQueryFailure(x, b, s, ...) ExitOnOptionalXmlQueryFailureSource(DUTIL_SOURCE_DEFAULT, x, b, s, __VA_ARGS__) 147#define ExitOnOptionalXmlQueryFailure(x, b, s, ...) ExitOnOptionalXmlQueryFailureSource(DUTIL_SOURCE_DEFAULT, x, b, s, __VA_ARGS__)
147#define ExitOnRequiredXmlQueryFailure(x, s, ...) ExitOnRequiredXmlQueryFailureSource(DUTIL_SOURCE_DEFAULT, x, s, __VA_ARGS__) 148#define ExitOnRequiredXmlQueryFailure(x, s, ...) ExitOnRequiredXmlQueryFailureSource(DUTIL_SOURCE_DEFAULT, x, s, __VA_ARGS__)
149#define ExitOnWaitObjectFailure(x, b, s, ...) ExitOnWaitObjectFailureSource(DUTIL_SOURCE_DEFAULT, x, b, s, __VA_ARGS__)
148 150
149// release macros 151// release macros
150#define ReleaseObject(x) if (x) { x->Release(); } 152#define ReleaseObject(x) if (x) { x->Release(); }
diff --git a/src/libs/dutil/WixToolset.DUtil/inc/dutilsources.h b/src/libs/dutil/WixToolset.DUtil/inc/dutilsources.h
index f1dd5d1a..664c21e5 100644
--- a/src/libs/dutil/WixToolset.DUtil/inc/dutilsources.h
+++ b/src/libs/dutil/WixToolset.DUtil/inc/dutilsources.h
@@ -63,6 +63,7 @@ typedef enum DUTIL_SOURCE
63 DUTIL_SOURCE_VERUTIL, 63 DUTIL_SOURCE_VERUTIL,
64 DUTIL_SOURCE_WNDUTIL, 64 DUTIL_SOURCE_WNDUTIL,
65 DUTIL_SOURCE_ENVUTIL, 65 DUTIL_SOURCE_ENVUTIL,
66 DUTIL_SOURCE_THRDUTIL,
66 67
67 DUTIL_SOURCE_EXTERNAL = 256, 68 DUTIL_SOURCE_EXTERNAL = 256,
68} DUTIL_SOURCE; 69} DUTIL_SOURCE;
diff --git a/src/libs/dutil/WixToolset.DUtil/inc/procutil.h b/src/libs/dutil/WixToolset.DUtil/inc/procutil.h
index d5ab9242..d61d91b5 100644
--- a/src/libs/dutil/WixToolset.DUtil/inc/procutil.h
+++ b/src/libs/dutil/WixToolset.DUtil/inc/procutil.h
@@ -58,7 +58,7 @@ HRESULT DAPI ProcExecute(
58HRESULT DAPI ProcWaitForCompletion( 58HRESULT DAPI ProcWaitForCompletion(
59 __in HANDLE hProcess, 59 __in HANDLE hProcess,
60 __in DWORD dwTimeout, 60 __in DWORD dwTimeout,
61 __out DWORD *pReturnCode 61 __out_opt DWORD* pdwReturnCode
62 ); 62 );
63HRESULT DAPI ProcWaitForIds( 63HRESULT DAPI ProcWaitForIds(
64 __in_ecount(cProcessIds) const DWORD* pdwProcessIds, 64 __in_ecount(cProcessIds) const DWORD* pdwProcessIds,
diff --git a/src/libs/dutil/WixToolset.DUtil/inc/thrdutil.h b/src/libs/dutil/WixToolset.DUtil/inc/thrdutil.h
new file mode 100644
index 00000000..47e159a1
--- /dev/null
+++ b/src/libs/dutil/WixToolset.DUtil/inc/thrdutil.h
@@ -0,0 +1,22 @@
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 ThrdWaitForCompletion - waits for thread to complete and gets return code.
11
12 *******************************************************************/
13HRESULT DAPI ThrdWaitForCompletion(
14 __in HANDLE hThread,
15 __in DWORD dwTimeout,
16 __out_opt DWORD* pdwReturnCode
17 );
18
19#ifdef __cplusplus
20}
21#endif
22
diff --git a/src/libs/dutil/WixToolset.DUtil/monutil.cpp b/src/libs/dutil/WixToolset.DUtil/monutil.cpp
index 6ad75b56..10954164 100644
--- a/src/libs/dutil/WixToolset.DUtil/monutil.cpp
+++ b/src/libs/dutil/WixToolset.DUtil/monutil.cpp
@@ -16,6 +16,7 @@
16#define MonExitOnInvalidHandleWithLastError(p, x, s, ...) ExitOnInvalidHandleWithLastErrorSource(DUTIL_SOURCE_MONUTIL, p, x, s, __VA_ARGS__) 16#define MonExitOnInvalidHandleWithLastError(p, x, s, ...) ExitOnInvalidHandleWithLastErrorSource(DUTIL_SOURCE_MONUTIL, p, x, s, __VA_ARGS__)
17#define MonExitOnWin32Error(e, x, s, ...) ExitOnWin32ErrorSource(DUTIL_SOURCE_MONUTIL, e, x, s, __VA_ARGS__) 17#define MonExitOnWin32Error(e, x, s, ...) ExitOnWin32ErrorSource(DUTIL_SOURCE_MONUTIL, e, x, s, __VA_ARGS__)
18#define MonExitOnGdipFailure(g, x, s, ...) ExitOnGdipFailureSource(DUTIL_SOURCE_MONUTIL, g, x, s, __VA_ARGS__) 18#define MonExitOnGdipFailure(g, x, s, ...) ExitOnGdipFailureSource(DUTIL_SOURCE_MONUTIL, g, x, s, __VA_ARGS__)
19#define MonExitOnWaitObjectFailure(x, b, s, ...) ExitOnWaitObjectFailureSource(DUTIL_SOURCE_MONUTIL, x, b, s, __VA_ARGS__)
19 20
20const int MON_THREAD_GROWTH = 5; 21const int MON_THREAD_GROWTH = 5;
21const int MON_ARRAY_GROWTH = 40; 22const int MON_ARRAY_GROWTH = 40;
@@ -1101,11 +1102,12 @@ static DWORD WINAPI WaiterThread(
1101{ 1102{
1102 HRESULT hr = S_OK; 1103 HRESULT hr = S_OK;
1103 HRESULT hrTemp = S_OK; 1104 HRESULT hrTemp = S_OK;
1104 DWORD dwRet = 0;
1105 BOOL fAgain = FALSE; 1105 BOOL fAgain = FALSE;
1106 BOOL fContinue = TRUE; 1106 BOOL fContinue = TRUE;
1107 BOOL fNotify = FALSE; 1107 BOOL fNotify = FALSE;
1108 BOOL fRet = FALSE; 1108 BOOL fRet = FALSE;
1109 BOOL fTimedOut = FALSE;
1110 DWORD dwSignaledIndex = 0;
1109 MSG msg = { }; 1111 MSG msg = { };
1110 MON_ADD_MESSAGE *pAddMessage = NULL; 1112 MON_ADD_MESSAGE *pAddMessage = NULL;
1111 MON_REMOVE_MESSAGE *pRemoveMessage = NULL; 1113 MON_REMOVE_MESSAGE *pRemoveMessage = NULL;
@@ -1128,13 +1130,14 @@ static DWORD WINAPI WaiterThread(
1128 1130
1129 do 1131 do
1130 { 1132 {
1131 dwRet = ::WaitForMultipleObjects(pWaiterContext->cHandles - pWaiterContext->cRequestsFailing, pWaiterContext->rgHandles, FALSE, pWaiterContext->cRequestsPending > 0 ? dwWait : INFINITE); 1133 hr = AppWaitForMultipleObjects(pWaiterContext->cHandles - pWaiterContext->cRequestsFailing, pWaiterContext->rgHandles, FALSE, pWaiterContext->cRequestsPending > 0 ? dwWait : INFINITE, &dwSignaledIndex);
1134 MonExitOnWaitObjectFailure(hr, fTimedOut, "Failed to wait for multiple objects.");
1132 1135
1133 uCurrentTime = ::GetTickCount(); 1136 uCurrentTime = ::GetTickCount();
1134 uDeltaInMs = uCurrentTime - uLastTimeInMs; 1137 uDeltaInMs = uCurrentTime - uLastTimeInMs;
1135 uLastTimeInMs = uCurrentTime; 1138 uLastTimeInMs = uCurrentTime;
1136 1139
1137 if (WAIT_OBJECT_0 == dwRet) 1140 if (!fTimedOut && 0 == dwSignaledIndex)
1138 { 1141 {
1139 do 1142 do
1140 { 1143 {
@@ -1391,10 +1394,10 @@ static DWORD WINAPI WaiterThread(
1391 } 1394 }
1392 } while (fAgain); 1395 } while (fAgain);
1393 } 1396 }
1394 else if (dwRet > WAIT_OBJECT_0 && dwRet - WAIT_OBJECT_0 < pWaiterContext->cHandles) 1397 else if (!fTimedOut)
1395 { 1398 {
1396 // OK a handle fired - only notify if it's the actual target, and not just some parent waiting for the target child to exist 1399 // OK a handle fired - only notify if it's the actual target, and not just some parent waiting for the target child to exist
1397 dwRequestIndex = dwRet - WAIT_OBJECT_0 - 1; 1400 dwRequestIndex = dwSignaledIndex - 1;
1398 fNotify = (pWaiterContext->rgRequests[dwRequestIndex].dwPathHierarchyIndex == pWaiterContext->rgRequests[dwRequestIndex].cPathHierarchy - 1); 1401 fNotify = (pWaiterContext->rgRequests[dwRequestIndex].dwPathHierarchyIndex == pWaiterContext->rgRequests[dwRequestIndex].cPathHierarchy - 1);
1399 1402
1400 // Initiate re-waits before we notify callback, to ensure we don't miss a single update 1403 // Initiate re-waits before we notify callback, to ensure we don't miss a single update
@@ -1426,10 +1429,6 @@ static DWORD WINAPI WaiterThread(
1426 } 1429 }
1427 } 1430 }
1428 } 1431 }
1429 else if (WAIT_TIMEOUT != dwRet)
1430 {
1431 MonExitWithLastError(hr, "Failed to wait for multiple objects with return code %u", dwRet);
1432 }
1433 1432
1434 // OK, now that we've checked all triggered handles (resetting silence period timers appropriately), check for any pending notifications that we can finally fire 1433 // OK, now that we've checked all triggered handles (resetting silence period timers appropriately), check for any pending notifications that we can finally fire
1435 // And set dwWait appropriately so we awaken at the right time to fire the next pending notification (in case no further writes occur during that time) 1434 // And set dwWait appropriately so we awaken at the right time to fire the next pending notification (in case no further writes occur during that time)
@@ -1726,10 +1725,10 @@ static LRESULT CALLBACK MonWndProc(
1726 DEV_BROADCAST_HANDLE *pHandle = NULL; 1725 DEV_BROADCAST_HANDLE *pHandle = NULL;
1727 DEV_BROADCAST_VOLUME *pVolume = NULL; 1726 DEV_BROADCAST_VOLUME *pVolume = NULL;
1728 DWORD dwUnitMask = 0; 1727 DWORD dwUnitMask = 0;
1729 DWORD er = ERROR_SUCCESS;
1730 WCHAR chDrive = L'\0'; 1728 WCHAR chDrive = L'\0';
1731 BOOL fArrival = FALSE; 1729 BOOL fArrival = FALSE;
1732 BOOL fReturnTrue = FALSE; 1730 BOOL fReturnTrue = FALSE;
1731 BOOL fTimedOut = FALSE;
1733 CREATESTRUCT *pCreateStruct = NULL; 1732 CREATESTRUCT *pCreateStruct = NULL;
1734 MON_WAITER_CONTEXT *pWaiterContext = NULL; 1733 MON_WAITER_CONTEXT *pWaiterContext = NULL;
1735 MON_STRUCT *pm = NULL; 1734 MON_STRUCT *pm = NULL;
@@ -1821,24 +1820,23 @@ static LRESULT CALLBACK MonWndProc(
1821 } 1820 }
1822 } 1821 }
1823 1822
1824 er = ::WaitForSingleObject(pm->internalWait.hWait, MON_THREAD_WAIT_REMOVE_DEVICE); 1823 hr = AppWaitForSingleObject(pm->internalWait.hWait, MON_THREAD_WAIT_REMOVE_DEVICE);
1824 MonExitOnWaitObjectFailure(hr, fTimedOut, "WaitForSingleObject failed with non-timeout reason while waiting for response from waiter thread");
1825
1825 // Make sure any waiter thread processing really old messages can immediately know that we're no longer waiting for a response 1826 // Make sure any waiter thread processing really old messages can immediately know that we're no longer waiting for a response
1826 if (WAIT_OBJECT_0 == er) 1827 if (!fTimedOut)
1827 { 1828 {
1828 // If the response ID matches what we sent, we actually got a valid reply! 1829 // If the response ID matches what we sent, we actually got a valid reply!
1829 if (pm->internalWait.dwReceiveIteration != pm->internalWait.dwSendIteration) 1830 if (pm->internalWait.dwReceiveIteration != pm->internalWait.dwSendIteration)
1830 { 1831 {
1831 TraceError(HRESULT_FROM_WIN32(er), "Waiter thread received wrong ID reply"); 1832 TraceError(E_UNEXPECTED, "Waiter thread received wrong ID reply");
1832 } 1833 }
1833 } 1834 }
1834 else if (WAIT_TIMEOUT == er)
1835 {
1836 TraceError(HRESULT_FROM_WIN32(er), "No response from any waiter thread for query remove message");
1837 }
1838 else 1835 else
1839 { 1836 {
1840 MonExitWithLastError(hr, "WaitForSingleObject failed with non-timeout reason while waiting for response from waiter thread"); 1837 TraceError(HRESULT_FROM_WIN32(WAIT_TIMEOUT), "No response from any waiter thread for query remove message");
1841 } 1838 }
1839
1842 ++pm->internalWait.dwSendIteration; 1840 ++pm->internalWait.dwSendIteration;
1843 } 1841 }
1844 } 1842 }
diff --git a/src/libs/dutil/WixToolset.DUtil/precomp.h b/src/libs/dutil/WixToolset.DUtil/precomp.h
index c9e4f74a..b628d271 100644
--- a/src/libs/dutil/WixToolset.DUtil/precomp.h
+++ b/src/libs/dutil/WixToolset.DUtil/precomp.h
@@ -90,6 +90,7 @@
90#include "timeutil.h" 90#include "timeutil.h"
91#include "wndutil.h" 91#include "wndutil.h"
92#include "thmutil.h" 92#include "thmutil.h"
93#include "thrdutil.h"
93#include "uncutil.h" 94#include "uncutil.h"
94#include "uriutil.h" 95#include "uriutil.h"
95#include "userutil.h" 96#include "userutil.h"
diff --git a/src/libs/dutil/WixToolset.DUtil/procutil.cpp b/src/libs/dutil/WixToolset.DUtil/procutil.cpp
index 340a0cda..29f575ae 100644
--- a/src/libs/dutil/WixToolset.DUtil/procutil.cpp
+++ b/src/libs/dutil/WixToolset.DUtil/procutil.cpp
@@ -17,6 +17,7 @@
17#define ProcExitOnInvalidHandleWithLastError(p, x, s, ...) ExitOnInvalidHandleWithLastErrorSource(DUTIL_SOURCE_PROCUTIL, p, x, s, __VA_ARGS__) 17#define ProcExitOnInvalidHandleWithLastError(p, x, s, ...) ExitOnInvalidHandleWithLastErrorSource(DUTIL_SOURCE_PROCUTIL, p, x, s, __VA_ARGS__)
18#define ProcExitOnWin32Error(e, x, s, ...) ExitOnWin32ErrorSource(DUTIL_SOURCE_PROCUTIL, e, x, s, __VA_ARGS__) 18#define ProcExitOnWin32Error(e, x, s, ...) ExitOnWin32ErrorSource(DUTIL_SOURCE_PROCUTIL, e, x, s, __VA_ARGS__)
19#define ProcExitOnGdipFailure(g, x, s, ...) ExitOnGdipFailureSource(DUTIL_SOURCE_PROCUTIL, g, x, s, __VA_ARGS__) 19#define ProcExitOnGdipFailure(g, x, s, ...) ExitOnGdipFailureSource(DUTIL_SOURCE_PROCUTIL, g, x, s, __VA_ARGS__)
20#define ProcExitOnWaitObjectFailure(x, b, s, ...) ExitOnWaitObjectFailureSource(DUTIL_SOURCE_PROCUTIL, x, b, s, __VA_ARGS__)
20 21
21 22
22// private functions 23// private functions
@@ -403,30 +404,25 @@ LExit:
403extern "C" HRESULT DAPI ProcWaitForCompletion( 404extern "C" HRESULT DAPI ProcWaitForCompletion(
404 __in HANDLE hProcess, 405 __in HANDLE hProcess,
405 __in DWORD dwTimeout, 406 __in DWORD dwTimeout,
406 __out DWORD *pReturnCode 407 __out_opt DWORD* pdwReturnCode
407 ) 408 )
408{ 409{
409 HRESULT hr = S_OK; 410 HRESULT hr = S_OK;
410 DWORD er = ERROR_SUCCESS; 411 BOOL fTimedOut = FALSE;
411 412
412 // Wait for everything to finish 413 // Wait for everything to finish.
413 er = ::WaitForSingleObject(hProcess, dwTimeout); 414 hr = AppWaitForSingleObject(hProcess, dwTimeout);
414 if (WAIT_FAILED == er) 415 ProcExitOnWaitObjectFailure(hr, fTimedOut, "Failed to wait for process to complete.");
415 { 416
416 ProcExitWithLastError(hr, "Failed to wait for process to complete."); 417 if (fTimedOut)
417 }
418 else if (WAIT_TIMEOUT == er)
419 { 418 {
420 ExitFunction1(hr = HRESULT_FROM_WIN32(er)); 419 hr = HRESULT_FROM_WIN32(WAIT_TIMEOUT);
421 } 420 }
422 421 else if (pdwReturnCode && !::GetExitCodeProcess(hProcess, pdwReturnCode))
423 if (!::GetExitCodeProcess(hProcess, &er))
424 { 422 {
425 ProcExitWithLastError(hr, "Failed to get process return code."); 423 ProcExitWithLastError(hr, "Failed to get process return code.");
426 } 424 }
427 425
428 *pReturnCode = er;
429
430LExit: 426LExit:
431 return hr; 427 return hr;
432} 428}
@@ -442,10 +438,10 @@ extern "C" HRESULT DAPI ProcWaitForIds(
442 ) 438 )
443{ 439{
444 HRESULT hr = S_OK; 440 HRESULT hr = S_OK;
445 DWORD er = ERROR_SUCCESS;
446 HANDLE hProcess = NULL; 441 HANDLE hProcess = NULL;
447 HANDLE * rghProcesses = NULL; 442 HANDLE* rghProcesses = NULL;
448 DWORD cProcesses = 0; 443 DWORD cProcesses = 0;
444 BOOL fTimedOut = FALSE;
449 445
450 rghProcesses = static_cast<HANDLE*>(MemAlloc(sizeof(DWORD) * cProcessIds, TRUE)); 446 rghProcesses = static_cast<HANDLE*>(MemAlloc(sizeof(DWORD) * cProcessIds, TRUE));
451 ProcExitOnNull(rgdwProcessIds, hr, E_OUTOFMEMORY, "Failed to allocate array for process ID Handles."); 447 ProcExitOnNull(rgdwProcessIds, hr, E_OUTOFMEMORY, "Failed to allocate array for process ID Handles.");
@@ -459,16 +455,14 @@ extern "C" HRESULT DAPI ProcWaitForIds(
459 } 455 }
460 } 456 }
461 457
462 er = ::WaitForMultipleObjects(cProcesses, rghProcesses, TRUE, dwMilliseconds); 458 hr = AppWaitForMultipleObjects(cProcesses, rghProcesses, TRUE, dwMilliseconds, NULL);
463 if (WAIT_FAILED == er) 459 ProcExitOnWaitObjectFailure(hr, fTimedOut, "Failed to wait for processes to complete.");
464 { 460
465 ProcExitWithLastError(hr, "Failed to wait for process to complete."); 461 if (fTimedOut)
466 }
467 else if (WAIT_TIMEOUT == er)
468 { 462 {
469 ProcExitOnWin32Error(er, hr, "Timed out while waiting for process to complete."); 463 ProcExitWithRootFailure(hr, HRESULT_FROM_WIN32(WAIT_TIMEOUT), "Timed out while waiting for processes to complete.");
470 } 464 }
471 465
472LExit: 466LExit:
473 if (rghProcesses) 467 if (rghProcesses)
474 { 468 {
diff --git a/src/libs/dutil/WixToolset.DUtil/thrdutil.cpp b/src/libs/dutil/WixToolset.DUtil/thrdutil.cpp
new file mode 100644
index 00000000..a8933a48
--- /dev/null
+++ b/src/libs/dutil/WixToolset.DUtil/thrdutil.cpp
@@ -0,0 +1,46 @@
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 ThrdExitOnLastError(x, s, ...) ExitOnLastErrorSource(DUTIL_SOURCE_THRDUTIL, x, s, __VA_ARGS__)
8#define ThrdExitOnLastErrorDebugTrace(x, s, ...) ExitOnLastErrorDebugTraceSource(DUTIL_SOURCE_THRDUTIL, x, s, __VA_ARGS__)
9#define ThrdExitWithLastError(x, s, ...) ExitWithLastErrorSource(DUTIL_SOURCE_THRDUTIL, x, s, __VA_ARGS__)
10#define ThrdExitOnFailure(x, s, ...) ExitOnFailureSource(DUTIL_SOURCE_THRDUTIL, x, s, __VA_ARGS__)
11#define ThrdExitOnRootFailure(x, s, ...) ExitOnRootFailureSource(DUTIL_SOURCE_THRDUTIL, x, s, __VA_ARGS__)
12#define ThrdExitWithRootFailure(x, e, s, ...) ExitWithRootFailureSource(DUTIL_SOURCE_THRDUTIL, x, e, s, __VA_ARGS__)
13#define ThrdExitOnFailureDebugTrace(x, s, ...) ExitOnFailureDebugTraceSource(DUTIL_SOURCE_THRDUTIL, x, s, __VA_ARGS__)
14#define ThrdExitOnNull(p, x, e, s, ...) ExitOnNullSource(DUTIL_SOURCE_THRDUTIL, p, x, e, s, __VA_ARGS__)
15#define ThrdExitOnNullWithLastError(p, x, s, ...) ExitOnNullWithLastErrorSource(DUTIL_SOURCE_THRDUTIL, p, x, s, __VA_ARGS__)
16#define ThrdExitOnNullDebugTrace(p, x, e, s, ...) ExitOnNullDebugTraceSource(DUTIL_SOURCE_THRDUTIL, p, x, e, s, __VA_ARGS__)
17#define ThrdExitOnInvalidHandleWithLastError(p, x, s, ...) ExitOnInvalidHandleWithLastErrorSource(DUTIL_SOURCE_THRDUTIL, p, x, s, __VA_ARGS__)
18#define ThrdExitOnWin32Error(e, x, s, ...) ExitOnWin32ErrorSource(DUTIL_SOURCE_THRDUTIL, e, x, s, __VA_ARGS__)
19#define ThrdExitOnGdipFailure(g, x, s, ...) ExitOnGdipFailureSource(DUTIL_SOURCE_THRDUTIL, g, x, s, __VA_ARGS__)
20#define ThrdExitOnWaitObjectFailure(x, b, s, ...) ExitOnWaitObjectFailureSource(DUTIL_SOURCE_THRDUTIL, x, b, s, __VA_ARGS__)
21
22DAPI_(HRESULT) ThrdWaitForCompletion(
23 __in HANDLE hThread,
24 __in DWORD dwTimeout,
25 __out_opt DWORD *pdwReturnCode
26 )
27{
28 HRESULT hr = S_OK;
29 BOOL fTimedOut = FALSE;
30
31 // Wait for everything to finish.
32 hr = AppWaitForSingleObject(hThread, dwTimeout);
33 ThrdExitOnWaitObjectFailure(hr, fTimedOut, "Failed to wait for thread to complete.");
34
35 if (fTimedOut)
36 {
37 hr = HRESULT_FROM_WIN32(WAIT_TIMEOUT);
38 }
39 else if (pdwReturnCode && !::GetExitCodeThread(hThread, pdwReturnCode))
40 {
41 ThrdExitWithLastError(hr, "Failed to get thread return code.");
42 }
43
44LExit:
45 return hr;
46}
diff --git a/src/libs/dutil/test/DUtilUnitTest/AppUtilTests.cpp b/src/libs/dutil/test/DUtilUnitTest/AppUtilTests.cpp
new file mode 100644
index 00000000..e8c23469
--- /dev/null
+++ b/src/libs/dutil/test/DUtilUnitTest/AppUtilTests.cpp
@@ -0,0 +1,60 @@
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
5namespace DutilTests
6{
7 using namespace System;
8 using namespace Xunit;
9 using namespace WixBuildTools::TestSupport;
10
11 public ref class AppUtil
12 {
13 public:
14 [Fact]
15 void WaitForMultipleObjectsTest()
16 {
17 HRESULT hr = S_OK;
18 HANDLE hOne = NULL;
19 HANDLE hTwo = NULL;
20 HANDLE rghHandles[2] = { };
21 DWORD dwSignaledIndex = 0;
22
23 try
24 {
25 hOne = ::CreateEventW(NULL, TRUE, FALSE, NULL);
26 if (!hOne)
27 {
28 hr = HRESULT_FROM_WIN32(::GetLastError());
29 NativeAssert::Succeeded(FAILED(hr) ? hr : E_FAIL, "Failed to create event.");
30 }
31
32 hTwo = ::CreateEventW(NULL, TRUE, TRUE, NULL);
33 if (!hTwo)
34 {
35 hr = HRESULT_FROM_WIN32(::GetLastError());
36 NativeAssert::Succeeded(FAILED(hr) ? hr : E_FAIL, "Failed to create event.");
37 }
38
39 rghHandles[0] = hOne;
40 rghHandles[1] = hTwo;
41
42 hr = AppWaitForMultipleObjects(countof(rghHandles), rghHandles, FALSE, 0, &dwSignaledIndex);
43 NativeAssert::Succeeded(hr, "Failed to wait for multiple objects.");
44 Assert::Equal<DWORD>(1, dwSignaledIndex);
45
46 rghHandles[0] = hTwo;
47 rghHandles[1] = hOne;
48
49 hr = AppWaitForMultipleObjects(countof(rghHandles), rghHandles, FALSE, 0, &dwSignaledIndex);
50 NativeAssert::Succeeded(hr, "Failed to wait for multiple objects.");
51 Assert::Equal<DWORD>(0, dwSignaledIndex);
52 }
53 finally
54 {
55 ReleaseHandle(hOne);
56 ReleaseHandle(hTwo);
57 }
58 }
59 };
60}
diff --git a/src/libs/dutil/test/DUtilUnitTest/DUtilUnitTest.vcxproj b/src/libs/dutil/test/DUtilUnitTest/DUtilUnitTest.vcxproj
index a1f13239..210f50f5 100644
--- a/src/libs/dutil/test/DUtilUnitTest/DUtilUnitTest.vcxproj
+++ b/src/libs/dutil/test/DUtilUnitTest/DUtilUnitTest.vcxproj
@@ -44,6 +44,7 @@
44 </PropertyGroup> 44 </PropertyGroup>
45 45
46 <ItemGroup> 46 <ItemGroup>
47 <ClCompile Include="AppUtilTests.cpp" />
47 <ClCompile Include="ApupUtilTests.cpp" /> 48 <ClCompile Include="ApupUtilTests.cpp" />
48 <ClCompile Include="AssemblyInfo.cpp" /> 49 <ClCompile Include="AssemblyInfo.cpp" />
49 <ClCompile Include="DictUtilTest.cpp" /> 50 <ClCompile Include="DictUtilTest.cpp" />
diff --git a/src/libs/dutil/test/DUtilUnitTest/DUtilUnitTest.vcxproj.filters b/src/libs/dutil/test/DUtilUnitTest/DUtilUnitTest.vcxproj.filters
index cb0c8a73..f1d9c307 100644
--- a/src/libs/dutil/test/DUtilUnitTest/DUtilUnitTest.vcxproj.filters
+++ b/src/libs/dutil/test/DUtilUnitTest/DUtilUnitTest.vcxproj.filters
@@ -15,6 +15,9 @@
15 </Filter> 15 </Filter>
16 </ItemGroup> 16 </ItemGroup>
17 <ItemGroup> 17 <ItemGroup>
18 <ClCompile Include="AppUtilTests.cpp">
19 <Filter>Source Files</Filter>
20 </ClCompile>
18 <ClCompile Include="ApupUtilTests.cpp"> 21 <ClCompile Include="ApupUtilTests.cpp">
19 <Filter>Source Files</Filter> 22 <Filter>Source Files</Filter>
20 </ClCompile> 23 </ClCompile>
diff --git a/src/libs/dutil/test/DUtilUnitTest/precomp.h b/src/libs/dutil/test/DUtilUnitTest/precomp.h
index ac57cdd4..a5542774 100644
--- a/src/libs/dutil/test/DUtilUnitTest/precomp.h
+++ b/src/libs/dutil/test/DUtilUnitTest/precomp.h
@@ -13,6 +13,7 @@
13#include <dutil.h> 13#include <dutil.h>
14 14
15#include <verutil.h> 15#include <verutil.h>
16#include <apputil.h>
16#include <atomutil.h> 17#include <atomutil.h>
17#include <dictutil.h> 18#include <dictutil.h>
18#include <dirutil.h> 19#include <dirutil.h>