main
cpp 683 lines 19.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 // Exit macros
7 #define ProcExitOnLastError(x, s, ...) ExitOnLastErrorSource(DUTIL_SOURCE_PROCUTIL, x, s, __VA_ARGS__)
8 #define ProcExitOnLastErrorDebugTrace(x, s, ...) ExitOnLastErrorDebugTraceSource(DUTIL_SOURCE_PROCUTIL, x, s, __VA_ARGS__)
9 #define ProcExitWithLastError(x, s, ...) ExitWithLastErrorSource(DUTIL_SOURCE_PROCUTIL, x, s, __VA_ARGS__)
10 #define ProcExitOnFailure(x, s, ...) ExitOnFailureSource(DUTIL_SOURCE_PROCUTIL, x, s, __VA_ARGS__)
11 #define ProcExitOnRootFailure(x, s, ...) ExitOnRootFailureSource(DUTIL_SOURCE_PROCUTIL, x, s, __VA_ARGS__)
12 #define ProcExitWithRootFailure(x, e, s, ...) ExitWithRootFailureSource(DUTIL_SOURCE_PROCUTIL, x, e, s, __VA_ARGS__)
13 #define ProcExitOnFailureDebugTrace(x, s, ...) ExitOnFailureDebugTraceSource(DUTIL_SOURCE_PROCUTIL, x, s, __VA_ARGS__)
14 #define ProcExitOnNull(p, x, e, s, ...) ExitOnNullSource(DUTIL_SOURCE_PROCUTIL, p, x, e, s, __VA_ARGS__)
15 #define ProcExitOnNullWithLastError(p, x, s, ...) ExitOnNullWithLastErrorSource(DUTIL_SOURCE_PROCUTIL, p, x, s, __VA_ARGS__)
16 #define ProcExitOnNullDebugTrace(p, x, e, s, ...) ExitOnNullDebugTraceSource(DUTIL_SOURCE_PROCUTIL, p, x, e, 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__)
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__)
21
22
23 // private functions
24 static HRESULT CreatePipes(
25 __out HANDLE *phOutRead,
26 __out HANDLE *phOutWrite,
27 __out HANDLE *phErrWrite,
28 __out HANDLE *phInRead,
29 __out HANDLE *phInWrite
30 );
31
32 static BOOL CALLBACK CloseWindowEnumCallback(
33 __in HWND hWnd,
34 __in LPARAM lParam
35 );
36
37
38 extern "C" HRESULT DAPI ProcElevated(
39 __in HANDLE hProcess,
40 __out BOOL* pfElevated
41 )
42 {
43 HRESULT hr = S_OK;
44 HANDLE hToken = NULL;
45 TOKEN_ELEVATION tokenElevated = { };
46 DWORD cbToken = 0;
47
48 if (!::OpenProcessToken(hProcess, TOKEN_QUERY, &hToken))
49 {
50 ProcExitWithLastError(hr, "Failed to open process token.");
51 }
52
53 if (::GetTokenInformation(hToken, TokenElevation, &tokenElevated, sizeof(TOKEN_ELEVATION), &cbToken))
54 {
55 *pfElevated = (0 != tokenElevated.TokenIsElevated);
56 }
57 else
58 {
59 DWORD er = ::GetLastError();
60 hr = HRESULT_FROM_WIN32(er);
61
62 // If it's invalid argument, this means the OS doesn't support TokenElevation, so we're not elevated.
63 if (E_INVALIDARG == hr)
64 {
65 *pfElevated = FALSE;
66 hr = S_OK;
67 }
68 else
69 {
70 ProcExitOnRootFailure(hr, "Failed to get elevation token from process.");
71 }
72 }
73
74 LExit:
75 ReleaseHandle(hToken);
76
77 return hr;
78 }
79
80 extern "C" HRESULT DAPI ProcSystem(
81 __in HANDLE hProcess,
82 __out BOOL* pfSystem
83 )
84 {
85 HRESULT hr = S_OK;
86 TOKEN_USER* pTokenUser = NULL;
87
88 hr = ProcGetTokenInformation(hProcess, TokenUser, reinterpret_cast<LPVOID*>(&pTokenUser));
89 ProcExitOnFailure(hr, "Failed to get TokenUser from process token.");
90
91 *pfSystem = ::IsWellKnownSid(pTokenUser->User.Sid, WinLocalSystemSid);
92
93 LExit:
94 ReleaseMem(pTokenUser);
95
96 return hr;
97 }
98
99 extern "C" HRESULT DAPI ProcGetTokenInformation(
100 __in HANDLE hProcess,
101 __in TOKEN_INFORMATION_CLASS tokenInformationClass,
102 __out LPVOID* ppvTokenInformation
103 )
104 {
105 HRESULT hr = S_OK;
106 DWORD er = ERROR_SUCCESS;
107 HANDLE hToken = NULL;
108 LPVOID pvTokenInformation = NULL;
109 DWORD cbToken = 0;
110
111 if (!::OpenProcessToken(hProcess, TOKEN_QUERY, &hToken))
112 {
113 ProcExitWithLastError(hr, "Failed to open process token.");
114 }
115
116 if (!::GetTokenInformation(hToken, tokenInformationClass, pvTokenInformation, 0, &cbToken))
117 {
118 er = ::GetLastError();
119 }
120
121 if (er != ERROR_INSUFFICIENT_BUFFER)
122 {
123 ProcExitOnWin32Error(er, hr, "Failed to get information from process token size.");
124 }
125
126 pvTokenInformation = MemAlloc(cbToken, TRUE);
127 ProcExitOnNull(pvTokenInformation, hr, E_OUTOFMEMORY, "Failed to allocate token information.");
128
129 if (!::GetTokenInformation(hToken, tokenInformationClass, pvTokenInformation, cbToken, &cbToken))
130 {
131 ProcExitWithLastError(hr, "Failed to get information from process token.");
132 }
133
134 *ppvTokenInformation = pvTokenInformation;
135 pvTokenInformation = NULL;
136
137 LExit:
138 ReleaseMem(pvTokenInformation);
139 ReleaseHandle(hToken);
140
141 return hr;
142 }
143
144 extern "C" HRESULT DAPI ProcHasPrivilege(
145 __in HANDLE hProcess,
146 __in LPCWSTR wzPrivilegeName,
147 __out BOOL* pfHasPrivilege
148 )
149 {
150 HRESULT hr = S_OK;
151 TOKEN_PRIVILEGES* pTokenPrivileges = NULL;
152 LUID luidPrivilege = { };
153
154 *pfHasPrivilege = FALSE;
155
156 if (!::LookupPrivilegeValueW(NULL, wzPrivilegeName, &luidPrivilege))
157 {
158 ProcExitWithLastError(hr, "Failed to get privilege LUID: %ls", wzPrivilegeName);
159 }
160
161 hr = ProcGetTokenInformation(hProcess, TokenPrivileges, reinterpret_cast<LPVOID*>(&pTokenPrivileges));
162 ProcExitOnFailure(hr, "Failed to get token privilege information.");
163
164 for (DWORD i = 0; i < pTokenPrivileges->PrivilegeCount; ++i)
165 {
166 LUID* pTokenLuid = &pTokenPrivileges->Privileges[i].Luid;
167
168 if (luidPrivilege.LowPart == pTokenLuid->LowPart && luidPrivilege.HighPart == pTokenLuid->HighPart)
169 {
170 *pfHasPrivilege = TRUE;
171 break;
172 }
173 }
174
175 LExit:
176 ReleaseMem(pTokenPrivileges);
177
178 return hr;
179 }
180
181 extern "C" HRESULT DAPI ProcEnablePrivilege(
182 __in HANDLE hProcess,
183 __in LPCWSTR wzPrivilegeName
184 )
185 {
186 HRESULT hr = S_OK;
187 HANDLE hToken = NULL;
188 TOKEN_PRIVILEGES priv = { };
189
190 priv.PrivilegeCount = 1;
191 priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
192
193 if (!::LookupPrivilegeValueW(NULL, wzPrivilegeName, &priv.Privileges[0].Luid))
194 {
195 ProcExitWithLastError(hr, "Failed to get privilege LUID: %ls", wzPrivilegeName);
196 }
197
198 if (!::OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES, &hToken))
199 {
200 ProcExitWithLastError(hr, "Failed to get process token to adjust privileges.");
201 }
202
203 if (!::AdjustTokenPrivileges(hToken, FALSE, &priv, sizeof(TOKEN_PRIVILEGES), NULL, 0))
204 {
205 ProcExitWithLastError(hr, "Failed to adjust token to add privilege: %ls", wzPrivilegeName);
206 }
207
208 if (ERROR_NOT_ALL_ASSIGNED == ::GetLastError())
209 {
210 hr = S_FALSE;
211 }
212
213 LExit:
214 ReleaseHandle(hToken);
215
216 return hr;
217 }
218
219 extern "C" HRESULT DAPI ProcWow64(
220 __in HANDLE hProcess,
221 __out BOOL* pfWow64
222 )
223 {
224 HRESULT hr = S_OK;
225 BOOL fIsWow64 = FALSE;
226
227 typedef BOOL(WINAPI* LPFN_ISWOW64PROCESS2)(HANDLE, USHORT *, USHORT *);
228 LPFN_ISWOW64PROCESS2 pfnIsWow64Process2 = (LPFN_ISWOW64PROCESS2)::GetProcAddress(::GetModuleHandleW(L"kernel32"), "IsWow64Process2");
229
230 if (pfnIsWow64Process2)
231 {
232 USHORT usProcessMachine = IMAGE_FILE_MACHINE_UNKNOWN;
233 if (!pfnIsWow64Process2(hProcess, &usProcessMachine, nullptr))
234 {
235 ProcExitWithLastError(hr, "Failed to check WOW64 process - IsWow64Process2.");
236 }
237
238 if (usProcessMachine != IMAGE_FILE_MACHINE_UNKNOWN)
239 {
240 fIsWow64 = TRUE;
241 }
242 }
243 else
244 {
245 typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS)(HANDLE, PBOOL);
246 LPFN_ISWOW64PROCESS pfnIsWow64Process = (LPFN_ISWOW64PROCESS)::GetProcAddress(::GetModuleHandleW(L"kernel32"), "IsWow64Process");
247
248 if (pfnIsWow64Process)
249 {
250 if (!pfnIsWow64Process(hProcess, &fIsWow64))
251 {
252 ProcExitWithLastError(hr, "Failed to check WOW64 process - IsWow64Process.");
253 }
254 }
255 }
256
257 *pfWow64 = fIsWow64;
258
259 LExit:
260 return hr;
261 }
262
263 extern "C" HRESULT DAPI ProcNativeMachine(
264 __in HANDLE hProcess,
265 __out USHORT* pusNativeMachine
266 )
267 {
268 // S_FALSE will indicate that the method is not supported.
269 HRESULT hr = S_FALSE;
270
271 typedef BOOL(WINAPI* LPFN_ISWOW64PROCESS2)(HANDLE, USHORT *, USHORT *);
272 LPFN_ISWOW64PROCESS2 pfnIsWow64Process2 = (LPFN_ISWOW64PROCESS2)::GetProcAddress(::GetModuleHandleW(L"kernel32"), "IsWow64Process2");
273
274 if (pfnIsWow64Process2)
275 {
276 USHORT usProcessMachineUnused = IMAGE_FILE_MACHINE_UNKNOWN;
277 if (!pfnIsWow64Process2(hProcess, &usProcessMachineUnused, pusNativeMachine))
278 {
279 ExitWithLastError(hr, "Failed to check WOW64 process - IsWow64Process2.");
280 }
281 hr = S_OK;
282 }
283
284 LExit:
285 return hr;
286 }
287
288 extern "C" HRESULT DAPI ProcDisableWowFileSystemRedirection(
289 __in PROC_FILESYSTEMREDIRECTION* pfsr
290 )
291 {
292 AssertSz(!pfsr->fDisabled, "File system redirection was already disabled.");
293 HRESULT hr = S_OK;
294
295 typedef BOOL (WINAPI *LPFN_Wow64DisableWow64FsRedirection)(PVOID *);
296 LPFN_Wow64DisableWow64FsRedirection pfnWow64DisableWow64FsRedirection = (LPFN_Wow64DisableWow64FsRedirection)::GetProcAddress(::GetModuleHandleW(L"kernel32"), "Wow64DisableWow64FsRedirection");
297
298 if (!pfnWow64DisableWow64FsRedirection)
299 {
300 ExitFunction1(hr = E_NOTIMPL);
301 }
302
303 if (!pfnWow64DisableWow64FsRedirection(&pfsr->pvRevertState))
304 {
305 ProcExitWithLastError(hr, "Failed to disable file system redirection.");
306 }
307
308 pfsr->fDisabled = TRUE;
309
310 LExit:
311 return hr;
312 }
313
314 extern "C" HRESULT DAPI ProcRevertWowFileSystemRedirection(
315 __in PROC_FILESYSTEMREDIRECTION* pfsr
316 )
317 {
318 HRESULT hr = S_OK;
319
320 if (pfsr->fDisabled)
321 {
322 typedef BOOL (WINAPI *LPFN_Wow64RevertWow64FsRedirection)(PVOID);
323 LPFN_Wow64RevertWow64FsRedirection pfnWow64RevertWow64FsRedirection = (LPFN_Wow64RevertWow64FsRedirection)::GetProcAddress(::GetModuleHandleW(L"kernel32"), "Wow64RevertWow64FsRedirection");
324
325 if (!pfnWow64RevertWow64FsRedirection(pfsr->pvRevertState))
326 {
327 ProcExitWithLastError(hr, "Failed to revert file system redirection.");
328 }
329
330 pfsr->fDisabled = FALSE;
331 pfsr->pvRevertState = NULL;
332 }
333
334 LExit:
335 return hr;
336 }
337
338
339 extern "C" HRESULT DAPI ProcExec(
340 __in_z LPCWSTR wzExecutablePath,
341 __in_z_opt LPCWSTR wzCommandLine,
342 __in int nCmdShow,
343 __out HANDLE *phProcess
344 )
345 {
346 HRESULT hr = S_OK;
347 LPWSTR sczFullCommandLine = NULL;
348 STARTUPINFOW si = { };
349 PROCESS_INFORMATION pi = { };
350
351 hr = StrAllocFormatted(&sczFullCommandLine, L"\"%ls\" %ls", wzExecutablePath, wzCommandLine ? wzCommandLine : L"");
352 ProcExitOnFailure(hr, "Failed to allocate full command-line.");
353
354 si.cb = sizeof(si);
355 si.dwFlags = STARTF_USESHOWWINDOW;
356 si.wShowWindow = static_cast<WORD>(nCmdShow);
357 if (!::CreateProcessW(wzExecutablePath, sczFullCommandLine, NULL, NULL, FALSE, 0, 0, NULL, &si, &pi))
358 {
359 ProcExitWithLastError(hr, "Failed to create process: %ls", sczFullCommandLine);
360 }
361
362 *phProcess = pi.hProcess;
363 pi.hProcess = NULL;
364
365 LExit:
366 ReleaseHandle(pi.hThread);
367 ReleaseHandle(pi.hProcess);
368 ReleaseStr(sczFullCommandLine);
369
370 return hr;
371 }
372
373
374 /********************************************************************
375 ProcExecute() - executes a command-line.
376
377 *******************************************************************/
378 extern "C" HRESULT DAPI ProcExecute(
379 __in_z_opt LPCWSTR wzApplicationName,
380 __in_z LPWSTR wzCommand,
381 __out HANDLE *phProcess,
382 __out_opt HANDLE *phChildStdIn,
383 __out_opt HANDLE *phChildStdOutErr
384 )
385 {
386 HRESULT hr = S_OK;
387
388 PROCESS_INFORMATION pi = { };
389 STARTUPINFOW si = { };
390
391 HANDLE hOutRead = INVALID_HANDLE_VALUE;
392 HANDLE hOutWrite = INVALID_HANDLE_VALUE;
393 HANDLE hErrWrite = INVALID_HANDLE_VALUE;
394 HANDLE hInRead = INVALID_HANDLE_VALUE;
395 HANDLE hInWrite = INVALID_HANDLE_VALUE;
396
397 // Create redirect pipes.
398 hr = CreatePipes(&hOutRead, &hOutWrite, &hErrWrite, &hInRead, &hInWrite);
399 ProcExitOnFailure(hr, "failed to create output pipes");
400
401 // Set up startup structure.
402 si.cb = sizeof(STARTUPINFOW);
403 si.dwFlags = STARTF_USESTDHANDLES;
404 si.hStdInput = hInRead;
405 si.hStdOutput = hOutWrite;
406 si.hStdError = hErrWrite;
407
408 #pragma prefast(push)
409 #pragma prefast(disable:25028)
410 if (::CreateProcessW(wzApplicationName,
411 wzCommand, // command line
412 NULL, // security info
413 NULL, // thread info
414 TRUE, // inherit handles
415 ::GetPriorityClass(::GetCurrentProcess()) | CREATE_NO_WINDOW, // creation flags
416 NULL, // environment
417 NULL, // cur dir
418 &si,
419 &pi))
420 #pragma prefast(pop)
421 {
422 // Close child process output/input handles so child doesn't hang
423 // while waiting for input from parent process.
424 ::CloseHandle(hOutWrite);
425 hOutWrite = INVALID_HANDLE_VALUE;
426
427 ::CloseHandle(hErrWrite);
428 hErrWrite = INVALID_HANDLE_VALUE;
429
430 ::CloseHandle(hInRead);
431 hInRead = INVALID_HANDLE_VALUE;
432 }
433 else
434 {
435 ProcExitWithLastError(hr, "Process failed to execute.");
436 }
437
438 *phProcess = pi.hProcess;
439 pi.hProcess = 0;
440
441 if (phChildStdIn)
442 {
443 *phChildStdIn = hInWrite;
444 hInWrite = INVALID_HANDLE_VALUE;
445 }
446
447 if (phChildStdOutErr)
448 {
449 *phChildStdOutErr = hOutRead;
450 hOutRead = INVALID_HANDLE_VALUE;
451 }
452
453 LExit:
454 if (pi.hThread)
455 {
456 ::CloseHandle(pi.hThread);
457 }
458
459 if (pi.hProcess)
460 {
461 ::CloseHandle(pi.hProcess);
462 }
463
464 ReleaseFileHandle(hOutRead);
465 ReleaseFileHandle(hOutWrite);
466 ReleaseFileHandle(hErrWrite);
467 ReleaseFileHandle(hInRead);
468 ReleaseFileHandle(hInWrite);
469
470 return hr;
471 }
472
473
474 /********************************************************************
475 ProcWaitForCompletion() - waits for process to complete and gets return code.
476
477 *******************************************************************/
478 extern "C" HRESULT DAPI ProcWaitForCompletion(
479 __in HANDLE hProcess,
480 __in DWORD dwTimeout,
481 __out_opt DWORD* pdwReturnCode
482 )
483 {
484 HRESULT hr = S_OK;
485 BOOL fTimedOut = FALSE;
486
487 // Wait for everything to finish.
488 hr = AppWaitForSingleObject(hProcess, dwTimeout);
489 ProcExitOnWaitObjectFailure(hr, fTimedOut, "Failed to wait for process to complete.");
490
491 if (fTimedOut)
492 {
493 hr = HRESULT_FROM_WIN32(WAIT_TIMEOUT);
494 }
495 else if (pdwReturnCode && !::GetExitCodeProcess(hProcess, pdwReturnCode))
496 {
497 ProcExitWithLastError(hr, "Failed to get process return code.");
498 }
499
500 LExit:
501 return hr;
502 }
503
504 /********************************************************************
505 ProcWaitForIds() - waits for multiple processes to complete.
506
507 *******************************************************************/
508 extern "C" HRESULT DAPI ProcWaitForIds(
509 __in_ecount(cProcessIds) const DWORD rgdwProcessIds[],
510 __in DWORD cProcessIds,
511 __in DWORD dwMilliseconds
512 )
513 {
514 HRESULT hr = S_OK;
515 HANDLE hProcess = NULL;
516 HANDLE* rghProcesses = NULL;
517 DWORD cProcesses = 0;
518 BOOL fTimedOut = FALSE;
519
520 rghProcesses = static_cast<HANDLE*>(MemAlloc(sizeof(HANDLE) * cProcessIds, TRUE));
521 ProcExitOnNull(rgdwProcessIds, hr, E_OUTOFMEMORY, "Failed to allocate array for process ID Handles.");
522
523 for (DWORD i = 0; i < cProcessIds; ++i)
524 {
525 hProcess = ::OpenProcess(SYNCHRONIZE, FALSE, rgdwProcessIds[i]);
526 if (hProcess != NULL)
527 {
528 rghProcesses[cProcesses++] = hProcess;
529 }
530 }
531
532 hr = AppWaitForMultipleObjects(cProcesses, rghProcesses, TRUE, dwMilliseconds, NULL);
533 ProcExitOnWaitObjectFailure(hr, fTimedOut, "Failed to wait for processes to complete.");
534
535 if (fTimedOut)
536 {
537 ProcExitWithRootFailure(hr, HRESULT_FROM_WIN32(WAIT_TIMEOUT), "Timed out while waiting for processes to complete.");
538 }
539
540 LExit:
541 if (rghProcesses)
542 {
543 for (DWORD i = 0; i < cProcesses; ++i)
544 {
545 if (NULL != rghProcesses[i])
546 {
547 ::CloseHandle(rghProcesses[i]);
548 }
549 }
550
551 MemFree(rghProcesses);
552 }
553
554 return hr;
555 }
556
557 /********************************************************************
558 ProcCloseIds() - sends WM_CLOSE messages to all process ids.
559
560 *******************************************************************/
561 extern "C" HRESULT DAPI ProcCloseIds(
562 __in_ecount(cProcessIds) const DWORD* pdwProcessIds,
563 __in DWORD cProcessIds
564 )
565 {
566 HRESULT hr = S_OK;
567
568 for (DWORD i = 0; i < cProcessIds; ++i)
569 {
570 if (!::EnumWindows(&CloseWindowEnumCallback, pdwProcessIds[i]))
571 {
572 ProcExitWithLastError(hr, "Failed to enumerate windows.");
573 }
574 }
575
576 LExit:
577 return hr;
578 }
579
580
581 static HRESULT CreatePipes(
582 __out HANDLE *phOutRead,
583 __out HANDLE *phOutWrite,
584 __out HANDLE *phErrWrite,
585 __out HANDLE *phInRead,
586 __out HANDLE *phInWrite
587 )
588 {
589 HRESULT hr = S_OK;
590 SECURITY_ATTRIBUTES sa;
591 HANDLE hOutTemp = INVALID_HANDLE_VALUE;
592 HANDLE hInTemp = INVALID_HANDLE_VALUE;
593
594 HANDLE hOutRead = INVALID_HANDLE_VALUE;
595 HANDLE hOutWrite = INVALID_HANDLE_VALUE;
596 HANDLE hErrWrite = INVALID_HANDLE_VALUE;
597 HANDLE hInRead = INVALID_HANDLE_VALUE;
598 HANDLE hInWrite = INVALID_HANDLE_VALUE;
599
600 // Fill out security structure so we can inherit handles
601 ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));
602 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
603 sa.bInheritHandle = TRUE;
604 sa.lpSecurityDescriptor = NULL;
605
606 // Create pipes
607 if (!::CreatePipe(&hOutTemp, &hOutWrite, &sa, 0))
608 {
609 ProcExitWithLastError(hr, "failed to create output pipe");
610 }
611
612 if (!::CreatePipe(&hInRead, &hInTemp, &sa, 0))
613 {
614 ProcExitWithLastError(hr, "failed to create input pipe");
615 }
616
617 // Duplicate output pipe so standard error and standard output write to the same pipe.
618 if (!::DuplicateHandle(::GetCurrentProcess(), hOutWrite, ::GetCurrentProcess(), &hErrWrite, 0, TRUE, DUPLICATE_SAME_ACCESS))
619 {
620 ProcExitWithLastError(hr, "failed to duplicate write handle");
621 }
622
623 // We need to create new "output read" and "input write" handles that are non inheritable. Otherwise CreateProcess will creates handles in
624 // the child process that can't be closed.
625 if (!::DuplicateHandle(::GetCurrentProcess(), hOutTemp, ::GetCurrentProcess(), &hOutRead, 0, FALSE, DUPLICATE_SAME_ACCESS))
626 {
627 ProcExitWithLastError(hr, "failed to duplicate output pipe");
628 }
629
630 if (!::DuplicateHandle(::GetCurrentProcess(), hInTemp, ::GetCurrentProcess(), &hInWrite, 0, FALSE, DUPLICATE_SAME_ACCESS))
631 {
632 ProcExitWithLastError(hr, "failed to duplicate input pipe");
633 }
634
635 // now that everything has succeeded, assign to the outputs
636 *phOutRead = hOutRead;
637 hOutRead = INVALID_HANDLE_VALUE;
638
639 *phOutWrite = hOutWrite;
640 hOutWrite = INVALID_HANDLE_VALUE;
641
642 *phErrWrite = hErrWrite;
643 hErrWrite = INVALID_HANDLE_VALUE;
644
645 *phInRead = hInRead;
646 hInRead = INVALID_HANDLE_VALUE;
647
648 *phInWrite = hInWrite;
649 hInWrite = INVALID_HANDLE_VALUE;
650
651 LExit:
652 ReleaseFileHandle(hOutRead);
653 ReleaseFileHandle(hOutWrite);
654 ReleaseFileHandle(hErrWrite);
655 ReleaseFileHandle(hInRead);
656 ReleaseFileHandle(hInWrite);
657 ReleaseFileHandle(hOutTemp);
658 ReleaseFileHandle(hInTemp);
659
660 return hr;
661 }
662
663
664 /********************************************************************
665 CloseWindowEnumCallback() - outputs trace and log info
666
667 *******************************************************************/
668 static BOOL CALLBACK CloseWindowEnumCallback(
669 __in HWND hWnd,
670 __in LPARAM lParam
671 )
672 {
673 DWORD dwPid = static_cast<DWORD>(lParam);
674 DWORD dwProcessId = 0;
675
676 ::GetWindowThreadProcessId(hWnd, &dwProcessId);
677 if (dwPid == dwProcessId)
678 {
679 ::SendMessageW(hWnd, WM_CLOSE, 0, 0);
680 }
681
682 return TRUE;
683 }