Solved

VB6 - Process Exit Event?

Posted on 2006-07-07
15
2,211 Views
Last Modified: 2010-08-05
Hello,

Due to constraints within our company, we are rewriting a VB.NET component in VB6.  Our component watches a process to see when it is closed by the user (or by other means).  In VB.NET, we used the Process Class to attach to a running process and then caught the "Process.Exited" event thrown when the process ended.  Is there a similar event in VB6?  

Our program spawns a launcher, which then spawns another process.  We want to wait for the 3rd process to exit, and then throw an event.  For example, our Process (Process A) shell's off Process B (3rd party), which then creates Process C.  When process C exits, we need to throw an event from Process A.  Right now, we are using a loop to constantly check when the process exits, but this causes too much processor usage for no reason.  Currently, our main method looks like the following:

Public Sub RunShell(FileName As String, ProcessToWatch As String)
    Dim idProg As Long, iExit As Long, iProc As Long

    idProg = Shell(FileName, 1)
    iExit = WaitOnShell(idProg)
    If Not iExit Then
        iExit = WaitOnShellByName(ProcessToWatch)
        If Not iExit Then RaiseEvent OnExit
    End If
End Sub

Is there something similar to "Process.Exited" in VB6, and how can I use it?
0
Comment
Question by:TLevin10
  • 7
  • 5
  • 3
15 Comments
 
LVL 28

Expert Comment

by:AzraSound
ID: 17059715
Not that I'm aware of, unless you are the one launching the process, in which case you can "watch" for the process to exit.  If it's merely a processor issue, you may try putting the code checking into some type of timer event to check once a second and then notify you once the process has ended.  It should be much less of a strain on the processor.
0
 

Author Comment

by:TLevin10
ID: 17059840
Is there any way to attach to the process at all?  I know that in VB.NET/C#, I can actually enable a process to raise events and it has an exit handler.  I assume that these are operating system features, not specific to .NET, since I can do it for any running process (Not just .NET compatible ones). For instance, in C#:

public void WatchProcess(string processToWatch)
{
      Process[] procCollection = Process.GetProcessesByName(processToWatch);

      foreach (Process p in procCollection)
      {
            p.EnableRaisingEvents = true;
            p.Exited +=new EventHandler(p_Exited);
      }
}

Is there a similar "Process" class in VB6, or some API calls to do the same thing?

0
 
LVL 28

Accepted Solution

by:
AzraSound earned 500 total points
ID: 17060081
No, remember, .NET is what has introduced this framework of classes/objects for we developers to tap into.  Prior to .NET, everything was done manually via intrinsic VB functions and the Windows API.

In VB, you can watch a process you started with the Shell command or CreateProcess API, because once you have the process id, you can call another API to wait for it to complete:
http://vbnet.mvps.org/index.html?code/faq/waitforsingleobject2.htm

However, if you are not launching this app, then unless you can grab a handle to the process somehow, this API function is useless to you.  It's been so long since I've done anything even remotely related to enumerating/searching for a process, so, if you are getting a handle to this process you are looking for, then you should be able to call the WaitForSingleObject API as demonstrated in the above link to determine when that process has ended.
0
 

Author Comment

by:TLevin10
ID: 17060206
Hi Azra,

First off, thanks for the quick response.  In fact, I do have the handle to the process, so calling WaitForSingleObject isn't such a problem.

Similar to looping, however, WaitForSingleObject() causes my application to hang until the spawned process is closed.  This is not good in my application, since I expect my users to continue working while the new process is doing its job...

Is it possible to use "WaitForSingleObject()" in a non-blocking manner, so that my application can continue running while the new process is doing its thing?

Thanks,

TLevin10
0
 
LVL 28

Expert Comment

by:AzraSound
ID: 17060256
Unfortunately, that's just a drawback of VB and watching a process (not event driven).  Add to the fact VB's lack of real ability to create separate threads, and you begin to run out of options.

With that said, I would say you have a couple of options:

1) As I noted before, run a simple check in some type of timer event to cut down the processor throttling
2) Do the best VB can do in multithreading.  Have this process checking functionality enclosed within an ActiveX EXE project that you can spawn from your main application.  You can shoot the component off to watch for the process and your main app can continue on as normal.  In addition, you can have the ActiveX EXE raise an event when it determines the process has ended, giving you the closest, in terms of look and feel, to your familar .NET Process.Exited scenario.
0
 

Author Comment

by:TLevin10
ID: 17060310
Alright - well, I guess I will have to deal :) [The problem with working backwards is you miss all the new features!]

Thanks
0
 
LVL 28

Expert Comment

by:AzraSound
ID: 17060346
No problem...good luck w/ everything
0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
LVL 29

Expert Comment

by:nffvrxqgrcfqvvc
ID: 17063494
<< Is it possible to use "WaitForSingleObject()" in a non-blocking manner

