Microsoft KB Archive/176391

From BetaArchive Wiki
Knowledge Base


Article ID: 176391

Article Last Modified on 7/1/2004



APPLIES TO

  • Microsoft Visual Basic 5.0 Enterprise Edition
  • Microsoft Visual Basic 6.0 Enterprise Edition
  • Microsoft Visual Basic 5.0 Learning Edition
  • Microsoft Visual Basic 6.0 Learning Edition
  • Microsoft Visual Basic 5.0 Professional Edition
  • Microsoft Visual Basic 6.0 Professional Edition



This article was previously published under Q176391

SUMMARY

This article describes how use API functions to programmatically close a single instance of most Windows programs through your Microsoft Visual Basic program. You can use this feature to start a program, to run the program without any user interaction, and to quit the program when all the program tasks are complete.

MORE INFORMATION

To programmatically close a single instance of a Windows program, use the FindWindow function to get the handle to the window that you want to close. The FindWindow function returns the handle of a top-level window with a class name and a window name that match the string parameters. The FindWindow function returns the handle of the window as a long value if it is successful, and it returns the handle of the window as a null value if it fails. To use FindWindow, you must supply the following two parameters:

  • lpClassName - a pointer to a null-terminated string that specifies the class name


-or-

a null-terminated string that is an atom that identifies the class-name string.

In this program, you can pass vbNullString.

  • lpWindowName - a pointer to a null-terminated string that specifies the window name (the title of the window).

Use the handle to send a message to close the window with the PostMessage function. The PostMessage function sends a message to a program message queue, which returns a value immediately. This function returns a non-zero value if it is successful, and it returns a zero value if it fails.

To use the PostMessage function, you must specify the following four parameters:

  • hWnd - the handle of the window that you want to close.


This long value is available as the result of the FindWindow function.

  • uInt - the message to post to the message queue. In this program, use the WM_CLOSE message.
  • wParam - the first message parameter. For this message, pass a null value.
  • lParam - the second message parameter. For this message, pass a null value.

If you send a message too soon in the event, a synchronization problem may occur that causes the program to quit before the message is processed. When you use the WaitForSingleObject function, this makes sure that the message is processed before the program quits.

To use the WaitForSingleObject function, you must specify the following two parameters:

  • hHandle - the handle of the object that you want to monitor.
  • dwMilliseconds - specifies the time-out interval in milliseconds.


If you set this parameter to infinite, the time-out interval of the function never elapses.

The WaitForSingleObject function requires a process handle, which is different from an hWnd. You must call GetWindowThreadProcessId to determine the ProcessID, and then pass it to the OpenProcess function to obtain a process handle.

To make sure that the program is closed, use the IsWindow function to determine whether the handle is valid. The IsWindow function returns a non-zero value if the handle is valid, and it returns a zero value if the handle does not exist.

To use the IsWindow function, specify the handle to check. If the handle still exists, you can use the TerminateProcess function to stop the handle process. However, Microsoft does not recommended that you use this extreme approach. Although you may have stopped the handle process, the dynamic-link libraries (DLLs) that are used by the handle may still reside in memory, which causes a memory leak. Use the TerminateProcess function with caution.

Create the Sample Program

This section describes how to create a sample program that shows you how to use Visual Basic code to quit a running program. The sample program starts and stops the Windows Calculator program.

To create the sample program, follow these steps:

  1. Start a new Standard EXE project in Visual Basic. By default, Form1 is created.
  2. Add two CommandButton controls to Form1.
  3. Copy the following code to the Code window of Form1:

          Option Explicit
    
          Private Declare Function WaitForSingleObject Lib "kernel32" _
             (ByVal hHandle As Long, _
             ByVal dwMilliseconds As Long) As Long
    
          Private Declare Function FindWindow Lib "user32" _
             Alias "FindWindowA" _
             (ByVal lpClassName As String, _
             ByVal lpWindowName As String) As Long
    
          Private Declare Function PostMessage Lib "user32" _
             Alias "PostMessageA" _
             (ByVal hwnd As Long, _
             ByVal wMsg As Long, _
             ByVal wParam As Long, _
             ByVal lParam As Long) As Long
    
          Private Declare Function IsWindow Lib "user32" _
             (ByVal hwnd As Long) As Long
    
          Private Declare Function OpenProcess Lib "kernel32" _
             (ByVal dwDesiredAccess As Long, _
             ByVal bInheritHandle As Long, _
             ByVal dwProcessId As Long) As Long
          
          Private Declare Function GetWindowThreadProcessId Lib "user32" _
             (ByVal hwnd As Long, _
             lpdwProcessId As Long) As Long
    
          'Constants that are used by the API
          Const WM_CLOSE = &H10
          Const INFINITE = &HFFFFFFFF
          Const SYNCHRONIZE = &H100000
    
          Private Sub Form_Load()
             Command1.Caption = "Start the Calculator"
             Command2.Caption = "Close the Calculator"
          End Sub
    
          Private Sub Command1_Click()
          'Starts Windows Calculator
             Shell "calc.exe", vbNormalNoFocus
          End Sub
    
          Private Sub Command2_Click()
          'Closes Windows Calculator
             Dim hWindow As Long
             Dim hThread As Long
             Dim hProcess As Long
             Dim lProcessId As Long
             Dim lngResult As Long
             Dim lngReturnValue As Long
    
             hWindow = FindWindow(vbNullString, "Calculator")
             hThread = GetWindowThreadProcessId(hWindow, lProcessId)
             hProcess = OpenProcess(SYNCHRONIZE, 0&, lProcessId)
             lngReturnValue = PostMessage(hWindow, WM_CLOSE, 0&, 0&)
             lngResult = WaitForSingleObject(hProcess, INFINITE)
    
             'Does the handle still exist?
             DoEvents
             hWindow = FindWindow(vbNullString, "Calculator")
             If IsWindow(hWindow) = 1 Then
                'The handle still exists. Use the TerminateProcess function
                'to close all related processes to this handle. See the
                'article for more information.
                MsgBox "Handle still exists."
             Else
                'Handle does not exist.
                MsgBox "All Program Instances Closed."
             End If
          End Sub
                        
  4. Press F5 to run the program.
  5. To start the Windows Calculator program, click Start the Calculator.

    To quit the Windows Calculator program, click Close the Calculator.


REFERENCES

For additional information, click the article numbers below to view the articles in the Microsoft Knowledge Base:

129797 How To Launch a Win32 Application from Visual Basic


129796 How To Use a 32-Bit Application to Determine When a Shelled Process Ends


For additional information, see both of the following:

  • Platform SDK documentation on FindWindow and PostMessage functions
  • Visual Basic 5.0 Programmer's Guide to the Win32 API



Additional query words: Platform SDK documentation terminate

Keywords: kbhowto kbapi KB176391