@joebigelow / wix / commits / 4e7b7c00

Add pipeutil to dutil

Plus a couple small clean-ups in a couple of dutil files.

Rob Mensching committed Jan 10, 2024 at 23:53 UTC 4e7b7c0059d76498d1c24f348dbf6d5799203fe0
12 files changed +570 -7
src/libs/dutil/WixToolset.DUtil/dutil.vcxproj
+2
@@ -87,6 +87,7 @@
87 <ClCompile Include="path3utl.cpp" />
88 <ClCompile Include="pathutil.cpp" />
89 <ClCompile Include="perfutil.cpp" />
90 + <ClCompile Include="pipeutil.cpp" />
91 <ClCompile Include="polcutil.cpp" />
92 <ClCompile Include="proc2utl.cpp" />
93 <ClCompile Include="proc3utl.cpp" />
@@ -152,6 +153,7 @@
153 <ClInclude Include="inc\osutil.h" />
154 <ClInclude Include="inc\pathutil.h" />
155 <ClInclude Include="inc\perfutil.h" />
156 + <ClInclude Include="inc\pipeutil.h" />
157 <ClInclude Include="inc\polcutil.h" />
158 <ClInclude Include="inc\procutil.h" />
159 <ClInclude Include="inc\queutil.h" />
src/libs/dutil/WixToolset.DUtil/dutil.vcxproj.filters
+6 -1
@@ -216,6 +216,9 @@
216 <ClCompile Include="deputil.cpp">
217 <Filter>Source Files</Filter>
218 </ClCompile>
219 + <ClCompile Include="pipeutil.cpp">
220 + <Filter>Source Files</Filter>
221 + </ClCompile>
222 </ItemGroup>
223 <ItemGroup>
224 <ClInclude Include="inc\aclutil.h">
@@ -398,11 +401,13 @@
401 <ClInclude Include="inc\deputil.h">
402 <Filter>Header Files</Filter>
403 </ClInclude>
404 + <ClInclude Include="inc\pipeutil.h">
405 + <Filter>Header Files</Filter>
406 + </ClInclude>
407 </ItemGroup>
408 <ItemGroup>
409 <None Include="xsd\thmutil.xsd">
410 <Filter>Header Files</Filter>
411 </None>
406 - <None Include="packages.config" />
412 </ItemGroup>
413 </Project>
\ No newline at end of file
src/libs/dutil/WixToolset.DUtil/fileutil.cpp
+4 -4
@@ -414,8 +414,8 @@ extern "C" HRESULT DAPI FileSetPointer(
414 Assert(INVALID_HANDLE_VALUE != hFile);
415
416 HRESULT hr = S_OK;
417 - LARGE_INTEGER liMove;
418 - LARGE_INTEGER liNewPosition;
417 + LARGE_INTEGER liMove = { };
418 + LARGE_INTEGER liNewPosition = { };
419
420 liMove.QuadPart = dw64Move;
421 if (!::SetFilePointerEx(hFile, liMove, &liNewPosition, dwMoveMethod))
@@ -843,7 +843,7 @@ extern "C" HRESULT DAPI FileCopyUsingHandles(
843 {
844 HRESULT hr = S_OK;
845 DWORD64 cbTotalCopied = 0;
846 - BYTE rgbData[4 * 1024];
846 + BYTE rgbData[4 * 1024] = { };
847 DWORD cbRead = 0;
848
849 do
@@ -887,7 +887,7 @@ extern "C" HRESULT DAPI FileCopyUsingHandlesWithProgress(
887 {
888 HRESULT hr = S_OK;
889 DWORD64 cbTotalCopied = 0;
890 - BYTE rgbData[64 * 1024];
890 + BYTE rgbData[64 * 1024] = { };
891 DWORD cbRead = 0;
892
893 LARGE_INTEGER liSourceSize = { };
src/libs/dutil/WixToolset.DUtil/inc/dutilsources.h
+1
@@ -37,6 +37,7 @@ typedef enum DUTIL_SOURCE
37 DUTIL_SOURCE_OSUTIL,
38 DUTIL_SOURCE_PATHUTIL,
39 DUTIL_SOURCE_PERFUTIL,
40 + DUTIL_SOURCE_PIPEUTIL,
41 DUTIL_SOURCE_POLCUTIL,
42 DUTIL_SOURCE_PROCUTIL,
43 DUTIL_SOURCE_REGUTIL,
src/libs/dutil/WixToolset.DUtil/inc/pipeutil.h new
+104
@@ -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
6 +extern "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 +
15 +static const DWORD PIPE_WAIT_FOR_CONNECTION = 100; // wait a 10th of a second,
16 +static const DWORD PIPE_RETRY_FOR_CONNECTION = 1800; // for up to 3 minutes.
17 +
18 +
19 +// structs
20 +
21 +typedef 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 +*******************************************************************/
38 +DAPI_(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 +*******************************************************************/
48 +DAPI_(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 +*******************************************************************/
59 +DAPI_(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 +*******************************************************************/
69 +DAPI_(HRESULT) PipeReadMessage(
70 + __in HANDLE hPipe,
71 + __in PIPE_MESSAGE* pMsg
72 +);
73 +
74 +/*******************************************************************
75 + PipeWriteMessage - writes a message to the pipe.
76 +
77 +*******************************************************************/
78 +DAPI_(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 +*******************************************************************/
89 +DAPI_(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 +*******************************************************************/
98 +DAPI_(HRESULT) PipeServerWaitForClientConnect(
99 + __in HANDLE hPipe
100 +);
101 +
102 +#ifdef __cplusplus
103 +}
104 +#endif
src/libs/dutil/WixToolset.DUtil/perfutil.cpp
+10
@@ -39,7 +39,9 @@ extern "C" void DAPI PerfInitialize(
39 vdFrequency = 1000; // ticks are measured in milliseconds
40 }
41 else
42 + {
43 vdFrequency = static_cast<double>(liFrequency.QuadPart);
44 + }
45 }
46
47
@@ -57,15 +59,23 @@ extern "C" void DAPI PerfClickTime(
59 LARGE_INTEGER* pli = pliElapsed;
60
61 if (!pli) // if elapsed time time was not requested, reset the start time
62 + {
63 pli = &liStart;
64 + }
65
66 if (vfHighPerformanceCounter)
67 + {
68 ::QueryPerformanceCounter(pli);
69 + }
70 else
71 + {
72 pli->QuadPart = ::GetTickCount();
73 + }
74
75 if (pliElapsed)
76 + {
77 pliElapsed->QuadPart -= liStart.QuadPart;
78 + }
79 }
80
81
src/libs/dutil/WixToolset.DUtil/pipeutil.cpp new
+347
@@ -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 +
6 +static const DWORD PIPE_64KB = 64 * 1024;
7 +static 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 +
25 +static 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 +
34 +DAPI_(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 +
71 +LExit:
72 + ReleaseFileHandle(hPipe);
73 + return hr;
74 +}
75 +
76 +DAPI_(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 +
100 +LExit:
101 + ReleaseFileHandle(hPipe);
102 + ReleaseStr(sczFullPipeName);
103 +
104 + return hr;
105 +}
106 +
107 +DAPI_(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 +
119 +DAPI_(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 +
156 +LExit:
157 + ReleaseFileHandle(hPipe);
158 + ReleaseStr(sczPipeName);
159 +
160 + return hr;
161 +}
162 +
163 +DAPI_(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 +
192 +LExit:
193 + if (!pMsg->fAllocatedData && pMsg->pvData)
194 + {
195 + MemFree(pMsg->pvData);
196 + }
197 +
198 + return hr;
199 +}
200 +
201 +DAPI_(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 +
258 +LExit:
259 + return hr;
260 +}
261 +
262 +DAPI_(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 +
296 +LExit:
297 + ReleaseMem(pv);
298 + return hr;
299 +}
300 +
301 +static 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 +
344 +LExit:
345 + ReleaseMem(pv);
346 + return hr;
347 +}
src/libs/dutil/WixToolset.DUtil/precomp.h
+1
@@ -73,6 +73,7 @@
73 #include "osutil.h"
74 #include "pathutil.h"
75 #include "perfutil.h"
76 +#include "pipeutil.h"
77 #include "polcutil.h"
78 #include "procutil.h"
79 #include "queutil.h"
src/libs/dutil/test/DUtilUnitTest/DUtilUnitTest.vcxproj
+1
@@ -59,6 +59,7 @@
59 <ClCompile Include="MemUtilTest.cpp" />
60 <ClCompile Include="MonUtilTest.cpp" />
61 <ClCompile Include="PathUtilTest.cpp" />
62 + <ClCompile Include="PipeUtilTest.cpp" />
63 <ClCompile Include="ProcUtilTest.cpp" />
64 <ClCompile Include="precomp.cpp">
65 <PrecompiledHeader>Create</PrecompiledHeader>
src/libs/dutil/test/DUtilUnitTest/DUtilUnitTest.vcxproj.filters
+4 -2
@@ -78,6 +78,9 @@
78 <ClCompile Include="LocUtilTests.cpp">
79 <Filter>Source Files</Filter>
80 </ClCompile>
81 + <ClCompile Include="PipeUtilTest.cpp">
82 + <Filter>Source Files</Filter>
83 + </ClCompile>
84 </ItemGroup>
85 <ItemGroup>
86 <ResourceCompile Include="UnitTest.rc">
@@ -94,10 +97,9 @@
97 </ItemGroup>
98 <ItemGroup>
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" />
100 <None Include="$(MSBuildThisFileDirectory)xunit.abstractions.dll" />
101 <None Include="TestData\ApupUtilTests\FeedBv2.0.xml" />
102 <None Include="TestData\LocUtilTests\strings.wxl" />
103 + <None Include="TestData\LocUtilTests\controls.wxl" />
104 </ItemGroup>
105 </Project>
\ No newline at end of file
src/libs/dutil/test/DUtilUnitTest/PipeUtilTest.cpp new
+89
@@ -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 +
5 +using namespace System;
6 +using namespace System::Security::Principal;
7 +using namespace Xunit;
8 +using namespace WixInternal::TestSupport;
9 +using namespace WixInternal::TestSupport::XunitExtensions;
10 +
11 +static DWORD STDAPICALLTYPE _TestPipeClientThreadProc(
12 + __in LPVOID lpThreadParameter
13 +);
14 +
15 +namespace 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 +
66 +static 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 +}
src/libs/dutil/test/DUtilUnitTest/precomp.h
+1
@@ -24,6 +24,7 @@
24 #include <locutil.h>
25 #include <memutil.h>
26 #include <pathutil.h>
27 +#include <pipeutil.h>
28 #include <procutil.h>
29 #include <strutil.h>
30 #include <monutil.h>