Yes. You can use MsgWaitForMultipleObjects. This will allow your GUI to process all messages.
0
 
LVL 29

Expert Comment

by:nffvrxqgrcfqvvc
ID: 17063518
Here is quick example to show how it works. You can spice it up as you please.


Option Explicit
   
    Private Declare Function OpenProcess Lib "kernel32" _
        (ByVal dwDesiredAccessas As Long, _
        ByVal bInheritHandle As Long, _
        ByVal dwProcId As Long) As Long

    Private Declare Function MsgWaitForMultipleObjects Lib "user32" ( _
        ByVal nCount As Long, _
        pHandles As Long, _
        ByVal fWaitAll As Long, _
        ByVal dwMilliseconds As Long, _
        ByVal dwWakeMask As Long) As Long
       
    Private Declare Function CloseHandle Lib "kernel32" ( _
        ByVal hObject As Long) As Long
   
    Private Const QS_HOTKEY& = &H80
    Private Const QS_KEY& = &H1
    Private Const QS_MOUSEBUTTON& = &H4
    Private Const QS_MOUSEMOVE& = &H2
    Private Const QS_PAINT& = &H20
    Private Const QS_POSTMESSAGE& = &H8
    Private Const QS_SENDMESSAGE& = &H40
    Private Const QS_TIMER& = &H10

    Private Const QS_ALLINPUT& = (QS_SENDMESSAGE _
                                Or QS_PAINT _
                                Or QS_TIMER _
                                Or QS_POSTMESSAGE _
                                Or QS_MOUSEBUTTON _
                                Or QS_MOUSEMOVE _
                                Or QS_HOTKEY _
                                Or QS_KEY)
                               
    Private Const WAIT_OBJECT_0& = 0
    Private Const INFINITE = &HFFFF
    Private Const PROCESS_ALL_ACCESS = &H1F0FFF
   
Dim hProcess As Long

Private Sub WaitOnProcess(ByVal arg As String)
   
    Dim PID     As Long
    Dim lBusy   As Long
   
    PID = Shell(arg, vbNormalFocus)
    hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0&, PID)
    Do
    lBusy = MsgWaitForMultipleObjects(1, hProcess, False, INFINITE, QS_ALLINPUT&)
    DoEvents
    Loop Until lBusy = WAIT_OBJECT_0&
    CloseHandle hProcess
   
    MsgBox arg & vbTab & "Exited", vbSystemModal
   
End Sub

Private Sub Command1_Click()
    WaitOnProcess "c:\windows\system32\calc.exe"
End Sub
0
 
LVL 28

Expert Comment

by:AzraSound
ID: 17065734
That, along with GetExitCodeProcess, though, both require a Do...Loop with the DoEvents keyword which results in 100% CPU usage, which is why I didn't suggest it (since processor usage was already an issue).
0
 
LVL 29

Expert Comment

by:nffvrxqgrcfqvvc
ID: 17066202
I agree with you that GetExitCodeProcess is high cpu usage but this is not the same when using MsgWaitForMultipleObjects
0
 
LVL 28

Expert Comment

by:AzraSound
ID: 17066598
Really?  That's very interesting as I don't think I've ever seen a Do...Loop, regardless of what was inside of it, as long as it had a DoEvents in it, it would eat up 100% of the CPU.  
0
 
LVL 29

Expert Comment

by:nffvrxqgrcfqvvc
ID: 17066607
Have you looked at the CPU usage when you run the example
0
 
LVL 28

Expert Comment

by:AzraSound
ID: 17068531
No, I'll take your word for it...I'm just saying its new to me.
0
 
LVL 29

Expert Comment

by:nffvrxqgrcfqvvc
ID: 17068587
Yeah its very nice for waiting on events because it pumps messages to your gui, and passes on the messages that are not of interest. This is what doevents is doing in the call simply passing along all messages. In C++ instead of doevents you would need to use PeekMessage,DispatchMessage.

http://blogs.msdn.com/oldnewthing/archive/2005/02/17/375307.aspx
0

Featured Post

Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

Join & Write a Comment

Introduction While answering a recent question about filtering a custom class collection, I realized that this could be accomplished with very little code by using the ScriptControl (SC) library.  This article will introduce you to the SC library a…
You can of course define an array to hold data that is of a particular type like an array of Strings to hold customer names or an array of Doubles to hold customer sales, but what do you do if you want to coordinate that data? This article describes…
Get people started with the process of using Access VBA to control Outlook using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Microsoft Outlook. Using automation, an Access applic…
Show developers how to use a criteria form to limit the data that appears on an Access report. It is a common requirement that users can specify the criteria for a report at runtime. The easiest way to accomplish this is using a criteria form that a…

747 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

9 Experts available now in Live!

Get 1:1 Help Now