aboutsummaryrefslogtreecommitdiff
path: root/src/libs
diff options
context:
space:
mode:
authorRob Mensching <rob@firegiant.com>2024-01-10 23:53:18 -0800
committerRob Mensching <rob@firegiant.com>2024-01-11 18:24:06 -0800
commit4e7b7c0059d76498d1c24f348dbf6d5799203fe0 (patch)
tree1b00606cee7fd54ca4e07aa7b550fe63982220b3 /src/libs
parent57b7689b2dc5e971911d1c6d48eebb5424ebca89 (diff)
downloadwix-4e7b7c0059d76498d1c24f348dbf6d5799203fe0.tar.gz
wix-4e7b7c0059d76498d1c24f348dbf6d5799203fe0.tar.bz2
wix-4e7b7c0059d76498d1c24f348dbf6d5799203fe0.zip
Add pipeutil to dutil
Plus a couple small clean-ups in a couple of dutil files.
Diffstat (limited to 'src/libs')
-rw-r--r--src/libs/dutil/WixToolset.DUtil/dutil.vcxproj2
-rw-r--r--src/libs/dutil/WixToolset.DUtil/dutil.vcxproj.filters7
-rw-r--r--src/libs/dutil/WixToolset.DUtil/fileutil.cpp8
-rw-r--r--src/libs/dutil/WixToolset.DUtil/inc/dutilsources.h1
-rw-r--r--src/libs/dutil/WixToolset.DUtil/inc/pipeutil.h104
-rw-r--r--src/libs/dutil/WixToolset.DUtil/perfutil.cpp10
-rw-r--r--src/libs/dutil/WixToolset.DUtil/pipeutil.cpp347
-rw-r--r--src/libs/dutil/WixToolset.DUtil/precomp.h1
-rw-r--r--src/libs/dutil/test/DUtilUnitTest/DUtilUnitTest.vcxproj1
-rw-r--r--src/libs/dutil/test/DUtilUnitTest/DUtilUnitTest.vcxproj.filters6
-rw-r--r--src/libs/dutil/test/DUtilUnitTest/PipeUtilTest.cpp89
-rw-r--r--src/libs/dutil/test/DUtilUnitTest/precomp.h1
12 files changed, 570 insertions, 7 deletions
diff --git a/src/libs/dutil/WixToolset.DUtil/dutil.vcxproj b/src/libs/dutil/WixToolset.DUtil/dutil.vcxproj
index 736acd46..c973b141 100644
--- a/src/libs/dutil/WixToolset.DUtil/dutil.vcxproj
+++ b/src/libs/dutil/WixToolset.DUtil/dutil.vcxproj
@@ -87,6 +87,7 @@
87 <ClCompile Include="path3utl.cpp" /> 87 <ClCompile Include="path3utl.cpp" />
88 <ClCompile Include="pathutil.cpp" /> 88 <ClCompile Include="pathutil.cpp" />
89 <ClCompile Include="perfutil.cpp" /> 89 <ClCompile Include="perfutil.cpp" />
90 <ClCompile Include="pipeutil.cpp" />
90 <ClCompile Include="polcutil.cpp" /> 91 <ClCompile Include="polcutil.cpp" />
91 <ClCompile Include="proc2utl.cpp" /> 92 <ClCompile Include="proc2utl.cpp" />
92 <ClCompile Include="proc3utl.cpp" /> 93 <ClCompile Include="proc3utl.cpp" />
@@ -152,6 +153,7 @@
152 <ClInclude Include="inc\osutil.h" /> 153 <ClInclude Include="inc\osutil.h" />
153 <ClInclude Include="inc\pathutil.h" /> 154 <ClInclude Include="inc\pathutil.h" />
154 <ClInclude Include="inc\perfutil.h" /> 155 <ClInclude Include="inc\perfutil.h" />
156 <ClInclude Include="inc\pipeutil.h" />
155 <ClInclude Include="inc\polcutil.h" /> 157 <ClInclude Include="inc\polcutil.h" />
156 <ClInclude Include="inc\procutil.h" /> 158 <ClInclude Include="inc\procutil.h" />
157 <ClInclude Include="inc\queutil.h" /> 159 <ClInclude Include="inc\queutil.h" />
diff --git a/src/libs/dutil/WixToolset.DUtil/dutil.vcxproj.filters b/src/libs/dutil/WixToolset.DUtil/dutil.vcxproj.filters
index c1095651..470fd3d0 100644
--- a/src/libs/dutil/WixToolset.DUtil/dutil.vcxproj.filters
+++ b/src/libs/dutil/WixToolset.DUtil/dutil.vcxproj.filters
@@ -216,6 +216,9 @@
216 <ClCompile Include="deputil.cpp"> 216 <ClCompile Include="deputil.cpp">
217 <Filter>Source Files</Filter> 217 <Filter>Source Files</Filter>
218 </ClCompile> 218 </ClCompile>
219 <ClCompile Include="pipeutil.cpp">
220 <Filter>Source Files</Filter>
221 </ClCompile>
219 </ItemGroup> 222 </ItemGroup>
220 <ItemGroup> 223 <ItemGroup>
221 <ClInclude Include="inc\aclutil.h"> 224 <ClInclude Include="inc\aclutil.h">
@@ -398,11 +401,13 @@
398 <ClInclude Include="inc\deputil.h"> 401 <ClInclude Include="inc\deputil.h">
399 <Filter>Header Files</Filter> 402 <Filter>Header Files</Filter>
400 </ClInclude> 403 </ClInclude>
404 <ClInclude Include="inc\pipeutil.h">
405 <Filter>Header Files</Filter>
406 </ClInclude>
401 </ItemGroup> 407 </ItemGroup>
402 <ItemGroup> 408 <ItemGroup>
403 <None Include="xsd\thmutil.xsd"> 409 <None Include="xsd\thmutil.xsd">
404 <Filter>Header Files</Filter> 410 <Filter>Header Files</Filter>
405 </None> 411 </None>
406 <None Include="packages.config" />
407 </ItemGroup> 412 </ItemGroup>
408</Project> \ No newline at end of file 413</Project> \ No newline at end of file
diff --git a/src/libs/dutil/WixToolset.DUtil/fileutil.cpp b/src/libs/dutil/WixToolset.DUtil/fileutil.cpp
index a9369ea1..31802d29 100644
--- a/src/libs/dutil/WixToolset.DUtil/fileutil.cpp
+++ b/src/libs/dutil/WixToolset.DUtil/fileutil.cpp
@@ -414,8 +414,8 @@ extern "C" HRESULT DAPI FileSetPointer(
414 Assert(INVALID_HANDLE_VALUE != hFile); 414 Assert(INVALID_HANDLE_VALUE != hFile);
415 415
416 HRESULT hr = S_OK; 416 HRESULT hr = S_OK;
417 LARGE_INTEGER liMove; 417 LARGE_INTEGER liMove = { };
418 LARGE_INTEGER liNewPosition; 418 LARGE_INTEGER liNewPosition = { };
419 419
420 liMove.QuadPart = dw64Move; 420 liMove.QuadPart = dw64Move;
421 if (!::SetFilePointerEx(hFile, liMove, &liNewPosition, dwMoveMethod)) 421 if (!::SetFilePointerEx(hFile, liMove, &liNewPosition, dwMoveMethod))
@@ -843,7 +843,7 @@ extern "C" HRESULT DAPI FileCopyUsingHandles(
843{ 843{
844 HRESULT hr = S_OK; 844 HRESULT hr = S_OK;
845 DWORD64 cbTotalCopied = 0; 845 DWORD64 cbTotalCopied = 0;
846 BYTE rgbData[4 * 1024]; 846 BYTE rgbData[4 * 1024] = { };
847 DWORD cbRead = 0; 847 DWORD cbRead = 0;
848 848
849 do 849 do
@@ -887,7 +887,7 @@ extern "C" HRESULT DAPI FileCopyUsingHandlesWithProgress(
887{ 887{
888 HRESULT hr = S_OK; 888 HRESULT hr = S_OK;
889 DWORD64 cbTotalCopied = 0; 889 DWORD64 cbTotalCopied = 0;
890 BYTE rgbData[64 * 1024]; 890 BYTE rgbData[64 * 1024] = { };
891 DWORD cbRead = 0; 891 DWORD cbRead = 0;
892 892
893 LARGE_INTEGER liSourceSize = { }; 893 LARGE_INTEGER liSourceSize = { };
diff --git a/src/libs/dutil/WixToolset.DUtil/inc/dutilsources.h b/src/libs/dutil/WixToolset.DUtil/inc/dutilsources.h
index cf10f910..42c7a554 100644
--- a/src/libs/dutil/WixToolset.DUtil/inc/dutilsources.h
+++ b/src/libs/dutil/WixToolset.DUtil/inc/dutilsources.h
@@ -37,6 +37,7 @@ typedef enum DUTIL_SOURCE
37 DUTIL_SOURCE_OSUTIL, 37 DUTIL_SOURCE_OSUTIL,
38 DUTIL_SOURCE_PATHUTIL, 38 DUTIL_SOURCE_PATHUTIL,
39 DUTIL_SOURCE_PERFUTIL, 39 DUTIL_SOURCE_PERFUTIL,
40 DUTIL_SOURCE_PIPEUTIL,
40 DUTIL_SOURCE_POLCUTIL, 41 DUTIL_SOURCE_POLCUTIL,
41 DUTIL_SOURCE_PROCUTIL, 42 DUTIL_SOURCE_PROCUTIL,
42 DUTIL_SOURCE_REGUTIL, 43 DUTIL_SOURCE_REGUTIL,
diff --git a/src/libs/dutil/WixToolset.DUtil/inc/pipeutil.h b/src/libs/dutil/WixToolset.DUtil/inc/pipeutil.h
new file mode 100644
index 00000000..d16d768c
--- /dev/null
+++ b/src/libs/dutil/WixToolset.DUtil/inc/pipeutil.h
@@ -0,0 +1,104 @@
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#define ReleasePipeHandle(h) if (h != INVALID_HANDLE_VALUE) { ::CloseHandle(h); }
10#define ReleasePipeMessage(pMsg) if (pMsg) { PipeFreeMessage(pMsg); }
11
12
13// constants
14
15static const DWORD PIPE_WAIT_FOR_CONNECTION = 100; // wait a 10th of a second,
16static const DWORD PIPE_RETRY_FOR_CONNECTION = 1800; // for up to 3 minutes.
17
18
19// structs
20
21typedef struct _PIPE_MESSAGE
22{
23 DWORD dwMessageType;
24 DWORD cbData;
25
26 BOOL fAllocatedData;
27 LPVOID pvData;
28} PIPE_MESSAGE;
29
30
31// functions
32
33/*******************************************************************
34 PipeClientConnect - Called from the client process to connect back
35 to the pipe provided by the server process.
36
37*******************************************************************/
38DAPI_(HRESULT) PipeClientConnect(
39 __in_z LPCWSTR wzPipeName,
40 __out HANDLE* phPipe
41);
42
43/*******************************************************************
44 PipeCreate - create a duplex byte-mode named pipe compatible for use
45 with the other pipeutil functions.
46
47*******************************************************************/
48DAPI_(HRESULT) PipeCreate(
49 __in LPCWSTR wzName,
50 __in_opt LPSECURITY_ATTRIBUTES psa,
51 __out HANDLE* phPipe
52);
53
54/*******************************************************************
55 PipeOpen - opens an exist named pipe compatible for use with the other
56 pipeutil functions.
57
58*******************************************************************/
59DAPI_(HRESULT) PipeOpen(
60 __in_z LPCWSTR wzName,
61 __out HANDLE* phPipe
62);
63
64/*******************************************************************
65 PipeReadMessage - reads a message from the pipe. Free with
66 PipeFreeMessage().
67
68*******************************************************************/
69DAPI_(HRESULT) PipeReadMessage(
70 __in HANDLE hPipe,
71 __in PIPE_MESSAGE* pMsg
72);
73
74/*******************************************************************
75 PipeWriteMessage - writes a message to the pipe.
76
77*******************************************************************/
78DAPI_(HRESULT) PipeWriteMessage(
79 __in HANDLE hPipe,
80 __in DWORD dwMessageType,
81 __in_bcount_opt(cbData) LPVOID pvData,
82 __in SIZE_T cbData
83);
84
85/*******************************************************************
86 PipeFreeMessage - frees any memory allocated in PipeReadMessage.
87
88*******************************************************************/
89DAPI_(void) PipeFreeMessage(
90 __in PIPE_MESSAGE* pMsg
91);
92
93/*******************************************************************
94 PipeServerWaitForClientConnect - Called from the server process to
95 wait for a client to connect back to the provided pipe.
96
97*******************************************************************/
98DAPI_(HRESULT) PipeServerWaitForClientConnect(
99 __in HANDLE hPipe
100);
101
102#ifdef __cplusplus
103}
104#endif
diff --git a/src/libs/dutil/WixToolset.DUtil/perfutil.cpp b/src/libs/dutil/WixToolset.DUtil/perfutil.cpp
index bc138d34..f556ce79 100644
--- a/src/libs/dutil/WixToolset.DUtil/perfutil.cpp
+++ b/src/libs/dutil/WixToolset.DUtil/perfutil.cpp
@@ -39,7 +39,9 @@ extern "C" void DAPI PerfInitialize(
39 vdFrequency = 1000; // ticks are measured in milliseconds 39 vdFrequency = 1000; // ticks are measured in milliseconds
40 } 40 }
41 else 41 else
42 {
42 vdFrequency = static_cast<double>(liFrequency.QuadPart); 43 vdFrequency = static_cast<double>(liFrequency.QuadPart);
44 }
43} 45}
44 46
45 47
@@ -57,15 +59,23 @@ extern "C" void DAPI PerfClickTime(
57 LARGE_INTEGER* pli = pliElapsed; 59 LARGE_INTEGER* pli = pliElapsed;
58 60
59 if (!pli) // if elapsed time time was not requested, reset the start time 61 if (!pli) // if elapsed time time was not requested, reset the start time
62 {
60 pli = &liStart; 63 pli = &liStart;
64 }
61 65
62 if (vfHighPerformanceCounter) 66 if (vfHighPerformanceCounter)
67 {
63 ::QueryPerformanceCounter(pli); 68 ::QueryPerformanceCounter(pli);
69 }
64 else 70 else
71 {
65 pli->QuadPart = ::GetTickCount(); 72 pli->QuadPart = ::GetTickCount();
73 }
66 74
67 if (pliElapsed) 75 if (pliElapsed)
76 {
68 pliElapsed->QuadPart -= liStart.QuadPart; 77 pliElapsed->QuadPart -= liStart.QuadPart;
78 }
69} 79}
70 80
71 81
diff --git a/src/libs/dutil/WixToolset.DUtil/pipeutil.cpp b/src/libs/dutil/WixToolset.DUtil/pipeutil.cpp
new file mode 100644
index 00000000..4aa69d56
--- /dev/null
+++ b/src/libs/dutil/WixToolset.DUtil/pipeutil.cpp
@@ -0,0 +1,347 @@
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
6static const DWORD PIPE_64KB = 64 * 1024;
7static const LPCWSTR PIPE_NAME_FORMAT_STRING = L"\\\\.\\pipe\\%ls";
8
9
10// Exit macros
11#define PipeExitOnLastError(x, s, ...) ExitOnLastErrorSource(DUTIL_SOURCE_PIPEUTIL, x, s, __VA_ARGS__)
12#define PipeExitOnLastErrorDebugTrace(x, s, ...) ExitOnLastErrorDebugTraceSource(DUTIL_SOURCE_PIPEUTIL, x, s, __VA_ARGS__)
13#define PipeExitWithLastError(x, s, ...) ExitWithLastErrorSource(DUTIL_SOURCE_PIPEUTIL, x, s, __VA_ARGS__)
14#define PipeExitOnFailure(x, s, ...) ExitOnFailureSource(DUTIL_SOURCE_PIPEUTIL, x, s, __VA_ARGS__)
15#define PipeExitOnRootFailure(x, s, ...) ExitOnRootFailureSource(DUTIL_SOURCE_PIPEUTIL, x, s, __VA_ARGS__)
16#define PipeExitOnFailureDebugTrace(x, s, ...) ExitOnFailureDebugTraceSource(DUTIL_SOURCE_PIPEUTIL, x, s, __VA_ARGS__)
17#define PipeExitOnNull(p, x, e, s, ...) ExitOnNullSource(DUTIL_SOURCE_PIPEUTIL, p, x, e, s, __VA_ARGS__)
18#define PipeExitOnNullWithLastError(p, x, s, ...) ExitOnNullWithLastErrorSource(DUTIL_SOURCE_PIPEUTIL, p, x, s, __VA_ARGS__)
19#define PipeExitOnNullDebugTrace(p, x, e, s, ...) PipeExitOnNullDebugTraceSource(DUTIL_SOURCE_PIPEUTIL, p, x, e, s, __VA_ARGS__)
20#define PipeExitOnInvalidHandleWithLastError(p, x, s, ...) ExitOnInvalidHandleWithLastErrorSource(DUTIL_SOURCE_PIPEUTIL, p, x, s, __VA_ARGS__)
21#define PipeExitOnWin32Error(e, x, s, ...) ExitOnWin32ErrorSource(DUTIL_SOURCE_PIPEUTIL, e, x, s, __VA_ARGS__)
22#define PipeExitOnGdipFailure(g, x, s, ...) ExitOnGdipFailureSource(DUTIL_SOURCE_PIPEUTIL, g, x, s, __VA_ARGS__)
23
24
25static HRESULT AllocatePipeMessage(
26 __in DWORD dwMessageType,
27 __in_bcount_opt(cbData) LPVOID pvData,
28 __in SIZE_T cbData,
29 __out_bcount(cb) LPVOID* ppvMessage,
30 __out SIZE_T* pcbMessage
31);
32
33
34DAPI_(HRESULT) PipeClientConnect(
35 __in_z LPCWSTR wzPipeName,
36 __out HANDLE* phPipe
37)
38{
39 HRESULT hr = S_OK;
40 LPWSTR sczPipeName = NULL;
41 HANDLE hPipe = INVALID_HANDLE_VALUE;
42
43 // Try to connect to the parent.
44 hr = StrAllocFormatted(&sczPipeName, PIPE_NAME_FORMAT_STRING, wzPipeName);
45 PipeExitOnFailure(hr, "Failed to allocate name of pipe.");
46
47 hr = E_UNEXPECTED;
48 for (DWORD cRetry = 0; FAILED(hr) && cRetry < PIPE_RETRY_FOR_CONNECTION; ++cRetry)
49 {
50 hPipe = ::CreateFileW(sczPipeName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
51 if (INVALID_HANDLE_VALUE == hPipe)
52 {
53 hr = HRESULT_FROM_WIN32(::GetLastError());
54 if (E_FILENOTFOUND == hr) // if the pipe isn't created, call it a timeout waiting on the parent.
55 {
56 hr = HRESULT_FROM_WIN32(ERROR_TIMEOUT);
57 }
58
59 ::Sleep(PIPE_WAIT_FOR_CONNECTION);
60 }
61 else // we have a connection, go with it.
62 {
63 hr = S_OK;
64 }
65 }
66 PipeExitOnRootFailure(hr, "Failed to open parent pipe: %ls", sczPipeName);
67
68 *phPipe = hPipe;
69 hPipe = INVALID_HANDLE_VALUE;
70
71LExit:
72 ReleaseFileHandle(hPipe);
73 return hr;
74}
75
76DAPI_(HRESULT) PipeCreate(
77 __in LPCWSTR wzName,
78 __in_opt LPSECURITY_ATTRIBUTES psa,
79 __out HANDLE* phPipe
80)
81{
82 HRESULT hr = S_OK;
83 LPWSTR sczFullPipeName = NULL;
84 HANDLE hPipe = INVALID_HANDLE_VALUE;
85
86 // Create the pipe.
87 hr = StrAllocFormatted(&sczFullPipeName, PIPE_NAME_FORMAT_STRING, wzName);
88 PipeExitOnFailure(hr, "Failed to allocate full name of pipe: %ls", wzName);
89
90 // TODO: consider using overlapped IO to do waits on the pipe and still be able to cancel and such.
91 hPipe = ::CreateNamedPipeW(sczFullPipeName, PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, PIPE_64KB, PIPE_64KB, 1, psa);
92 if (INVALID_HANDLE_VALUE == hPipe)
93 {
94 PipeExitWithLastError(hr, "Failed to create pipe: %ls", sczFullPipeName);
95 }
96
97 *phPipe = hPipe;
98 hPipe = INVALID_HANDLE_VALUE;
99
100LExit:
101 ReleaseFileHandle(hPipe);
102 ReleaseStr(sczFullPipeName);
103
104 return hr;
105}
106
107DAPI_(void) PipeFreeMessage(
108 __in PIPE_MESSAGE* pMsg
109)
110{
111 if (pMsg->fAllocatedData)
112 {
113 ReleaseNullMem(pMsg->pvData);
114 pMsg->fAllocatedData = FALSE;
115 }
116}
117
118
119DAPI_(HRESULT) PipeOpen(
120 __in_z LPCWSTR wzName,
121 __out HANDLE* phPipe
122)
123{
124 HRESULT hr = S_OK;
125 LPWSTR sczPipeName = NULL;
126 HANDLE hPipe = INVALID_HANDLE_VALUE;
127
128 // Try to connect to the parent.
129 hr = StrAllocFormatted(&sczPipeName, PIPE_NAME_FORMAT_STRING, wzName);
130 PipeExitOnFailure(hr, "Failed to allocate name of pipe.");
131
132 hr = E_UNEXPECTED;
133 for (DWORD cRetry = 0; FAILED(hr) && cRetry < PIPE_RETRY_FOR_CONNECTION; ++cRetry)
134 {
135 hPipe = ::CreateFileW(sczPipeName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
136 if (INVALID_HANDLE_VALUE == hPipe)
137 {
138 hr = HRESULT_FROM_WIN32(::GetLastError());
139 if (E_FILENOTFOUND == hr) // if the pipe isn't created, call it a timeout waiting on the parent.
140 {
141 hr = HRESULT_FROM_WIN32(ERROR_TIMEOUT);
142 }
143
144 ::Sleep(PIPE_WAIT_FOR_CONNECTION);
145 }
146 else // we have a connection, go with it.
147 {
148 hr = S_OK;
149 }
150 }
151 PipeExitOnRootFailure(hr, "Failed to open parent pipe: %ls", sczPipeName);
152
153 *phPipe = hPipe;
154 hPipe = INVALID_HANDLE_VALUE;
155
156LExit:
157 ReleaseFileHandle(hPipe);
158 ReleaseStr(sczPipeName);
159
160 return hr;
161}
162
163DAPI_(HRESULT) PipeReadMessage(
164 __in HANDLE hPipe,
165 __in PIPE_MESSAGE* pMsg
166)
167{
168 HRESULT hr = S_OK;
169 BYTE pbMessageIdAndByteCount[sizeof(DWORD) + sizeof(DWORD)] = { };
170
171 hr = FileReadHandle(hPipe, pbMessageIdAndByteCount, sizeof(pbMessageIdAndByteCount));
172 if (HRESULT_FROM_WIN32(ERROR_BROKEN_PIPE) == hr)
173 {
174 memset(pbMessageIdAndByteCount, 0, sizeof(pbMessageIdAndByteCount));
175 hr = S_FALSE;
176 }
177 PipeExitOnFailure(hr, "Failed to read message from pipe.");
178
179 pMsg->dwMessageType = *(DWORD*)(pbMessageIdAndByteCount);
180 pMsg->cbData = *(DWORD*)(pbMessageIdAndByteCount + sizeof(DWORD));
181 if (pMsg->cbData)
182 {
183 pMsg->pvData = MemAlloc(pMsg->cbData, FALSE);
184 PipeExitOnNull(pMsg->pvData, hr, E_OUTOFMEMORY, "Failed to allocate data for message.");
185
186 hr = FileReadHandle(hPipe, reinterpret_cast<LPBYTE>(pMsg->pvData), pMsg->cbData);
187 PipeExitOnFailure(hr, "Failed to read data for message.");
188
189 pMsg->fAllocatedData = TRUE;
190 }
191
192LExit:
193 if (!pMsg->fAllocatedData && pMsg->pvData)
194 {
195 MemFree(pMsg->pvData);
196 }
197
198 return hr;
199}
200
201DAPI_(HRESULT) PipeServerWaitForClientConnect(
202 __in HANDLE hPipe
203)
204{
205 HRESULT hr = S_OK;
206 DWORD dwPipeState = PIPE_READMODE_BYTE | PIPE_NOWAIT;
207
208 // Temporarily make the pipe non-blocking so we will not get stuck in ::ConnectNamedPipe() forever
209 // if the child decides not to show up.
210 if (!::SetNamedPipeHandleState(hPipe, &dwPipeState, NULL, NULL))
211 {
212 PipeExitWithLastError(hr, "Failed to set pipe to non-blocking.");
213 }
214
215 // Loop for a while waiting for a connection from child process.
216 DWORD cRetry = 0;
217 do
218 {
219 if (!::ConnectNamedPipe(hPipe, NULL))
220 {
221 DWORD er = ::GetLastError();
222 if (ERROR_PIPE_CONNECTED == er)
223 {
224 hr = S_OK;
225 break;
226 }
227 else if (ERROR_PIPE_LISTENING == er)
228 {
229 if (cRetry < PIPE_RETRY_FOR_CONNECTION)
230 {
231 hr = HRESULT_FROM_WIN32(er);
232 }
233 else
234 {
235 hr = HRESULT_FROM_WIN32(ERROR_TIMEOUT);
236 break;
237 }
238
239 ++cRetry;
240 ::Sleep(PIPE_WAIT_FOR_CONNECTION);
241 }
242 else
243 {
244 hr = HRESULT_FROM_WIN32(er);
245 break;
246 }
247 }
248 } while (HRESULT_FROM_WIN32(ERROR_PIPE_LISTENING) == hr);
249 PipeExitOnRootFailure(hr, "Failed to wait for child to connect to pipe.");
250
251 // Put the pipe back in blocking mode.
252 dwPipeState = PIPE_READMODE_BYTE | PIPE_WAIT;
253 if (!::SetNamedPipeHandleState(hPipe, &dwPipeState, NULL, NULL))
254 {
255 PipeExitWithLastError(hr, "Failed to reset pipe to blocking.");
256 }
257
258LExit:
259 return hr;
260}
261
262DAPI_(HRESULT) PipeWriteMessage(
263 __in HANDLE hPipe,
264 __in DWORD dwMessageType,
265 __in_bcount_opt(cbData) LPVOID pvData,
266 __in SIZE_T cbData
267)
268{
269// HRESULT hr = S_OK;
270//
271// hr = FileWriteHandle(hPipe, reinterpret_cast<LPCBYTE>(&dwMessageType), sizeof(dwMessageType));
272// PipeExitOnFailure(hr, "Failed to write message id to pipe.");
273//
274// hr = FileWriteHandle(hPipe, reinterpret_cast<LPCBYTE>(&cbData), sizeof(cbData));
275// PipeExitOnFailure(hr, "Failed to write message data size to pipe.");
276//
277// if (pvData && cbData)
278// {
279// hr = FileWriteHandle(hPipe, reinterpret_cast<LPCBYTE>(pvData), cbData);
280// PipeExitOnFailure(hr, "Failed to write message data to pipe.");
281// }
282//
283//LExit:
284// return hr;
285 HRESULT hr = S_OK;
286 LPVOID pv = NULL;
287 SIZE_T cb = 0;
288
289 hr = AllocatePipeMessage(dwMessageType, pvData, cbData, &pv, &cb);
290 ExitOnFailure(hr, "Failed to allocate message to write.");
291
292 // Write the message.
293 hr = FileWriteHandle(hPipe, reinterpret_cast<LPCBYTE>(pv), cb);
294 ExitOnFailure(hr, "Failed to write message type to pipe.");
295
296LExit:
297 ReleaseMem(pv);
298 return hr;
299}
300
301static HRESULT AllocatePipeMessage(
302 __in DWORD dwMessageType,
303 __in_bcount_opt(cbData) LPVOID pvData,
304 __in SIZE_T cbData,
305 __out_bcount(cb) LPVOID* ppvMessage,
306 __out SIZE_T* pcbMessage
307)
308{
309 HRESULT hr = S_OK;
310 LPVOID pv = NULL;
311 size_t cb = 0;
312 DWORD dwcbData = 0;
313
314 // If no data was provided, ensure the count of bytes is zero.
315 if (!pvData)
316 {
317 cbData = 0;
318 }
319 else if (MAXDWORD < cbData)
320 {
321 ExitWithRootFailure(hr, E_INVALIDDATA, "Pipe message is too large.");
322 }
323
324 hr = ::SizeTAdd(sizeof(dwMessageType) + sizeof(dwcbData), cbData, &cb);
325 ExitOnRootFailure(hr, "Failed to calculate total pipe message size");
326
327 dwcbData = (DWORD)cbData;
328
329 // Allocate the message.
330 pv = MemAlloc(cb, FALSE);
331 ExitOnNull(pv, hr, E_OUTOFMEMORY, "Failed to allocate memory for message.");
332
333 memcpy_s(pv, cb, &dwMessageType, sizeof(dwMessageType));
334 memcpy_s(static_cast<BYTE*>(pv) + sizeof(dwMessageType), cb - sizeof(dwMessageType), &dwcbData, sizeof(dwcbData));
335 if (dwcbData)
336 {
337 memcpy_s(static_cast<BYTE*>(pv) + sizeof(dwMessageType) + sizeof(dwcbData), cb - sizeof(dwMessageType) - sizeof(dwcbData), pvData, dwcbData);
338 }
339
340 *pcbMessage = cb;
341 *ppvMessage = pv;
342 pv = NULL;
343
344LExit:
345 ReleaseMem(pv);
346 return hr;
347}
diff --git a/src/libs/dutil/WixToolset.DUtil/precomp.h b/src/libs/dutil/WixToolset.DUtil/precomp.h
index 607f7ce6..81dc7992 100644
--- a/src/libs/dutil/WixToolset.DUtil/precomp.h
+++ b/src/libs/dutil/WixToolset.DUtil/precomp.h
@@ -73,6 +73,7 @@
73#include "osutil.h" 73#include "osutil.h"
74#include "pathutil.h" 74#include "pathutil.h"
75#include "perfutil.h" 75#include "perfutil.h"
76#include "pipeutil.h"
76#include "polcutil.h" 77#include "polcutil.h"
77#include "procutil.h" 78#include "procutil.h"
78#include "queutil.h" 79#include "queutil.h"
diff --git a/src/libs/dutil/test/DUtilUnitTest/DUtilUnitTest.vcxproj b/src/libs/dutil/test/DUtilUnitTest/DUtilUnitTest.vcxproj
index edf8ba67..94826b8f 100644
--- a/src/libs/dutil/test/DUtilUnitTest/DUtilUnitTest.vcxproj
+++ b/src/libs/dutil/test/DUtilUnitTest/DUtilUnitTest.vcxproj
@@ -59,6 +59,7 @@
59 <ClCompile Include="MemUtilTest.cpp" /> 59 <ClCompile Include="MemUtilTest.cpp" />
60 <ClCompile Include="MonUtilTest.cpp" /> 60 <ClCompile Include="MonUtilTest.cpp" />
61 <ClCompile Include="PathUtilTest.cpp" /> 61 <ClCompile Include="PathUtilTest.cpp" />
62 <ClCompile Include="PipeUtilTest.cpp" />
62 <ClCompile Include="ProcUtilTest.cpp" /> 63 <ClCompile Include="ProcUtilTest.cpp" />
63 <ClCompile Include="precomp.cpp"> 64 <ClCompile Include="precomp.cpp">
64 <PrecompiledHeader>Create</PrecompiledHeader> 65 <PrecompiledHeader>Create</PrecompiledHeader>
diff --git a/src/libs/dutil/test/DUtilUnitTest/DUtilUnitTest.vcxproj.filters b/src/libs/dutil/test/DUtilUnitTest/DUtilUnitTest.vcxproj.filters
index d216f2af..e4972c1a 100644
--- a/src/libs/dutil/test/DUtilUnitTest/DUtilUnitTest.vcxproj.filters
+++ b/src/libs/dutil/test/DUtilUnitTest/DUtilUnitTest.vcxproj.filters
@@ -78,6 +78,9 @@
78 <ClCompile Include="LocUtilTests.cpp"> 78 <ClCompile Include="LocUtilTests.cpp">
79 <Filter>Source Files</Filter> 79 <Filter>Source Files</Filter>
80 </ClCompile> 80 </ClCompile>
81 <ClCompile Include="PipeUtilTest.cpp">
82 <Filter>Source Files</Filter>
83 </ClCompile>
81 </ItemGroup> 84 </ItemGroup>
82 <ItemGroup> 85 <ItemGroup>
83 <ResourceCompile Include="UnitTest.rc"> 86 <ResourceCompile Include="UnitTest.rc">
@@ -94,10 +97,9 @@
94 </ItemGroup> 97 </ItemGroup>
95 <ItemGroup> 98 <ItemGroup>
96 <None Include="$(MSBuildThisFileDirectory)xunit.runner.visualstudio.testadapter.dll" /> 99 <None Include="$(MSBuildThisFileDirectory)xunit.runner.visualstudio.testadapter.dll" />
97 <None Include="$(MSBuildThisFileDirectory)xunit.runner.reporters.net452.dll" />
98 <None Include="$(MSBuildThisFileDirectory)xunit.runner.utility.net452.dll" />
99 <None Include="$(MSBuildThisFileDirectory)xunit.abstractions.dll" /> 100 <None Include="$(MSBuildThisFileDirectory)xunit.abstractions.dll" />
100 <None Include="TestData\ApupUtilTests\FeedBv2.0.xml" /> 101 <None Include="TestData\ApupUtilTests\FeedBv2.0.xml" />
101 <None Include="TestData\LocUtilTests\strings.wxl" /> 102 <None Include="TestData\LocUtilTests\strings.wxl" />
103 <None Include="TestData\LocUtilTests\controls.wxl" />
102 </ItemGroup> 104 </ItemGroup>
103</Project> \ No newline at end of file 105</Project> \ No newline at end of file
diff --git a/src/libs/dutil/test/DUtilUnitTest/PipeUtilTest.cpp b/src/libs/dutil/test/DUtilUnitTest/PipeUtilTest.cpp
new file mode 100644
index 00000000..87a5e8f2
--- /dev/null
+++ b/src/libs/dutil/test/DUtilUnitTest/PipeUtilTest.cpp
@@ -0,0 +1,89 @@
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
5using namespace System;
6using namespace System::Security::Principal;
7using namespace Xunit;
8using namespace WixInternal::TestSupport;
9using namespace WixInternal::TestSupport::XunitExtensions;
10
11static DWORD STDAPICALLTYPE _TestPipeClientThreadProc(
12 __in LPVOID lpThreadParameter
13);
14
15namespace DutilTests
16{
17 public ref class PipeUtil
18 {
19 public:
20 [Fact]
21 void PipeConnectWriteAndRead()
22 {
23 HRESULT hr = S_OK;
24 HANDLE hServerPipe = INVALID_HANDLE_VALUE;
25 HANDLE hClientThread = NULL;
26 PIPE_MESSAGE msg = { };
27 DWORD dwThread = 42;
28 DWORD dwTestMessageId = 987654;
29
30 try
31 {
32 hr = PipeCreate(L"DutilTest", NULL, &hServerPipe);
33 NativeAssert::Succeeded(hr, "Failed to create server pipe.");
34
35 hClientThread = ::CreateThread(NULL, 0, _TestPipeClientThreadProc, &dwTestMessageId, 0, NULL);
36 if (hClientThread == 0)
37 {
38 NativeAssert::Fail("Failed to create client thread.");
39 return;
40 }
41
42 hr = PipeServerWaitForClientConnect(hServerPipe);
43 NativeAssert::Succeeded(hr, "Failed to wait for client to connect to pipe.");
44
45 hr = PipeReadMessage(hServerPipe, &msg);
46 NativeAssert::Succeeded(hr, "Failed to read message from client.");
47
48 NativeAssert::Equal(dwTestMessageId, msg.dwMessageType);
49
50 AppWaitForSingleObject(hClientThread, INFINITE);
51
52 ::GetExitCodeThread(hClientThread, &dwThread);
53 NativeAssert::Equal((DWORD)12, dwThread);
54 }
55 finally
56 {
57 ReleasePipeMessage(&msg);
58 ReleaseHandle(hClientThread);
59 ReleasePipeHandle(hServerPipe);
60 }
61 }
62 };
63}
64
65
66static DWORD STDAPICALLTYPE _TestPipeClientThreadProc(
67 __in LPVOID lpThreadParameter
68)
69{
70 HRESULT hr = S_OK;
71 HANDLE hClientPipe = INVALID_HANDLE_VALUE;
72
73 hr = PipeClientConnect(L"DutilTest", &hClientPipe);
74 if (FAILED(hr))
75 {
76 return hr;
77 }
78
79 ::Sleep(200);
80
81 hr = PipeWriteMessage(hClientPipe, *(LPDWORD)lpThreadParameter, NULL, 0);
82 if (FAILED(hr))
83 {
84 return hr;
85 }
86
87 ReleasePipeHandle(hClientPipe);
88 return 12;
89}
diff --git a/src/libs/dutil/test/DUtilUnitTest/precomp.h b/src/libs/dutil/test/DUtilUnitTest/precomp.h
index 92310b41..5a836074 100644
--- a/src/libs/dutil/test/DUtilUnitTest/precomp.h
+++ b/src/libs/dutil/test/DUtilUnitTest/precomp.h
@@ -24,6 +24,7 @@
24#include <locutil.h> 24#include <locutil.h>
25#include <memutil.h> 25#include <memutil.h>
26#include <pathutil.h> 26#include <pathutil.h>
27#include <pipeutil.h>
27#include <procutil.h> 28#include <procutil.h>
28#include <strutil.h> 29#include <strutil.h>
29#include <monutil.h> 30#include <monutil.h>