Deborah L. Cooper
October 1996
This article explains how to create an in-process OLE server (that is, a class) in Visual Basic® 4.0 that encapsulates the Windows® application programming interface (API) ShellExecute function. The class developed in this article will allow you to launch other Windows application programs, open and/or print documents, and explore folders under the Windows 95 operating system. In addition, the class also encapsulates the CreateProcessA, WaitForSingleObject, and CloseHandle functions. These functions allow you to launch an application program, set the focus to that application, and wait until that program has been terminated by the user before the focus can be returned to the calling application.
The Windows application programming interface (API) ShellExecute function can be used from within a Microsoft® Visual Basic 4.0 application program to launch other Windows application programs, open and print documents, and explore folders (directories).
The declaration statement for the ShellExecute function is:
Private Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" (ByVal hwnd As Long, ByVal lpOperation As String, ByVal lpFile As String, ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long
As you can see, the ShellExecute function requires six arguments, as follows:
hWnd | A long value containing the window’s handle | |
LpOperation | A string specifying the operation the ShellExecute function is to perform. One of the following three values may be specified: | |
Open—Indicates the file lpFile is to be opened. Under the Windows 95 operating system, this file may be a folder. | ||
Print—Indicates the file lpFile is to be printed. | ||
Explore—Indicates the folder specified in lpFile is to be explored. | ||
LpFile | A string containing the name of the file to open, print, or explore. | |
LpParameters | Set to NULL if lpFile specifies a document file. If lpFile specifies an executable file, then lpParameters is a pointer to a string specifying the parameters that should be passed to the application. | |
LpDirectory | A string specifying the default directory’s name. | |
NShowCmd | If a document file is specified in lpFile, this should be set to a value of zero. If an executable file is specified in lpFile, this determines how the ShellExecute function displays the application after it is loaded. The following values may be used: | |
SW_HIDE | Hides the window and activates the executable file. | |
SW_MAXIMIZE | Maximizes the window. | |
SW_MINIMIZE | Minimizes the window. The next top-level window in the Z-order is activated. | |
SW_RESTORE | Activates the window even if it is hidden or minimized | |
SW_SHOW | Activates the window and displays it in its original size and at its original position. | |
SW_SHOWMAXIMIZED | Activates the window. The window is displayed as maximized. | |
SW_SHOWMINIMIZED | Activates the window. The window is displayed as minimized. | |
SW_SHOWMINNOACTIVE | Activates the window as minimized. The active window retains the focus. | |
SW_SHOWNA | Activates the window in its current state but the active window retains the focus. | |
SW_SHOWNOACTIVATE | Displays the window in its most recent size and in its most recent position. The active window retains the focus. | |
SW_SHOWNORMAL | Displays the window in its original size and at its original position. |
The cShellExecute class included with this article may be used in any application program you develop in Visual Basic 4.0. This class provides an easy mechanism to launch application programs, open or print documents, and explore folders. The class also lets you launch an application program and force that application to retain the focus until it is terminated. Depending on your requirements, either the ShellExecute function or the CreateProcessA function may be used to launch an application program. However, if you need to specifically determine when that newly-launched application has been terminated, then you must use the latter function. The following discussion will show how to implement both of these features in your Visual Basic application programs.
In the demonstration program included with this article, you can click on the ExploreFolder command button. This action tells the program to explore the Most Recently Used Documents folder (c:\windows\recent). The calling program must pass two pieces of information to the ExploreFolder method: the name of the window you want the folder to be opened over and the complete pathname of the folder.
The ExploreFolder method, shown below, calls the ShellExecute function with the two arguments you have specified (the folder and window names). The explorer window is then displayed to the user.
Public Sub ExploreFolder(FormName As Long, FolderName As String)
On Error Resume Next
Dim X As Long
X = ShellExecute(FormName, "Explore", FolderName, 0&, 0&, SW_SHOWMAXIMIZED)
End Sub
To explore a folder under the Windows 95 operating system, we must tell the ShellExecute function the operation to perform, in this case "explore”, the parent window we want to use, and the folder or directory name. The folder will then be displayed on the screen.
In this section, we will discuss how to open a document using the ShellExecute function. Let’s suppose we want to read a text file called WEBSITE.TXT stored in the root directory of our hard disk. In our demonstration program, we would click on the Open Document command button to open the file. The OpenThisDoc method provides this functionality for us.
The OpenThisDoc method in the cShelExec class looks like this:
Public Sub OpenThisDoc(FormName As Long, FileName As String)
On Error Resume Next
Dim X As Long
X = ShellExecute(FormName, "Open", FileName, 0&, 0&, SW_SHOWMAXIMIZED)
End Sub
Notice the OpenThisDoc method requires two arguments—the parent window’s handle and the name of the document we want to open. We pass these two arguments to the ShellExecute function while also setting the ShellExecute’s second argument to “Open”. This tells the ShellExecute function to open the WEBSITE.TT file using the application program associated with this particular file (in this case, Notepad).
The PrintThisFile method in the cShellExec class lets you send a specific file to the printer. The code fragment for PrintThisFile is:
Public Sub PrintThisFile(FormName As Long, FileName As String)
On Error Resume Next
Dim X As Long
X = ShellExecute(FormName, "Print", FileName, vbNullString, 0&, SW_SHOWMAXIMIZED)
End Sub
As with both the ExploreFolder and OpenThisDoc methods, the PrintThisFile method requires that you pass the file’s name and the parent window’s handle to the method. Next, the operation field of the ShellExecute function is set to “Print”, which sends the document to the printer.
Although the ShellExecute function is quite versatile when it comes to launching applications, printing documents, and exploring folders, it does have one drawback. When you use the ShellExecute function to launch another Windows application program, that second program is immediately executed but you have no way of forcing the user’s attention specifically to that application. The user is free to click on any other application’s window, making that window the current focus of his attention.
In many situations, you may want to launch an application program and force the operating system to wait until that application has been terminated before allowing any other action to be performed. Unfortunately, you cannot use the ShellExecute function to do this!
You must use several other Windows API functions to launch and wait for the program to be terminated. The ExecuteAndWait method, shown below, can address this problem quite nicely. All you have to do is provide the full pathname and its required arguments to this method. The application you have just launched will retain the focus until it is subsequently terminated.
Public Sub ExecuteAndWait(cmdline As String)
Dim NameOfProc As PROCESS_INFORMATION
Dim NameStart As STARTUPINFO
Dim X As Long
NameStart.cb = Len(NameStart)
X = CreateProcessA(0&, cmdline$, 0&, 0&, 1&, NORMAL_PRIORITY_CLASS, 0&, 0&, NameStart, NameOfProc)
X = WaitForSingleObject(NameOfProc.hProcess, INFINITE)
X = CloseHandle(NameOfProc.hProcess)
End Sub
As you can see from the code above, the ExecuteAndWait method uses several functions—CreateProcessA, WaitForSingleObject, and CloseHandle. We have already seen that a Windows application program can be executed by calling the ShellExecute function. You can also use the CreateProcessA function to launch applications and to force that application to retain the focus until it is terminated.
When an application program is launched, a process is created by the operating system. In other words, a process is an application program loaded into memory. The operating system gives each application, or process, a unique 32-bit identifier. When the process is terminated, the identifier becomes invalid—it is no longer in use.
Therefore, to execute a program and wait until it is terminated, you must first call the CreateProcessA function to load and execute your application program. Next, you call the WaitForSingleObject function which forces the operating system to wait until this application has been terminated. Finally, when the application has been terminated by the user, you call the CloseHandle function to release the application’s 32-bit identifier to the system pool. The bibliography at the end of this article sites several articles that discuss this concept in greater detail.
“How to Launch App Based on File Extension Using ShellExecute,” Q147807 (MSDN Library, Knowledge Base)
“Using Associations to Find and Start Applications” (MSDN Library, Platform, SDK, and DDK Documentation)
“How to Determine When a Shelled 32-bit Process Has Terminated,” Q129796 (MSDN Library, Knowledge Base)
Tip 168: Using the ShellExecute Function to Print Files (MSDN Library, Technical Articles)
WaitForSingleObject, QuickInfo.
“How to Launch a Win32 Application from Visual Basic”, Q129797 (MSDN Library, Knowledge Base)
“Tip 173: Launching Applications in Visual Basic” (MSDN Library, Technical Articles)