Announcement

Collapse
No announcement yet.

Demo - Wait for any process to terminate by using DebugActiveProcess, advice sought

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Demo - Wait for any process to terminate by using DebugActiveProcess, advice sought

    Ive just cooked up this little PB/CC proggy that uses DebugActiveProcess to 'monitor' a process ID to detect the exact millisecond that any monitored process terminates. Yes there are thousands of ways to detect when a process has closed, but this seems to be the fastest in that it 'kicks in' virtually immediately as soon as the monitored process terminates and there isnt any polling as such, just sitting in a WaitForDebugEvent loop.
    To try it out, start a program like calc.exe, then from command prompt run "procmon.exe 500", where 500 is the PID of calc.exe. Then, when you feel like it close Calculator, and the PB/CC monitoring program should tell you immediately that the process has closed.
    NOW, my question!... are there any ways I can improve this? Does being attached to a process in this way slow down the target program? Does sitting in the WaitForDebugEvent hinder system performance at all?
    All feedback is very much appreciated

    Code:
    '[b]PROCMON.BAS[/b]
    #COMPILE EXE
    #INCLUDE "win32api.inc"
    
    SUB DoEventsAPI
    ON ERROR RESUME NEXT
        STATIC Msg AS tagMsg
        IF PeekMessage(Msg, %NULL, 0, 0, %PM_REMOVE) THEN
            TranslateMessage Msg
            DispatchMessage Msg
        END IF
    END SUB
    
    FUNCTION PBMAIN() AS LONG
    DIM DE AS DEBUG_EVENT
    DIM SI AS STARTUPINFO, PI AS PROCESS_INFORMATION
    DIM lRes AS LONG, lStatus AS LONG
    DIM ProcID AS LONG, DebugRes AS LONG
    ProcID = VAL(TRIM$(COMMAND$))
    IF ProcID = 0 OR ProcID = -1 THEN
       STDOUT "Waynes Process Termination Monitor Test"
       STDOUT "Usage: procmon <process ID>"
       EXIT FUNCTION
    END IF
    DebugRes = DebugActiveProcess(ProcID)
    IF DebugRes = 0 THEN
       STDOUT "Failed to attach to process " & TRIM$(STR$(ProcID))
       EXIT FUNCTION
    END IF
    STDOUT "Attached to process " & TRIM$(STR$(ProcID)) & " - waiting for termination...";
          DO
             ' Wait 1ms for a debug event
             lRes = WaitForDebugEvent(DE, 1)
             ' If lRes <> 0 there's a debug event in DE
             IF lRes THEN
                ' Set the default continue status
                lStatus = %DBG_CONTINUE
                SELECT CASE DE.dwDebugEventCode
                   CASE %EXIT_PROCESS_DEBUG_EVENT
                      STDOUT ""
                      STDOUT "Process has terminated!"
                END SELECT
                ' Continue the process execution
                ContinueDebugEvent DE.dwProcessId, DE.dwThreadId, lStatus
             END IF
             ' Allow this process to process messages
             DoEventsAPI
          LOOP UNTIL DE.dwDebugEventCode = %EXIT_PROCESS_DEBUG_EVENT
    END FUNCTION

    ------------------


    [This message has been edited by Wayne Diamond (edited July 10, 2001).]
    -

  • #2
    Wayne,

    I haven't tried the code. But i would expect if a program has started
    debugging another app, the app will suffer some sort of performance hit.
    Since anything the app does must be verified by your program, in that message
    loop.

    Just out of curiosity, have you tried using similar code to actually pause a process?
    I was experimenting which such code in VB a few months ago, but never found
    a way to 'detach' from the program being debugged, until either it or my program
    exited - of which would bring both down.

    - Nathan.

    [This message has been edited by Nathan Evans (edited July 10, 2001).]

    Comment


    • #3
      Thanks Nathan,
      This seems to suspend the process:
      Code:
      #COMPILE EXE
      #INCLUDE "win32api.inc"
      
      SUB DoEventsAPI
      ON ERROR RESUME NEXT
          STATIC Msg AS tagMsg
          IF PeekMessage(Msg, %NULL, 0, 0, %PM_REMOVE) THEN
              TranslateMessage Msg
              DispatchMessage Msg
          END IF
      END SUB
      
      FUNCTION PBMAIN() AS LONG
      DIM DE AS DEBUG_EVENT
      DIM SI AS STARTUPINFO, PI AS PROCESS_INFORMATION
      DIM lRes AS LONG, lStatus AS LONG
      DIM ProcID AS LONG, DebugRes AS LONG
      ProcID = VAL(TRIM$(COMMAND$))
      IF ProcID = 0 OR ProcID = -1 THEN
         STDOUT "Waynes Process Suspension Thingy"
         STDOUT "Usage: procsusp <process ID>"
         EXIT FUNCTION
      END IF
      DebugRes = DebugActiveProcess(ProcID)
      IF DebugRes = 0 THEN
         STDOUT "Failed to attach to process " & TRIM$(STR$(ProcID))
         EXIT FUNCTION
      END IF
      lStatus = %DBG_CONTINUE
      STDOUT "Attached to process " & TRIM$(STR$(ProcID)) & " - waiting for termination...";
      'Wait for the first debug event
      lRes = WaitForDebugEvent(DE, 0)
      'but dont respond with
      STDOUT "Process is suspended, press any key to resume ..."
      WAITKEY$
      ContinueDebugEvent DE.dwProcessId, DE.dwThreadId, lStatus
      STDOUT "Process control returned. Press any key to terminate both apps ..."
      WAITKEY$
      END FUNCTION
      Basically, the process is suspended immediately after WaitForDebugEvent is triggered, and it is suspended until ContinueDebugEvent is called

      Youre right though, it does seem that monitoring a process for termination in this way would affect its performance (but in your case, performance isnt an issue I guess when youre process is suspended )


      ------------------
      -

      Comment


      • #4
        and here is an unorthodox way to terminate a process by attaching to the process to become its debugger, and then unloading, taking both debugger and debuggee out in the one go
        Code:
        #COMPILE EXE
        #INCLUDE "win32api.inc"
        
        FUNCTION PBMAIN() AS LONG
        DIM DE AS DEBUG_EVENT
        DIM SI AS STARTUPINFO, PI AS PROCESS_INFORMATION
        DIM lRes AS LONG, lStatus AS LONG
        DIM ProcID AS LONG, DebugRes AS LONG
        ProcID = VAL(TRIM$(COMMAND$))
        IF ProcID = 0 OR ProcID = -1 THEN
           STDOUT "Waynes Process Kill Thingy"
           STDOUT "Usage: prockill <process ID>"
           EXIT FUNCTION
        END IF
        DebugRes = DebugActiveProcess(ProcID)
        IF DebugRes = 0 THEN
           STDOUT "Failed to attach to process " & TRIM$(STR$(ProcID))
           EXIT FUNCTION
        END IF
        STDOUT "Attached to process. This program will now end, taking PID " & TRIM$(STR$(ProcID)) & " with it!"
        END FUNCTION

        ------------------
        -

        Comment


        • #5
          Thanks for the code.

          I wonder if there's a way to pause a process, and resume it, but without
          remaining its debugger.


          - Nathan.

          Comment

          Working...
          X