Skip to content

Instantly share code, notes, and snippets.

@Qix-
Last active December 31, 2015 12:29
Show Gist options
  • Save Qix-/7986308 to your computer and use it in GitHub Desktop.
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!
/*
* 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