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>