main
cpp 608 lines 17.7 KB
Raw
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 static const DWORD PIPE_MESSAGE_DISCONNECT = 0xFFFFFFFF;
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 ZeroMemory(pMsg, sizeof(PIPE_MESSAGE));
118 }
119
120 DAPI_(void) PipeFreeRpcResult(
121 __in PIPE_RPC_RESULT* pResult
122 )
123 {
124 if (pResult->pbData)
125 {
126 ReleaseNullMem(pResult->pbData);
127 }
128 }
129
130 DAPI_(HRESULT) PipeOpen(
131 __in_z LPCWSTR wzName,
132 __out HANDLE* phPipe
133 )
134 {
135 HRESULT hr = S_OK;
136 LPWSTR sczPipeName = NULL;
137 HANDLE hPipe = INVALID_HANDLE_VALUE;
138
139 // Try to connect to the parent.
140 hr = StrAllocFormatted(&sczPipeName, PIPE_NAME_FORMAT_STRING, wzName);
141 PipeExitOnFailure(hr, "Failed to allocate name of pipe.");
142
143 hr = E_UNEXPECTED;
144 for (DWORD cRetry = 0; FAILED(hr) && cRetry < PIPE_RETRY_FOR_CONNECTION; ++cRetry)
145 {
146 hPipe = ::CreateFileW(sczPipeName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
147 if (INVALID_HANDLE_VALUE == hPipe)
148 {
149 hr = HRESULT_FROM_WIN32(::GetLastError());
150 if (E_FILENOTFOUND == hr) // if the pipe isn't created, call it a timeout waiting on the parent.
151 {
152 hr = HRESULT_FROM_WIN32(ERROR_TIMEOUT);
153 }
154
155 ::Sleep(PIPE_WAIT_FOR_CONNECTION);
156 }
157 else // we have a connection, go with it.
158 {
159 hr = S_OK;
160 }
161 }
162 PipeExitOnRootFailure(hr, "Failed to open parent pipe: %ls", sczPipeName);
163
164 *phPipe = hPipe;
165 hPipe = INVALID_HANDLE_VALUE;
166
167 LExit:
168 ReleaseFileHandle(hPipe);
169 ReleaseStr(sczPipeName);
170
171 return hr;
172 }
173
174 DAPI_(HRESULT) PipeReadMessage(
175 __in HANDLE hPipe,
176 __in PIPE_MESSAGE* pMsg
177 )
178 {
179 HRESULT hr = S_OK;
180 DWORD rgdwMessageIdAndByteCount[2] = { };
181 LPBYTE pbData = NULL;
182 DWORD cbData = 0;
183
184 hr = FileReadHandle(hPipe, reinterpret_cast<LPBYTE>(rgdwMessageIdAndByteCount), sizeof(rgdwMessageIdAndByteCount));
185 if (HRESULT_FROM_WIN32(ERROR_BROKEN_PIPE) == hr)
186 {
187 memset(rgdwMessageIdAndByteCount, 0, sizeof(rgdwMessageIdAndByteCount));
188 hr = S_FALSE;
189 }
190 PipeExitOnFailure(hr, "Failed to read message from pipe.");
191
192 Trace(REPORT_STANDARD, "RPC pipe %p read message: %u recv cbData: %u", hPipe, rgdwMessageIdAndByteCount[0], rgdwMessageIdAndByteCount[1]);
193
194 cbData = rgdwMessageIdAndByteCount[1];
195 if (cbData)
196 {
197 pbData = reinterpret_cast<LPBYTE>(MemAlloc(cbData, FALSE));
198 PipeExitOnNull(pbData, hr, E_OUTOFMEMORY, "Failed to allocate data for message.");
199
200 hr = FileReadHandle(hPipe, pbData, cbData);
201 PipeExitOnFailure(hr, "Failed to read data for message.");
202 }
203
204 pMsg->dwMessageType = rgdwMessageIdAndByteCount[0];
205 pMsg->cbData = cbData;
206 pMsg->pvData = pbData;
207 pbData = NULL;
208
209 if (PIPE_MESSAGE_DISCONNECT == pMsg->dwMessageType)
210 {
211 hr = S_FALSE;
212 }
213
214 LExit:
215 ReleaseMem(pbData);
216
217 return hr;
218 }
219
220 DAPI_(void) PipeRpcInitialize(
221 __in PIPE_RPC_HANDLE* phRpcPipe,
222 __in HANDLE hPipe,
223 __in BOOL fTakeHandleOwnership
224 )
225 {
226 phRpcPipe->hPipe = hPipe;
227 if (phRpcPipe->hPipe != INVALID_HANDLE_VALUE)
228 {
229 ::InitializeCriticalSection(&phRpcPipe->cs);
230 phRpcPipe->fOwnHandle = fTakeHandleOwnership;
231 phRpcPipe->fInitialized = TRUE;
232 }
233 }
234
235 DAPI_(BOOL) PipeRpcInitialized(
236 __in PIPE_RPC_HANDLE* phRpcPipe
237 )
238 {
239 return phRpcPipe->fInitialized && phRpcPipe->hPipe != INVALID_HANDLE_VALUE;
240 }
241
242 DAPI_(void) PipeRpcUninitiailize(
243 __in PIPE_RPC_HANDLE* phRpcPipe
244 )
245 {
246 if (phRpcPipe->fInitialized)
247 {
248 ::DeleteCriticalSection(&phRpcPipe->cs);
249
250 if (phRpcPipe->fOwnHandle)
251 {
252 ::CloseHandle(phRpcPipe->hPipe);
253 }
254
255 phRpcPipe->hPipe = INVALID_HANDLE_VALUE;
256 phRpcPipe->fOwnHandle = FALSE;
257 phRpcPipe->fInitialized = FALSE;
258 }
259 }
260
261 DAPI_(HRESULT) PipeRpcReadMessage(
262 __in PIPE_RPC_HANDLE* phRpcPipe,
263 __in PIPE_MESSAGE* pMsg
264 )
265 {
266 HRESULT hr = S_OK;
267
268 ::EnterCriticalSection(&phRpcPipe->cs);
269
270 hr = PipeReadMessage(phRpcPipe->hPipe, pMsg);
271 PipeExitOnFailure(hr, "Failed to read message from RPC pipe.");
272
273 LExit:
274 ::LeaveCriticalSection(&phRpcPipe->cs);
275
276 return hr;
277 }
278
279 DAPI_(HRESULT) PipeRpcRequest(
280 __in PIPE_RPC_HANDLE* phRpcPipe,
281 __in DWORD dwMessageType,
282 __in_bcount(cbArgs) LPVOID pvArgs,
283 __in SIZE_T cbArgs,
284 __in PIPE_RPC_RESULT* pResult
285 )
286 {
287 HRESULT hr = S_OK;
288 HANDLE hPipe = phRpcPipe->hPipe;
289 BOOL fLocked = FALSE;
290 DWORD rgResultAndDataSize[2] = { };
291 DWORD cbData = 0;
292 LPBYTE pbData = NULL;
293
294 if (hPipe == INVALID_HANDLE_VALUE)
295 {
296 ExitFunction();
297 }
298
299 Trace(REPORT_STANDARD, "RPC pipe %p request message: %d send cbArgs: %u", hPipe, dwMessageType, cbArgs);
300
301 ::EnterCriticalSection(&phRpcPipe->cs);
302 fLocked = TRUE;
303
304 // Send the message.
305 hr = PipeRpcWriteMessage(phRpcPipe, dwMessageType, pvArgs, cbArgs);
306 PipeExitOnFailure(hr, "Failed to send RPC pipe request.");
307
308 // Read the result and size of response data.
309 hr = FileReadHandle(hPipe, reinterpret_cast<LPBYTE>(rgResultAndDataSize), sizeof(rgResultAndDataSize));
310 PipeExitOnFailure(hr, "Failed to read result and size of message.");
311
312 pResult->hr = rgResultAndDataSize[0];
313 cbData = rgResultAndDataSize[1];
314
315 Trace(REPORT_STANDARD, "RPC pipe %p request message: %d returned hr: 0x%x, cbData: %u", hPipe, dwMessageType, pResult->hr, cbData);
316 AssertSz(FAILED(pResult->hr) || pResult->hr == S_OK || pResult->hr == S_FALSE, "Unexpected HRESULT from RPC pipe request.");
317
318 if (cbData)
319 {
320 pbData = reinterpret_cast<LPBYTE>(MemAlloc(cbData, TRUE));
321 PipeExitOnNull(pbData, hr, E_OUTOFMEMORY, "Failed to allocate memory for RPC pipe results.");
322
323 hr = FileReadHandle(hPipe, pbData, cbData);
324 PipeExitOnFailure(hr, "Failed to read result data.");
325 }
326
327 pResult->cbData = cbData;
328 pResult->pbData = pbData;
329 pbData = NULL;
330
331 hr = pResult->hr;
332 PipeExitOnFailure(hr, "RPC pipe client reported failure.");
333
334 LExit:
335 ReleaseMem(pbData);
336
337 if (fLocked)
338 {
339 ::LeaveCriticalSection(&phRpcPipe->cs);
340 }
341
342 return hr;
343 }
344
345 DAPI_(HRESULT) PipeRpcResponse(
346 __in PIPE_RPC_HANDLE* phRpcPipe,
347 __in DWORD
348 #if DEBUG
349 dwMessageType
350 #endif
351 ,
352 __in HRESULT hrResult,
353 __in_bcount(cbResult) LPVOID pvResult,
354 __in SIZE_T cbResult
355 )
356 {
357 HRESULT hr = S_OK;
358 HANDLE hPipe = phRpcPipe->hPipe;
359 DWORD dwcbResult = 0;
360
361 hr = DutilSizetToDword(pvResult ? cbResult : 0, &dwcbResult);
362 PipeExitOnFailure(hr, "Pipe message is too large.");
363
364 Trace(REPORT_STANDARD, "RPC pipe %p response message: %d returned hr: 0x%x, cbResult: %u", hPipe, dwMessageType, hrResult, dwcbResult);
365
366 ::EnterCriticalSection(&phRpcPipe->cs);
367
368 hr = FileWriteHandle(hPipe, reinterpret_cast<LPCBYTE>(&hrResult), sizeof(hrResult));
369 PipeExitOnFailure(hr, "Failed to write RPC result code to pipe.");
370
371 hr = FileWriteHandle(hPipe, reinterpret_cast<LPCBYTE>(&dwcbResult), sizeof(dwcbResult));
372 PipeExitOnFailure(hr, "Failed to write RPC result size to pipe.");
373
374 if (dwcbResult)
375 {
376 hr = FileWriteHandle(hPipe, reinterpret_cast<LPCBYTE>(pvResult), dwcbResult);
377 PipeExitOnFailure(hr, "Failed to write RPC result data to pipe.");
378 }
379
380 LExit:
381 ::LeaveCriticalSection(&phRpcPipe->cs);
382
383 return hr;
384 }
385
386 DAPI_(HRESULT) PipeRpcWriteMessage(
387 __in PIPE_RPC_HANDLE* phRpcPipe,
388 __in DWORD dwMessageType,
389 __in_bcount_opt(cbData) LPVOID pvData,
390 __in SIZE_T cbData
391 )
392 {
393 HRESULT hr = S_OK;
394
395 ::EnterCriticalSection(&phRpcPipe->cs);
396
397 hr = PipeWriteMessage(phRpcPipe->hPipe, dwMessageType, pvData, cbData);
398 PipeExitOnFailure(hr, "Failed to write message type to RPC pipe.");
399
400 LExit:
401 ::LeaveCriticalSection(&phRpcPipe->cs);
402
403 return hr;
404 }
405
406 DAPI_(HRESULT) PipeRpcWriteMessageReadResponse(
407 __in PIPE_RPC_HANDLE* phRpcPipe,
408 __in DWORD dwMessageType,
409 __in_bcount_opt(cbData) LPBYTE pbArgData,
410 __in SIZE_T cbArgData,
411 __in PIPE_RPC_RESULT* pResult
412 )
413 {
414 HRESULT hr = S_OK;
415 DWORD rgResultAndSize[2] = { };
416 LPBYTE pbResultData = NULL;
417 DWORD cbResultData = 0;
418
419 hr = PipeWriteMessage(phRpcPipe->hPipe, dwMessageType, pbArgData, cbArgData);
420 PipeExitOnFailure(hr, "Failed to write message type to RPC pipe.");
421
422 // Read the result and size of response.
423 hr = FileReadHandle(phRpcPipe->hPipe, reinterpret_cast<LPBYTE>(rgResultAndSize), sizeof(rgResultAndSize));
424 ExitOnFailure(hr, "Failed to read result and size of message.");
425
426 pResult->hr = rgResultAndSize[0];
427 cbResultData = rgResultAndSize[1];
428
429 if (cbResultData)
430 {
431 pbResultData = reinterpret_cast<LPBYTE>(MemAlloc(cbResultData, TRUE));
432 ExitOnNull(pbResultData, hr, E_OUTOFMEMORY, "Failed to allocate memory for BA results.");
433
434 hr = FileReadHandle(phRpcPipe->hPipe, pbResultData, cbResultData);
435 ExitOnFailure(hr, "Failed to read result and size of message.");
436 }
437
438 pResult->cbData = cbResultData;
439 pResult->pbData = pbResultData;
440 pbResultData = NULL;
441
442 hr = pResult->hr;
443 ExitOnFailure(hr, "BA reported failure.");
444
445 LExit:
446 ReleaseMem(pbResultData);
447
448 ::LeaveCriticalSection(&phRpcPipe->cs);
449
450 return hr;
451 }
452
453 DAPI_(HRESULT) PipeServerWaitForClientConnect(
454 __in HANDLE hClientProcess,
455 __in HANDLE hPipe
456 )
457 {
458 HRESULT hr = S_OK;
459 DWORD dwPipeState = PIPE_READMODE_BYTE | PIPE_NOWAIT;
460
461 // Temporarily make the pipe non-blocking so we will not get stuck in ::ConnectNamedPipe() forever
462 // if the client decides not to show up.
463 if (!::SetNamedPipeHandleState(hPipe, &dwPipeState, NULL, NULL))
464 {
465 PipeExitWithLastError(hr, "Failed to set pipe to non-blocking.");
466 }
467
468 // Loop for a while waiting for a connection from client process.
469 DWORD cRetry = 0;
470 do
471 {
472 if (!::ConnectNamedPipe(hPipe, NULL))
473 {
474 DWORD er = ::GetLastError();
475 if (ERROR_PIPE_CONNECTED == er)
476 {
477 hr = S_OK;
478 break;
479 }
480 else if (ERROR_PIPE_LISTENING == er)
481 {
482 if (cRetry < PIPE_RETRY_FOR_CONNECTION)
483 {
484 hr = HRESULT_FROM_WIN32(er);
485 }
486 else
487 {
488 hr = HRESULT_FROM_WIN32(ERROR_TIMEOUT);
489 break;
490 }
491
492 ++cRetry;
493
494 // Ensure the client is still around.
495 hr = ::AppWaitForSingleObject(hClientProcess, PIPE_WAIT_FOR_CONNECTION);
496 if (HRESULT_FROM_WIN32(WAIT_TIMEOUT) == hr)
497 {
498 // Timeout out means the process is still there, that's good.
499 hr = HRESULT_FROM_WIN32(ERROR_PIPE_LISTENING);
500 }
501 else if (SUCCEEDED(hr))
502 {
503 // Success means the process is gone, that's bad.
504 hr = HRESULT_FROM_WIN32(WAIT_ABANDONED);
505 }
506 }
507 else
508 {
509 hr = HRESULT_FROM_WIN32(er);
510 break;
511 }
512 }
513 } while (HRESULT_FROM_WIN32(ERROR_PIPE_LISTENING) == hr);
514 PipeExitOnRootFailure(hr, "Failed to wait for child to connect to pipe.");
515
516 // Put the pipe back in blocking mode.
517 dwPipeState = PIPE_READMODE_BYTE | PIPE_WAIT;
518 if (!::SetNamedPipeHandleState(hPipe, &dwPipeState, NULL, NULL))
519 {
520 PipeExitWithLastError(hr, "Failed to reset pipe to blocking.");
521 }
522
523 LExit:
524 return hr;
525 }
526
527 DAPI_(HRESULT) PipeWriteDisconnect(
528 __in HANDLE hPipe
529 )
530 {
531 HRESULT hr = S_OK;
532 LPVOID pv = NULL;
533 SIZE_T cb = 0;
534
535 hr = AllocatePipeMessage(PIPE_MESSAGE_DISCONNECT, NULL, 0, &pv, &cb);
536 ExitOnFailure(hr, "Failed to allocate message to write.");
537
538 // Write the message.
539 hr = FileWriteHandle(hPipe, reinterpret_cast<LPCBYTE>(pv), cb);
540 ExitOnFailure(hr, "Failed to write message type to pipe.");
541
542 LExit:
543 ReleaseMem(pv);
544 return hr;
545 }
546
547 DAPI_(HRESULT) PipeWriteMessage(
548 __in HANDLE hPipe,
549 __in DWORD dwMessageType,
550 __in_bcount_opt(cbData) LPVOID pvData,
551 __in SIZE_T cbData
552 )
553 {
554 HRESULT hr = S_OK;
555 LPVOID pv = NULL;
556 SIZE_T cb = 0;
557
558 hr = AllocatePipeMessage(dwMessageType, pvData, cbData, &pv, &cb);
559 ExitOnFailure(hr, "Failed to allocate message to write.");
560
561 // Write the message.
562 hr = FileWriteHandle(hPipe, reinterpret_cast<LPCBYTE>(pv), cb);
563 ExitOnFailure(hr, "Failed to write message type to pipe.");
564
565 LExit:
566 ReleaseMem(pv);
567
568 return hr;
569 }
570
571 static HRESULT AllocatePipeMessage(
572 __in DWORD dwMessageType,
573 __in_bcount_opt(cbData) LPVOID pvData,
574 __in SIZE_T cbData,
575 __out_bcount(*pcbMessage) LPVOID* ppvMessage,
576 __out SIZE_T* pcbMessage
577 )
578 {
579 HRESULT hr = S_OK;
580 LPVOID pv = NULL;
581 size_t cb = 0;
582 DWORD dwcbData = 0;
583
584 hr = DutilSizetToDword(pvData ? cbData : 0, &dwcbData);
585 PipeExitOnFailure(hr, "Pipe message is too large.");
586
587 hr = ::SizeTAdd(sizeof(dwMessageType) + sizeof(dwcbData), dwcbData, &cb);
588 ExitOnRootFailure(hr, "Failed to calculate total pipe message size");
589
590 // Allocate the message.
591 pv = MemAlloc(cb, FALSE);
592 ExitOnNull(pv, hr, E_OUTOFMEMORY, "Failed to allocate memory for message.");
593
594 memcpy_s(pv, cb, &dwMessageType, sizeof(dwMessageType));
595 memcpy_s(static_cast<BYTE*>(pv) + sizeof(dwMessageType), cb - sizeof(dwMessageType), &dwcbData, sizeof(dwcbData));
596 if (dwcbData)
597 {
598 memcpy_s(static_cast<BYTE*>(pv) + sizeof(dwMessageType) + sizeof(dwcbData), cb - sizeof(dwMessageType) - sizeof(dwcbData), pvData, dwcbData);
599 }
600
601 *pcbMessage = cb;
602 *ppvMessage = pv;
603 pv = NULL;
604
605 LExit:
606 ReleaseMem(pv);
607 return hr;
608 }