From: Hector Santos on
James wrote:

> "Emil Dotchevski" <emildotchevski(a)gmail.com> wrote in message
> news:95e9d35d-60e0-414d-81bb-cef3c12d485b(a)k2g2000pro.googlegroups.com...
>> I want to terminate a process with an exit code, and I want that exit
>> code to be returned by the process being killed. Note that I can't
>> synchronize with the process and I can't "wait a little" before I kill
>> it.
>>
>> On my system (XP SP3) the test below fails nearly 100% of the time.
>> When it fails, the process being killed returns zero (instead of 42.)
>>
>> Any ideas?
> [...]
>
> Create a remote thread in the process and wait for it to quit. The act
> of the remote thread starting and quitting should indicate that the
> process has been initialized?


Very interesting idea to explore. Based on the MSDN, it does seem to
provide a mechanism to provide a wait for the thread to go active or
to stop. For example

DWORD WINAPI rThreadProcInit(LPVOID p)
{
// remote thread started and finishing.
return 0;
}

and then using this finish to wait on before terminating the child
process.

I just tried this, and it worked nicely.

Howevever, it assumes that the child process was not in a EXIT state
or exited before termination.

--
HLS
From: m on
Here is some better code:

DWORD WINAPI ThreadProc(LPVOID p)
{
ExitProcess((DWORD)p);
}

though it still may fail if the process terminated before it gets control,
this is better then the other suggestions. As I mentioned previously, the
only safe way to to this is to hijack the exe being launched - and it is far
simpler thing to do then to play with remote threads and code injection!
Maybe I am just dense, but I fail to see why one would _want_ to use a more
complicated method that can fail, when a simpler one that can't is
available.

"Hector Santos" <sant9442(a)nospam.gmail.com> wrote in message
news:OcXMgZPrKHA.5896(a)TK2MSFTNGP04.phx.gbl...
> James wrote:
>
>> "Emil Dotchevski" <emildotchevski(a)gmail.com> wrote in message
>> news:95e9d35d-60e0-414d-81bb-cef3c12d485b(a)k2g2000pro.googlegroups.com...
>>> I want to terminate a process with an exit code, and I want that exit
>>> code to be returned by the process being killed. Note that I can't
>>> synchronize with the process and I can't "wait a little" before I kill
>>> it.
>>>
>>> On my system (XP SP3) the test below fails nearly 100% of the time.
>>> When it fails, the process being killed returns zero (instead of 42.)
>>>
>>> Any ideas?
>> [...]
>>
>> Create a remote thread in the process and wait for it to quit. The act of
>> the remote thread starting and quitting should indicate that the process
>> has been initialized?
>
>
> Very interesting idea to explore. Based on the MSDN, it does seem to
> provide a mechanism to provide a wait for the thread to go active or to
> stop. For example
>
> DWORD WINAPI rThreadProcInit(LPVOID p)
> {
> // remote thread started and finishing.
> return 0;
> }
>
> and then using this finish to wait on before terminating the child
> process.
>
> I just tried this, and it worked nicely.
>
> Howevever, it assumes that the child process was not in a EXIT state or
> exited before termination.
>
> --
> HLS

From: Hector Santos on

After trying various ideas (including the CreateRemoteThread() sync
idea as shown below) across various machines and OSes:

NT 4.0 Single CPU
NT 4.0 Dual CPU (not core)
WINDOWS 2000 Single CPU
WINDOWS 2000 Dual Core
WINDOWS 2003 Dual Core
WINDOWS VISTA Dual Core
WINDOWS 7.0 Dual Core

I've come to the "observed" conclusion TerminateProcess() behaves MOST
differently on XP as the OP suspected.

// File: v:\wc5beta\testemil1.cpp

#include <stdio.h>
#include <windows.h>
#include <conio.h>
#include <assert.h>

void check_call( bool result, char const * call, char const * file,
int line );
#define CHECK_CALL(call) check_call(call,#call,__FILE__,__LINE__);

DWORD WINAPI rThreadProc(LPVOID p) { return 0; }

int main( int argc, char const * argv[] )
{
if( argc>1 ) {
assert( !strcmp(argv[1],"inf") );
return 21;
//for(;;) {}
}
HANDLE rh = NULL;
DWORD rtid = 0;
int errors=0, zeroes=0;
int n42 =0;
char cmd_line[32768];
strcat(strcpy(cmd_line,argv[0])," inf");
for( int i=0; i!=100; ++i )
{
if (kbhit() && getch() == 27) break;
STARTUPINFO sinfo = {0};
sinfo.cb = sizeof(STARTUPINFO);
PROCESS_INFORMATION pe;
DWORD cf = CREATE_SUSPENDED;

CHECK_CALL((CreateProcess(0,cmd_line,0,0,TRUE,cf,0,0,&sinfo,&pe)!=0));
if (cf == CREATE_SUSPENDED) {
Sleep(0);
CHECK_CALL((ResumeThread(pe.hThread)!=0));
}
CHECK_CALL((CloseHandle(pe.hThread)!=0));

rh = CreateRemoteThread(pe.hProcess, NULL, 0, rThreadProc,
NULL, 0, &rtid);
if (rh == INVALID_HANDLE_VALUE) {
printf("CreateRemoteThread Error %d\n",GetLastError());
CHECK_CALL((TerminateProcess(pe.hProcess,42)!=0));
exit(4);
}
while (WaitForSingleObject(rh,1000)!=WAIT_OBJECT_0)
{
if (kbhit() && getch() == 27) break;
}
CHECK_CALL((TerminateProcess(pe.hProcess,42)!=0));

CHECK_CALL((WaitForSingleObject(pe.hProcess,INFINITE)==WAIT_OBJECT_0));
DWORD ec=0xFFFFFFFF;
CHECK_CALL((GetExitCodeProcess(pe.hProcess,&ec)!=0));
CHECK_CALL((CloseHandle(pe.hProcess)!=0));
errors += (ec!=42);
n42 += (ec==42);
zeroes += (ec==0);
if (ec != 42) printf("-- i: %d error: %d\n",i,ec);
}
printf("n42: %d | errors: %d | zeros: %d\n", n42, errors, zeroes);
return 0;
}
.... rest of code....

With the exception of the XP run and VISTA/W7, TerminateProcess()
failed each time with access 5 at the first spawn. On XP, it
terminates with 42 the expected return exit code 21.

On VISTA/W7, I get an error 1812 on the CreateProcess call. Probably
related to admin rights I have to explore.

Now, remove the return 21, and just use the loop:

if( argc>1 ) {
assert( !strcmp(argv[1],"inf") );
//return 21;
for(;;) {}
}

and they (Except under Vista/W7) all behave the same with occasional
random exit code 0 on the NT 4.0 Dual CPU machine.

--


m wrote:

> Here is some better code:
>
> DWORD WINAPI ThreadProc(LPVOID p)
> {
> ExitProcess((DWORD)p);
> }
>
> though it still may fail if the process terminated before it gets
> control, this is better then the other suggestions. As I mentioned
> previously, the only safe way to to this is to hijack the exe being
> launched - and it is far simpler thing to do then to play with remote
> threads and code injection! Maybe I am just dense, but I fail to see why
> one would _want_ to use a more complicated method that can fail, when a
> simpler one that can't is available.