Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Unified Diff: src/installer-ca/dutil/procutil.cpp

Issue 11521026: initial custom action library, "hello, world" quality (Closed)
Patch Set: Created Sept. 3, 2013, 12:48 p.m.
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: src/installer-ca/dutil/procutil.cpp
===================================================================
new file mode 100644
--- /dev/null
+++ b/src/installer-ca/dutil/procutil.cpp
@@ -0,0 +1,499 @@
+//-------------------------------------------------------------------------------------------------
+// <copyright file="procutil.cpp" company="Outercurve Foundation">
+// Copyright (c) 2004, Outercurve Foundation.
+// This software is released under Microsoft Reciprocal License (MS-RL).
+// The license and further copyright text can be found in the file
+// LICENSE.TXT at the root directory of the distribution.
+// </copyright>
+//
+// <summary>
+// Process helper functions.
+// </summary>
+//-------------------------------------------------------------------------------------------------
+
+#include "../precomp.h"
+
+
+// private functions
+static HRESULT CreatePipes(
+ __out HANDLE *phOutRead,
+ __out HANDLE *phOutWrite,
+ __out HANDLE *phErrWrite,
+ __out HANDLE *phInRead,
+ __out HANDLE *phInWrite
+ );
+
+static BOOL CALLBACK CloseWindowEnumCallback(
+ __in HWND hWnd,
+ __in LPARAM lParam
+ );
+
+
+extern "C" HRESULT DAPI ProcElevated(
+ __in HANDLE hProcess,
+ __out BOOL* pfElevated
+ )
+{
+ HRESULT hr = S_OK;
+ HANDLE hToken = NULL;
+ TOKEN_ELEVATION tokenElevated = { };
+ DWORD cbToken = 0;
+
+ if (!::OpenProcessToken(hProcess, TOKEN_QUERY, &hToken))
+ {
+ ExitWithLastError(hr, "Failed to open process token.");
+ }
+
+ if (::GetTokenInformation(hToken, TokenElevation, &tokenElevated, sizeof(TOKEN_ELEVATION), &cbToken))
+ {
+ *pfElevated = (0 != tokenElevated.TokenIsElevated);
+ }
+ else
+ {
+ DWORD er = ::GetLastError();
+ hr = HRESULT_FROM_WIN32(er);
+
+ // If it's invalid argument, this means the OS doesn't support TokenElevation, so we're not elevated.
+ if (E_INVALIDARG == hr)
+ {
+ *pfElevated = FALSE;
+ hr = S_OK;
+ }
+ else
+ {
+ ExitOnRootFailure(hr, "Failed to get elevation token from process.");
+ }
+ }
+
+LExit:
+ ReleaseHandle(hToken);
+
+ return hr;
+}
+
+extern "C" HRESULT DAPI ProcWow64(
+ __in HANDLE hProcess,
+ __out BOOL* pfWow64
+ )
+{
+ HRESULT hr = S_OK;
+ BOOL fIsWow64 = FALSE;
+
+ typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS)(HANDLE, PBOOL);
+ LPFN_ISWOW64PROCESS pfnIsWow64Process = (LPFN_ISWOW64PROCESS)::GetProcAddress(::GetModuleHandleW(L"kernel32"), "IsWow64Process");
+
+ if (pfnIsWow64Process)
+ {
+ if (!pfnIsWow64Process(hProcess, &fIsWow64))
+ {
+ ExitWithLastError(hr, "Failed to check WOW64 process.");
+ }
+ }
+
+ *pfWow64 = fIsWow64;
+
+LExit:
+ return hr;
+}
+
+extern "C" HRESULT DAPI ProcDisableWowFileSystemRedirection(
+ __in PROC_FILESYSTEMREDIRECTION* pfsr
+ )
+{
+ AssertSz(!pfsr->fDisabled, "File system redirection was already disabled.");
+ HRESULT hr = S_OK;
+
+ typedef BOOL (WINAPI *LPFN_Wow64DisableWow64FsRedirection)(PVOID *);
+ LPFN_Wow64DisableWow64FsRedirection pfnWow64DisableWow64FsRedirection = (LPFN_Wow64DisableWow64FsRedirection)::GetProcAddress(::GetModuleHandleW(L"kernel32"), "Wow64DisableWow64FsRedirection");
+
+ if (!pfnWow64DisableWow64FsRedirection)
+ {
+ ExitFunction1(hr = E_NOTIMPL);
+ }
+
+ if (!pfnWow64DisableWow64FsRedirection(&pfsr->pvRevertState))
+ {
+ ExitWithLastError(hr, "Failed to disable file system redirection.");
+ }
+
+ pfsr->fDisabled = TRUE;
+
+LExit:
+ return hr;
+}
+
+extern "C" HRESULT DAPI ProcRevertWowFileSystemRedirection(
+ __in PROC_FILESYSTEMREDIRECTION* pfsr
+ )
+{
+ HRESULT hr = S_OK;
+
+ if (pfsr->fDisabled)
+ {
+ typedef BOOL (WINAPI *LPFN_Wow64RevertWow64FsRedirection)(PVOID);
+ LPFN_Wow64RevertWow64FsRedirection pfnWow64RevertWow64FsRedirection = (LPFN_Wow64RevertWow64FsRedirection)::GetProcAddress(::GetModuleHandleW(L"kernel32"), "Wow64RevertWow64FsRedirection");
+
+ if (!pfnWow64RevertWow64FsRedirection(pfsr->pvRevertState))
+ {
+ ExitWithLastError(hr, "Failed to revert file system redirection.");
+ }
+
+ pfsr->fDisabled = FALSE;
+ pfsr->pvRevertState = NULL;
+ }
+
+LExit:
+ return hr;
+}
+
+
+extern "C" HRESULT DAPI ProcExec(
+ __in_z LPCWSTR wzExecutablePath,
+ __in_z_opt LPCWSTR wzCommandLine,
+ __in int nCmdShow,
+ __out HANDLE *phProcess
+ )
+{
+ HRESULT hr = S_OK;
+ LPWSTR sczFullCommandLine = NULL;
+ STARTUPINFOW si = { };
+ PROCESS_INFORMATION pi = { };
+
+ hr = StrAllocFormatted(&sczFullCommandLine, L"\"%ls\" %ls", wzExecutablePath, wzCommandLine ? wzCommandLine : L"");
+ ExitOnFailure(hr, "Failed to allocate full command-line.");
+
+ si.cb = sizeof(si);
+ si.wShowWindow = static_cast<WORD>(nCmdShow);
+ if (!::CreateProcessW(wzExecutablePath, sczFullCommandLine, NULL, NULL, FALSE, 0, 0, NULL, &si, &pi))
+ {
+ ExitWithLastError1(hr, "Failed to create process: %ls", sczFullCommandLine);
+ }
+
+ *phProcess = pi.hProcess;
+ pi.hProcess = NULL;
+
+LExit:
+ ReleaseHandle(pi.hThread);
+ ReleaseHandle(pi.hProcess);
+ ReleaseStr(sczFullCommandLine);
+
+ return hr;
+}
+
+
+/********************************************************************
+ ProcExecute() - executes a command-line.
+
+*******************************************************************/
+extern "C" HRESULT DAPI ProcExecute(
+ __in_z LPWSTR wzCommand,
+ __out HANDLE *phProcess,
+ __out_opt HANDLE *phChildStdIn,
+ __out_opt HANDLE *phChildStdOutErr
+ )
+{
+ HRESULT hr = S_OK;
+
+ PROCESS_INFORMATION pi = { };
+ STARTUPINFOW si = { };
+
+ HANDLE hOutRead = INVALID_HANDLE_VALUE;
+ HANDLE hOutWrite = INVALID_HANDLE_VALUE;
+ HANDLE hErrWrite = INVALID_HANDLE_VALUE;
+ HANDLE hInRead = INVALID_HANDLE_VALUE;
+ HANDLE hInWrite = INVALID_HANDLE_VALUE;
+
+ // Create redirect pipes.
+ hr = CreatePipes(&hOutRead, &hOutWrite, &hErrWrite, &hInRead, &hInWrite);
+ ExitOnFailure(hr, "failed to create output pipes");
+
+ // Set up startup structure.
+ si.cb = sizeof(STARTUPINFOW);
+ si.dwFlags = STARTF_USESTDHANDLES;
+ si.hStdInput = hInRead;
+ si.hStdOutput = hOutWrite;
+ si.hStdError = hErrWrite;
+
+#pragma prefast(push)
+#pragma prefast(disable:25028)
+ if (::CreateProcessW(NULL,
+ wzCommand, // command line
+ NULL, // security info
+ NULL, // thread info
+ TRUE, // inherit handles
+ ::GetPriorityClass(::GetCurrentProcess()) | CREATE_NO_WINDOW, // creation flags
+ NULL, // environment
+ NULL, // cur dir
+ &si,
+ &pi))
+#pragma prefast(pop)
+ {
+ // Close child process output/input handles so child doesn't hang
+ // while waiting for input from parent process.
+ ::CloseHandle(hOutWrite);
+ hOutWrite = INVALID_HANDLE_VALUE;
+
+ ::CloseHandle(hErrWrite);
+ hErrWrite = INVALID_HANDLE_VALUE;
+
+ ::CloseHandle(hInRead);
+ hInRead = INVALID_HANDLE_VALUE;
+ }
+ else
+ {
+ ExitWithLastError(hr, "Process failed to execute.");
+ }
+
+ *phProcess = pi.hProcess;
+ pi.hProcess = 0;
+
+ if (phChildStdIn)
+ {
+ *phChildStdIn = hInWrite;
+ hInWrite = INVALID_HANDLE_VALUE;
+ }
+
+ if (phChildStdOutErr)
+ {
+ *phChildStdOutErr = hOutRead;
+ hOutRead = INVALID_HANDLE_VALUE;
+ }
+
+LExit:
+ if (pi.hThread)
+ {
+ ::CloseHandle(pi.hThread);
+ }
+
+ if (pi.hProcess)
+ {
+ ::CloseHandle(pi.hProcess);
+ }
+
+ ReleaseFileHandle(hOutRead);
+ ReleaseFileHandle(hOutWrite);
+ ReleaseFileHandle(hErrWrite);
+ ReleaseFileHandle(hInRead);
+ ReleaseFileHandle(hInWrite);
+
+ return hr;
+}
+
+
+/********************************************************************
+ ProcWaitForCompletion() - waits for process to complete and gets return code.
+
+*******************************************************************/
+extern "C" HRESULT DAPI ProcWaitForCompletion(
+ __in HANDLE hProcess,
+ __in DWORD dwTimeout,
+ __out DWORD *pReturnCode
+ )
+{
+ HRESULT hr = S_OK;
+ DWORD er = ERROR_SUCCESS;
+
+ // Wait for everything to finish
+ er = ::WaitForSingleObject(hProcess, dwTimeout);
+ if (WAIT_FAILED == er)
+ {
+ ExitWithLastError(hr, "Failed to wait for process to complete.");
+ }
+ else if (WAIT_TIMEOUT == er)
+ {
+ ExitFunction1(hr = HRESULT_FROM_WIN32(er));
+ }
+
+ if (!::GetExitCodeProcess(hProcess, &er))
+ {
+ ExitWithLastError(hr, "Failed to get process return code.");
+ }
+
+ *pReturnCode = er;
+
+LExit:
+ return hr;
+}
+
+/********************************************************************
+ ProcWaitForIds() - waits for multiple processes to complete.
+
+*******************************************************************/
+extern "C" HRESULT DAPI ProcWaitForIds(
+ __in_ecount(cProcessIds) const DWORD rgdwProcessIds[],
+ __in DWORD cProcessIds,
+ __in DWORD dwMilliseconds
+ )
+{
+ HRESULT hr = S_OK;
+ DWORD er = ERROR_SUCCESS;
+ HANDLE hProcess = NULL;
+ HANDLE * rghProcesses = NULL;
+ DWORD cProcesses = 0;
+
+ rghProcesses = static_cast<HANDLE*>(MemAlloc(sizeof(DWORD) * cProcessIds, TRUE));
+ ExitOnNull(rgdwProcessIds, hr, E_OUTOFMEMORY, "Failed to allocate array for process ID Handles.");
+
+ for (DWORD i = 0; i < cProcessIds; ++i)
+ {
+ hProcess = ::OpenProcess(SYNCHRONIZE, FALSE, rgdwProcessIds[i]);
+ if (hProcess != NULL)
+ {
+ rghProcesses[cProcesses++] = hProcess;
+ }
+ }
+
+ er = ::WaitForMultipleObjects(cProcesses, rghProcesses, TRUE, dwMilliseconds);
+ if (WAIT_FAILED == er)
+ {
+ ExitWithLastError(hr, "Failed to wait for process to complete.");
+ }
+ else if (WAIT_TIMEOUT == er)
+ {
+ ExitOnWin32Error(er, hr, "Timed out while waiting for process to complete.");
+ }
+
+LExit:
+ if (rghProcesses)
+ {
+ for (DWORD i = 0; i < cProcesses; ++i)
+ {
+ if (NULL != rghProcesses[i])
+ {
+ ::CloseHandle(rghProcesses[i]);
+ }
+ }
+
+ MemFree(rghProcesses);
+ }
+
+ return hr;
+}
+
+/********************************************************************
+ ProcCloseIds() - sends WM_CLOSE messages to all process ids.
+
+*******************************************************************/
+extern "C" HRESULT DAPI ProcCloseIds(
+ __in_ecount(cProcessIds) const DWORD* pdwProcessIds,
+ __in DWORD cProcessIds
+ )
+{
+ HRESULT hr = S_OK;
+
+ for (DWORD i = 0; i < cProcessIds; ++i)
+ {
+ if (!::EnumWindows(&CloseWindowEnumCallback, pdwProcessIds[i]))
+ {
+ ExitWithLastError(hr, "Failed to enumerate windows.");
+ }
+ }
+
+LExit:
+ return hr;
+}
+
+
+static HRESULT CreatePipes(
+ __out HANDLE *phOutRead,
+ __out HANDLE *phOutWrite,
+ __out HANDLE *phErrWrite,
+ __out HANDLE *phInRead,
+ __out HANDLE *phInWrite
+ )
+{
+ HRESULT hr = S_OK;
+ SECURITY_ATTRIBUTES sa;
+ HANDLE hOutTemp = INVALID_HANDLE_VALUE;
+ HANDLE hInTemp = INVALID_HANDLE_VALUE;
+
+ HANDLE hOutRead = INVALID_HANDLE_VALUE;
+ HANDLE hOutWrite = INVALID_HANDLE_VALUE;
+ HANDLE hErrWrite = INVALID_HANDLE_VALUE;
+ HANDLE hInRead = INVALID_HANDLE_VALUE;
+ HANDLE hInWrite = INVALID_HANDLE_VALUE;
+
+ // Fill out security structure so we can inherit handles
+ ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));
+ sa.nLength = sizeof(SECURITY_ATTRIBUTES);
+ sa.bInheritHandle = TRUE;
+ sa.lpSecurityDescriptor = NULL;
+
+ // Create pipes
+ if (!::CreatePipe(&hOutTemp, &hOutWrite, &sa, 0))
+ {
+ ExitWithLastError(hr, "failed to create output pipe");
+ }
+
+ if (!::CreatePipe(&hInRead, &hInTemp, &sa, 0))
+ {
+ ExitWithLastError(hr, "failed to create input pipe");
+ }
+
+ // Duplicate output pipe so standard error and standard output write to the same pipe.
+ if (!::DuplicateHandle(::GetCurrentProcess(), hOutWrite, ::GetCurrentProcess(), &hErrWrite, 0, TRUE, DUPLICATE_SAME_ACCESS))
+ {
+ ExitWithLastError(hr, "failed to duplicate write handle");
+ }
+
+ // We need to create new "output read" and "input write" handles that are non inheritable. Otherwise CreateProcess will creates handles in
+ // the child process that can't be closed.
+ if (!::DuplicateHandle(::GetCurrentProcess(), hOutTemp, ::GetCurrentProcess(), &hOutRead, 0, FALSE, DUPLICATE_SAME_ACCESS))
+ {
+ ExitWithLastError(hr, "failed to duplicate output pipe");
+ }
+
+ if (!::DuplicateHandle(::GetCurrentProcess(), hInTemp, ::GetCurrentProcess(), &hInWrite, 0, FALSE, DUPLICATE_SAME_ACCESS))
+ {
+ ExitWithLastError(hr, "failed to duplicate input pipe");
+ }
+
+ // now that everything has succeeded, assign to the outputs
+ *phOutRead = hOutRead;
+ hOutRead = INVALID_HANDLE_VALUE;
+
+ *phOutWrite = hOutWrite;
+ hOutWrite = INVALID_HANDLE_VALUE;
+
+ *phErrWrite = hErrWrite;
+ hErrWrite = INVALID_HANDLE_VALUE;
+
+ *phInRead = hInRead;
+ hInRead = INVALID_HANDLE_VALUE;
+
+ *phInWrite = hInWrite;
+ hInWrite = INVALID_HANDLE_VALUE;
+
+LExit:
+ ReleaseFileHandle(hOutRead);
+ ReleaseFileHandle(hOutWrite);
+ ReleaseFileHandle(hErrWrite);
+ ReleaseFileHandle(hInRead);
+ ReleaseFileHandle(hInWrite);
+ ReleaseFileHandle(hOutTemp);
+ ReleaseFileHandle(hInTemp);
+
+ return hr;
+}
+
+
+/********************************************************************
+ CloseWindowEnumCallback() - outputs trace and log info
+
+*******************************************************************/
+static BOOL CALLBACK CloseWindowEnumCallback(
+ __in HWND hWnd,
+ __in LPARAM lParam
+ )
+{
+ DWORD dwPid = static_cast<DWORD>(lParam);
+ DWORD dwProcessId = 0;
+
+ ::GetWindowThreadProcessId(hWnd, &dwProcessId);
+ if (dwPid == dwProcessId)
+ {
+ ::SendMessageW(hWnd, WM_CLOSE, 0, 0);
+ }
+
+ return TRUE;
+}

Powered by Google App Engine
This is Rietveld