You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
161 lines
3.6 KiB
161 lines
3.6 KiB
#ifndef UNICODE |
|
#define UNICODE |
|
#endif |
|
|
|
#include <windows.h> |
|
#include <stdio.h> |
|
#include <stdlib.h> |
|
|
|
// Skip initial argument in a command line. Adapted from my winserv |
|
// http://www.sw4me.com/wiki/Winserv |
|
static LPTSTR skip_arg(LPTSTR p) |
|
{ |
|
int inquote, slashes; |
|
|
|
// skip spaces |
|
while (isspace(*p)) { p++; } |
|
if (*p == TEXT('\0')) { return p; } |
|
inquote = 0; slashes = 0; |
|
// we found where the argument begins |
|
for (;;) { |
|
while (*p == TEXT('\\')) { |
|
slashes++; |
|
p++; |
|
} |
|
if (*p == TEXT('"')) { |
|
if ((slashes & 1) == 0) { |
|
if ((inquote) && (p[1] == TEXT('"'))) { |
|
p++; |
|
} else { |
|
inquote = !inquote; |
|
} |
|
} |
|
} |
|
slashes=0; |
|
if ((*p == TEXT('\0')) || (!inquote && isspace(*p))) { |
|
while (isspace(*p)) |
|
p++; |
|
return p; |
|
} |
|
p++; |
|
} |
|
} |
|
|
|
// Terminate unsuccessfully with an error message |
|
static void Fail(const char *desc) { |
|
fprintf(stderr, "Error %u in %s\n", GetLastError(), desc); |
|
exit(1); |
|
} |
|
|
|
// Raymond Chen's CreateProcessInJob |
|
// see https://devblogs.microsoft.com/oldnewthing/20131209-00/?p=2433 |
|
BOOL CreateProcessInJob( |
|
HANDLE hJob, |
|
LPCTSTR lpApplicationName, |
|
LPTSTR lpCommandLine, |
|
LPSECURITY_ATTRIBUTES lpProcessAttributes, |
|
LPSECURITY_ATTRIBUTES lpThreadAttributes, |
|
BOOL bInheritHandles, |
|
DWORD dwCreationFlags, |
|
LPVOID lpEnvironment, |
|
LPCTSTR lpCurrentDirectory, |
|
LPSTARTUPINFO lpStartupInfo, |
|
LPPROCESS_INFORMATION ppi) |
|
{ |
|
BOOL fRc = CreateProcess( |
|
lpApplicationName, |
|
lpCommandLine, |
|
lpProcessAttributes, |
|
lpThreadAttributes, |
|
bInheritHandles, |
|
dwCreationFlags | CREATE_SUSPENDED, |
|
lpEnvironment, |
|
lpCurrentDirectory, |
|
lpStartupInfo, |
|
ppi); |
|
if (fRc) { |
|
fRc = AssignProcessToJobObject(hJob, ppi->hProcess); |
|
if (fRc && !(dwCreationFlags & CREATE_SUSPENDED)) { |
|
fRc = ResumeThread(ppi->hThread) != (DWORD)-1; |
|
} |
|
if (!fRc) { |
|
TerminateProcess(ppi->hProcess, 0); |
|
CloseHandle(ppi->hProcess); |
|
CloseHandle(ppi->hThread); |
|
ppi->hProcess = ppi->hThread = NULL; |
|
} |
|
} |
|
return fRc; |
|
} |
|
|
|
// defined in pijhelp.cc, so I can use C++ raw literals |
|
extern const char *Help; |
|
|
|
|
|
int main(int argc, char*argv[]) |
|
{ |
|
if (argc <= 1) { |
|
printf("%s",Help); |
|
exit(0); |
|
} |
|
LPTSTR cmdline = GetCommandLineW(); |
|
LPTSTR restCmdLine = skip_arg(cmdline); |
|
HANDLE hJob = CreateJobObject(NULL,NULL); |
|
if (hJob == NULL) { |
|
Fail("CreateJobObject"); |
|
} |
|
HANDLE hPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1); |
|
if (hPort == NULL) { |
|
Fail("CreateIoCompletionPort"); |
|
} |
|
|
|
// see https://devblogs.microsoft.com/oldnewthing/20130405-00/?p=4743 |
|
JOBOBJECT_ASSOCIATE_COMPLETION_PORT jacp; |
|
jacp.CompletionKey = hJob; |
|
jacp.CompletionPort = hPort; |
|
if (!SetInformationJobObject(hJob, |
|
JobObjectAssociateCompletionPortInformation, |
|
&jacp, sizeof(jacp))) { |
|
Fail("SetInformationJobObject(JobObjectAssociateCompletionPortInformation)"); |
|
} |
|
|
|
STARTUPINFO si = { sizeof si }; |
|
PROCESS_INFORMATION pi; |
|
if (!CreateProcessInJob(hJob, |
|
NULL, |
|
restCmdLine, |
|
NULL, |
|
NULL, |
|
FALSE, |
|
0, |
|
NULL, |
|
NULL, |
|
&si, |
|
&pi)) { |
|
Fail("CreateProcess"); |
|
} |
|
CloseHandle(pi.hProcess); |
|
CloseHandle(pi.hThread); |
|
|
|
|
|
DWORD completionCode; |
|
ULONG_PTR completionKey; |
|
LPOVERLAPPED overlapped; |
|
|
|
for (;;) { |
|
BOOL rc = GetQueuedCompletionStatus(hPort, |
|
&completionCode, |
|
&completionKey, |
|
&overlapped, |
|
INFINITE); |
|
if (!rc) { |
|
Fail("GetQueuedCompletionStatus"); |
|
} |
|
if ((HANDLE)completionKey == hJob && |
|
completionCode == JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO) { |
|
break; |
|
} |
|
} |
|
CloseHandle(hJob); |
|
return 0; |
|
}
|
|
|