Microsoft KB Archive/176391

= How To Programmatically Close a Single Instance of a Windows-Based Program =

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:  Start a new Standard EXE project in Visual Basic. By default, Form1 is created. Add two CommandButton controls to Form1.  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  Press F5 to run the program. To start the Windows Calculator program, click Start the Calculator.

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

