Thread: testing for process

  1. #1
    Registered User whackaxe's Avatar
    Join Date
    Mar 2004
    Posts
    332

    testing for process

    i seem to be having a problem with a function written for testing is a process is open

    my process opener is this
    Code:
    bool C_terragen::launchTerragen()
    {
         string TMP_fullPath = configFile.SZ_config_tgpath;
         TMP_fullPath += "terragen.exe";
    
         if(CreateProcess(TMP_fullPath.c_str(),NULL,NULL,NULL,0,NORMAL_PRIORITY_CLASS,NULL,NULL,&si,&pi))
         {
         ttStartTime = time(NULL);
         cout<<"terragen started"<<endl;
         }
         else
         {
         cout<<"ERROR: unable to lauch terragen";
         }
    }
    that is working (it prints out terragen started, and th app does start)

    my process killer is this

    Code:
    bool C_terragen::killTerragen()
    {
         if(!TerminateProcess(pi.hProcess, 0))
         {
              return(0);
         }
         else
         {
              if(isRunning())
              {
                    return(0);
              }
              else
              {
                    return(1);
              }
         }
    }
    that WAS working untill i added the isRunning function to double check. which leads me to the function that is causing the problem...

    Code:
    bool C_terragen::isRunning()
    {
         if (WaitForSingleObject(pi.hProcess, 1000) == WAIT_TIMEOUT)
         {
              CloseHandle(pi.hThread);
              CloseHandle(pi.hProcess);
              return(0);
         }
         else
         {
              return(1);
         }
    }
    this function always returns false. at first i thought it might be because it was called faster than the process starting up, but even pausing my program and resuming it when i could see the app fully loaded still returned false

    pi is (suprise suprise) a PROCESS_INFORMATION structure

    BTW. the application that is opened is susceptioble to quiting automaticly

    if you have read down to here, then a massive thank you already, if you can give me an answer, that would be just grand

  2. #2
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    TerminateProcess() returns non-zero when successful. So after killing the process you call isRunning(). Since the process has exited, the state of pi.hProcess is signalled so WaitForSingleObject() will return WAIT_OBJECT_O immediately.

    Here is a simple app that demonstrates the path of execution (notice the error checking and use of GetLastError()):
    Code:
    #include <windows.h>
    #include <iostream>
    using namespace std;
    
    int main()
    {
        PROCESS_INFORMATION pi = {0}; // always zero out structs
        STARTUPINFO si = {0};
    
        si.cb = sizeof(STARTUPINFO);
        si.dwFlags = STARTF_USESHOWWINDOW;
        si.wShowWindow = SW_MAXIMIZE;
    
        BOOL ret = CreateProcess(NULL, "Notepad.exe", NULL, NULL, FALSE, 
                                 0, NULL, NULL, &si, &pi);
        if (!ret)
        {
            cerr << "CreateProcess() failed, ec = " << GetLastError() << endl;
            return 1;
        }//if
        cout << "Process created." << endl;
    
        ret = TerminateProcess(pi.hProcess, 0);
        if (!ret)
        {
            cerr << "TerminateProcess() failed, ec = " << GetLastError() << endl;
            CloseHandle(pi.hThread);
            CloseHandle(pi.hProcess);
            return 2;
        }//if
        cout << "Process terminated" << endl;
    
        DWORD status = WaitForSingleObject(pi.hProcess, 1000);
        cout << "WaitForSingleObject() returned ";
        switch (status)
        {
            case WAIT_TIMEOUT:  
                cout << "WAIT_TIMEOUT" << endl; 
                break;
            case WAIT_OBJECT_0: 
                cout << "WAIT_OBJECT_0" << endl; 
                break;
            case WAIT_FAILED:   
                cout << "WAIT_FAILED, ec = " << GetLastError() << endl; 
                break;
            default:            
                cout << status << endl; 
                break;
        }//switch
        
        CloseHandle(pi.hThread);
        CloseHandle(pi.hProcess);
    
        return 0;
    }//main
    Only call TerminateProcess() as a last resort. You should atleast try sending the application WM_CLOSE first. Or if you are the author of the application, setup a mechinism for telling the app to shutdown.

    Your "isRunning" method name is very misleading because that's not what it is doing. If you simply want to test if your application is still running, use this:
    Code:
    bool stillRunning = WaitForSingleObject(pi.hProcess, 0) == WAIT_TIMEOUT;
    gg
    Last edited by Codeplug; 04-04-2004 at 08:54 AM.

  3. #3
    Registered User whackaxe's Avatar
    Join Date
    Mar 2004
    Posts
    332
    thank you. i still have a few questions though.
    1) what exactly does WAIT_OBJECT_O mean? what does it mean to be "signalled"?
    2) how do i send WM_CLOSE to the application(not mine btw)?

    EDIT:
    Your "isRunning" method name is very misleading because that's not what it is doing. If you simply want to test if your application is still running, use this:
    Code:

    bool stillRunning = WaitForSingleObject(pi.hProcess, 0) == WAIT_TIMEOUT;
    isnt that what my function is doing already?
    Last edited by whackaxe; 04-04-2004 at 09:08 AM.

  4. #4
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    >> what does it mean to be "signalled"?
    Certain kernel objects can be signalled or non-signalled. User applications can test if these objects are signalled by using one of the wait functions.

    >> what exactly does WAIT_OBJECT_O mean?
    That is one of the possible return values from WaitForSingleObjec(). As you can read, that means "The time-out interval elapsed, and the object's state is nonsignaled.".

    In the case of a process object, once the process terminates, the process object becomes signalled.

    >> isnt that what my function is doing already?
    You're waiting up to a second, then closing the handles if it's still running (which won't do anything but close the handles - process is not affected).

    >>how do i send WM_CLOSE to the application...?
    Since you have a handle to the application's main thread, you can use PostThreadMessage() to send WM_CLOSE.

    gg

  5. #5
    Registered User whackaxe's Avatar
    Join Date
    Mar 2004
    Posts
    332
    ah right, understnad now.

    i'm having atrouble getting PostThreadMessage() though i have this to close the app
    Code:
         DWORD thid = pi.dwThreadId;
         if (PostThreadMessage(thid,WM_CLOSE,WM_CLOSE,WM_CLOSE))
         {
              CloseHandle(pi.hThread);
              CloseHandle(pi.hProcess);
              return(1);
         }
         else
         {
         return(0);
         }

  6. #6
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    Just because PostThreadMessage() is successfull, doesn't mean that the message was processed.
    Anyways, as it turns out, PostThreadMessage() isn't enough to get the job done.

    Here is another example application that demostrates the points in this article (which uses VB but uses the Win32 API all the same).
    Code:
    #include <windows.h>
    #include <iostream>
    using namespace std;
    
    
    BOOL CALLBACK EnumThreadWndProc(HWND hwnd, LPARAM lParam)
    {
        BOOL ret = PostMessage(hwnd, WM_CLOSE, 0, 0);
        if (!ret)
        {
            cerr << "PostMessage(WM_CLOSE) failed, ec = " 
                 << GetLastError() << endl;
        }//if
    
        return TRUE;
    }//EnumThreadWndProc
    
    
    int main()
    {
        PROCESS_INFORMATION pi = {0}; // always zero out structs
        STARTUPINFO si = {0};
    
        si.cb = sizeof(STARTUPINFO);
        si.dwFlags = STARTF_USESHOWWINDOW;
        si.wShowWindow = SW_MAXIMIZE;
    
        BOOL ret = CreateProcess(NULL, "Notepad.exe", NULL, NULL, FALSE, 
                                 0, NULL, NULL, &si, &pi);
        if (!ret)
        {
            cerr << "CreateProcess() failed, ec = " << GetLastError() << endl;
            return 1;
        }//if
        cout << "Process created." << endl;
    
        // give the process a chance to startup
        Sleep(1000);
    
        // send all the top level windows of the process thread WM_CLOSE
        ret = EnumThreadWindows(pi.dwThreadId, EnumThreadWndProc, 0);
        if (!ret)
            cerr << "EnumThreadWindows() failed, ec = " << GetLastError() << endl;
    
        // give the process up to 5 seconds to process the WM_CLOSE, if we failed
        // to post any messages, then don't wait at all
        DWORD timeout = 5000;
        if (!ret)
            timeout = 0; // don't wait at all
    
        // see if the process is still running    
        bool isRunning = WaitForSingleObject(pi.hProcess, timeout) == WAIT_TIMEOUT;
        if (isRunning)
        {
            cout << "Process still running, using TerminateProcess()..." << endl;
            ret = TerminateProcess(pi.hProcess, 0);
            if (!ret)
                cerr << "TerminateProcess() failed, ec = " << GetLastError() << endl;
            else
                cout << "Process terminated via TerminateProcess()" << endl;
        }//if
        else
        {
            cout << "Process received WM_CLOSE successfully" << endl;
        }//else
        
        CloseHandle(pi.hThread);
        CloseHandle(pi.hProcess);
    
        return 0;
    }//main
    gg

  7. #7
    Yes, my avatar is stolen anonytmouse's Avatar
    Join Date
    Dec 2002
    Posts
    2,544
    Beaten by Codeplug... Anyway:

    Code:
    BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
    {
        DWORD pid = 0;
    
        //
        // Get the processid for this window
        //
        if (GetWindowThreadProcessId(hwnd, &pid))
        {
            //
            // If the window belongs to the target process post it
            // a close message
            //
            if (lParam == pid) PostMessage(hwnd, WM_CLOSE, 0, 0);
        }
    
        //
        // Continue the enumeration
        //
        return TRUE;
    }
    
    
    
    void SendCloseToWindows(DWORD dwProcessID)
    {
        EnumWindows(EnumWindowsProc, (LPARAM) dwProcessID);
    }
    
    
    BOOL KillProcess(void)
    {
        BOOL bRet;
    
        //
        // Send WM_CLOSE to top-level windows belonging
        // to the process
        //
        SendCloseToWindows(pi.dwProcessID);
    
        //
        // Wait 2 seconds for the process to finish
        //
        if (WaitForSingleObject(pi.hProcess, 2000) == WAIT_OBJECT_0)
        {
            //
            // Object was signalled, meaning the process has finished
            //
            bRet = TRUE;
        }
        else
        {
            //
            // The wait timed out waiting for the object to become signalled,
            // meaning the process is still running, or an error occurred.
            // Either way, terminate the process forcefully.
            //
            bRet = TerminateProcess(pi.hProcess, 0);
        }
    
        return bRet;
    }

  8. #8
    Registered User whackaxe's Avatar
    Join Date
    Mar 2004
    Posts
    332
    hrm. i think i'll be sticking with terminateprocess()
    1) cos i'm lazy. i know it's bad and a poor excuse, but i have another one!
    2) the software to stop is EXTREMELY slow answering, and it needs to die when i tell it to to keep syncronisd with other events

    thanks you for all your answers and patience

  9. #9
    Yes, my avatar is stolen anonytmouse's Avatar
    Join Date
    Dec 2002
    Posts
    2,544
    You can also try
    Code:
    PostThreadMessage(pi.dwThreadId, WM_QUIT, 0, 0);
    which is a little better than TerminateProcess() but should be faster than WM_CLOSE.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. OpenGL: Depth Testing, Matrixes, ect.?
    By Zeusbwr in forum Game Programming
    Replies: 8
    Last Post: 12-08-2004, 09:37 AM
  2. C++ bit testing
    By Vicious in forum C++ Programming
    Replies: 3
    Last Post: 09-19-2004, 11:44 AM
  3. Blending and Depth Testing
    By Thunderco in forum Game Programming
    Replies: 2
    Last Post: 03-08-2004, 06:37 PM
  4. program for Radiation Testing
    By Unregistered in forum C Programming
    Replies: 5
    Last Post: 02-07-2002, 01:47 AM
  5. Testing Testing 123.. Oh yeah and...
    By minime6696 in forum Windows Programming
    Replies: 0
    Last Post: 08-13-2001, 09:07 AM