Last active
December 31, 2015 12:29
-
-
Save Qix-/7986308 to your computer and use it in GitHub Desktop.
No-Inherit is a little windows utility I whipped up for use with Cygwin to fix a few issues while executing windows-based programs to run a child program natively, without inheriting the parent process' environment. Use it how you want!
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Windows utility that creates a child process without inheriting any | |
* sort of environment. Used in the setup scripts to fake a vanilla | |
* windows environment for CMake. | |
* | |
* Developed by Qix | |
*/ | |
#pragma comment(lib, "Userenv.lib") | |
#pragma comment(lib, "Advapi32.lib") | |
#include <Windows.h> | |
#include <cstdio> | |
#include <userenv.h> | |
#include <sstream> | |
#define PRINTMSG(fmt, ...) {printf("! - <%d> " fmt "\n", GetLastError(), __VA_ARGS__);\ | |
LPSTR buf = 0;\ | |
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, GetLastError(), 0, (LPSTR)&buf, 0, 0);\ | |
printf("\t%s\n", buf);\ | |
LocalFree(buf);} | |
#define PRINTMSGR(fmt, ...) {PRINTMSG(fmt, __VA_ARGS__); return 1;} | |
int GetExitCodeProcessSmart(HANDLE, DWORD*); | |
int main(int argc, char** argv) | |
{ | |
// Create a security token | |
HANDLE secToken; | |
if(!OpenProcessToken( GetCurrentProcess(), | |
TOKEN_QUERY | TOKEN_IMPERSONATE, | |
&secToken)) | |
PRINTMSGR("Could not lease process token!"); | |
// Create environment block | |
void* envBlock = 0; | |
if(!CreateEnvironmentBlock(&envBlock, secToken, FALSE)) | |
PRINTMSGR("Could not create non-inherited environment block!"); | |
// Close security token | |
if(!CloseHandle(secToken)) | |
PRINTMSG("WARNING: Could not close security handle!"); | |
// Do we have args? | |
std::stringstream ss; | |
if(argc > 1) | |
{ | |
// Collapse | |
for(int i = 1; i < argc; i++) | |
ss << (i == 1 ? "" : " ") << argv[i]; | |
} else { | |
printf("! - No command specified!\n"); | |
return 2; | |
} | |
// Get startup info | |
STARTUPINFOA info; | |
ZeroMemory(&info, sizeof(info)); | |
info.cb = sizeof(info); | |
// Create process | |
PROCESS_INFORMATION proc; | |
if(!CreateProcessA( NULL, | |
(LPSTR)ss.str().c_str(), | |
NULL, | |
NULL, | |
FALSE, | |
CREATE_DEFAULT_ERROR_MODE | | |
CREATE_NEW_PROCESS_GROUP | | |
CREATE_UNICODE_ENVIRONMENT, | |
envBlock, | |
NULL, | |
&info, | |
&proc)) | |
PRINTMSGR("Could not create non-inherited child process!!"); | |
// Wait for return | |
int finalResult = -1; | |
DWORD returnCode = 0; | |
while((finalResult = GetExitCodeProcessSmart(proc.hProcess, &returnCode)) == 0) | |
Sleep(50); | |
// Was was the final result? | |
if(finalResult == -1) | |
PRINTMSGR("Failed when waiting for process to exit"); | |
// Return | |
return returnCode; | |
} | |
// Below function credits to bionicbeagle over at MSDN | |
int GetExitCodeProcessSmart(HANDLE hProcess, DWORD* pdwOutExitCode) | |
{ | |
//Get exit code for the process | |
//'hProcess' = process handle | |
//'pdwOutExitCode' = if not NULL, receives the exit code (valid only if returned 1) | |
//RETURN: | |
//= 1 if success, exit code is returned in 'pdwOutExitCode' | |
//= 0 if process has not exited yet | |
//= -1 if error, check GetLastError() for more info | |
int nRes = -1; | |
DWORD dwExitCode = 0; | |
if(::GetExitCodeProcess(hProcess, &dwExitCode)) | |
{ | |
if(dwExitCode != STILL_ACTIVE) | |
{ | |
nRes = 1; | |
} | |
else | |
{ | |
//Check if process is still alive | |
DWORD dwR = ::WaitForSingleObject(hProcess, 0); | |
if(dwR == WAIT_OBJECT_0) | |
{ | |
nRes = 1; | |
} | |
else if(dwR == WAIT_TIMEOUT) | |
{ | |
nRes = 0; | |
} | |
else | |
{ | |
//Error | |
nRes = -1; | |
} | |
} | |
} | |
if(pdwOutExitCode) | |
*pdwOutExitCode = dwExitCode; | |
return nRes; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment