tags:

views:

234

answers:

3

After I get a handle returned by CreateProcess, I call TerminateProcess, passing 42 for the process exit code. Then, I use WaitForSingleObject for the process to terminate, and finally I call GetExitCodeProcess.

None of the function calls report errors. The child process is an infinite loop and does not terminate on its own.

The problem is that sometimes GetExitCodeProcess returns 42 for the exit code (as it should) and sometimes it returns 0. Any idea why?

#include <string>
#include <sstream>
#include <iostream>
#include <assert.h>
#include <windows.h>

void check_call( bool result, char const * call );
#define CHECK_CALL(call) check_call(call,#call);

int
main( int argc, char const * argv[] )
    {
    if( argc>1 )
        {
        assert( !strcmp(argv[1],"inf") );
        for(;;)
            {
            }
        }
    int err=0;
    for( int i=0; i!=200; ++i )
        {
        STARTUPINFO sinfo;
        ZeroMemory(&sinfo,sizeof(STARTUPINFO));
        sinfo.cb=sizeof(STARTUPINFO);
        PROCESS_INFORMATION pe;
        char cmd_line[32768];
        strcat(strcpy(cmd_line,argv[0])," inf");
        CHECK_CALL((CreateProcess(0,cmd_line,0,0,TRUE,0,0,0,&sinfo,&pe)!=0));
        CHECK_CALL((CloseHandle(pe.hThread)!=0));
        CHECK_CALL((TerminateProcess(pe.hProcess,42)!=0));
        CHECK_CALL((WaitForSingleObject(pe.hProcess,INFINITE)==WAIT_OBJECT_0));
        DWORD ec=0;
        CHECK_CALL((GetExitCodeProcess(pe.hProcess,&ec)!=0));
        CHECK_CALL((CloseHandle(pe.hProcess)!=0));
        err += (ec!=42);
        }
    std::cout << err;
    return 0;
    }

std::string
get_last_error_str( DWORD err )
    {
    std::ostringstream s;
    s << err;
    LPVOID lpMsgBuf=0;
    if( FormatMessageA(
            FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
            0,
            err,
            MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
            (LPSTR)&lpMsgBuf,
            0,
            0) )
        {
        assert(lpMsgBuf!=0);
        std::string msg;
        try
            {
            std::string((LPCSTR)lpMsgBuf).swap(msg);
            }
        catch(
        ... )
            {
            }
        LocalFree(lpMsgBuf);
        if( !msg.empty() && msg[msg.size()-1]=='\n' )
            msg.resize(msg.size()-1);
        if( !msg.empty() && msg[msg.size()-1]=='\r' )
            msg.resize(msg.size()-1);
        s << ", \"" << msg << '"';
        }
    return s.str();
    }

void
check_call( bool result, char const * call )
    {
    assert(call && *call);
    if( !result )
        {
        std::cerr << call << " failed.\nGetLastError:" << get_last_error_str(GetLastError()) << std::endl;
        exit(2);
        }
    }
A: 

From GetExitCodeProcess docs:

If the function fails, the return value is zero. To get extended error information, call GetLastError.

From: http://msdn.microsoft.com/en-us/library/ms683189(VS.85).aspx

I'd recommend calling GetLastError() to see what broke. You might want to put a sleep(1) in your loop too :P

Seth
I mentioned already that none of the functions report errors. I don't want to Sleep(), and it won't help because, WaitForSingleObject is triggered after the exit code passed to TerminateProcess is stored, as explained in http://msdn.microsoft.com/en-us/library/ms686722%28VS.85%29.aspx.
Emil
A: 

I thought that nobugz's comment had this nailed...

But here's another wild guess - maybe you're calling TerminateProcess() too soon instead of too late, and Windows doesn't quite serialize setting process error code specified by TerminateProcess() with whatever it might be trying to do at process initialization? I think this is unlikely, but it might be worth putting in the the Sleep(1) call that Seth suggested (or even a Sleep(0)) call to see if the behavior changes.

Also, you might want to consider posting some code that people can experiment with.

Michael Burr
A: 

Please read this and this.

Basically, the TerminateProcess function is an ugly mess that should be avoided. Use it at your own peril.

If at all possible use should use another mechanism to shutdown your process.

Jason