You are currently offline, waiting for your internet to reconnect

How To Launch a Win32 Application from Visual Basic

This article was previously published under Q129797
This article has been archived. It is offered "as is" and will no longer be updated.
A Windows application can consist of more than one process, and a processcan consist of more than one thread. The Microsoft Win32 applicationprogram interface (API) supports multitasking, which creates the effect ofsimultaneous execution of multiple processes and threads. This articledescribes processes and threads, and explains how to create and use themfrom Microsoft Visual Basic, with a step-by-step example.
A process is a program that is loaded into memory and prepared forexecution. Each process has a private virtual address space. A processconsists of the code, data, and other system resources such as files,pipes, and synchronization objects that are accessible to the threads ofthe process. Each process is started with a single thread, but additionalindependently executing threads can be created.

A thread can execute any part of the program's code, including a partexecuted by another thread. Threads are the basic entity to which theoperating system allocates CPU time. Each thread maintains a set ofstructures for saving its context while waiting to be scheduled forprocessing time. The context includes the thread's set of machineregisters, the kernel stack, a thread environment block, and a user stackin the address space of the thread's process. All threads of a processshare the virtual address space and can access the global variables andsystem resources of the process.

A multitasking operating system divides the available CPU time among thethreads that need it. In Windows, the Win32 API is designed for preemptivemultitasking; this means that the system allocates small slices of CPU timeamong the competing threads. The currently executing thread is suspendedwhen its time slice elapses, allowing another thread to run. When thesystem switches from one thread to another, it saves the context of thesuspended thread and restores the saved context of the next thread in thequeue.

Because each time slice is small (approximately 20 milliseconds), itappears that multiple threads are executing at the same time. This isactually the case on multiprocessor systems where the executable threadsare distributed among the available processors. On a single processorsystem, however, using multiple threads does not result in moreinstructions being executed. In fact, the system can slow down if it isforced to keep track of too many threads.

How to Launch Win32 Applications from Visual Basic

There are two ways to launch another Win32 application from a MicrosoftVisual Basic application:
  • Use the Visual Basic shell command. This spawns a new process and returns its process ID. However, to be able to do anything useful, a process handle is required, which can be obtained by a subsequent call to the OpenProcess Win32 API function.
  • Use the CreateProcess Win32 API function that creates both a process object and a main thread object. Both the process and the initial thread are assigned a 32-bit identifier that remains valid until the respective object (process or thread) terminates. The 32-bit identifier can be used to uniquely identify the object within the system. The new process and new thread handles are also created with full access rights. All these four values are returned in the PROCESS_INFORMATION structure that is passed by reference to CreateProcess.
The process handle returned by either of the two methods can then be usedwith other Win32 APIs such as TerminateProcess to manipulate the newlylaunched application.

It is important to understand that at creation time, the system gives eachobject an initial usage count of one. Then, just before CreateProcessreturns, the function opens both the process and the thread object andplaces the process-relative handles for each in the hProcess and hThreadmembers of the PROCESS_INFORMATION structure.

When CreateProcess opens these objects, the usage count for each incrementsto two. This means that before the Windows NT or Windows 2000 Executive can free the process object, the process must terminate (decrementing the usage count to one) and the parent process must call CloseHandle (decrementing the usage count to zero). To free the thread object, the thread must terminate and the parent process must close the handle to the thread object.

CAUTION: It is very important to close these handles. Failure to do so canresult in a system memory leak because some Windows NT or Windows 2000 Executive objects are never destroyed.

Similar considerations are required when obtaining a process handle withOpenProcess. In this case too, the usage count is incremented by one, andunless the handle is closed, the process object will remain in memory evenwhen the process itself has terminated.

Step-by-Step Example

  1. Start a new Standard EXE project in Visual Basic. Form1 is created by default.
  2. Copy the following code to the Code window of the Form1 form:
    Option Explicit      Private Type PROCESS_INFORMATION         hProcess As Long         hThread As Long         dwProcessId As Long         dwThreadId As Long      End Type      Private Type STARTUPINFO         cb As Long         lpReserved As String         lpDesktop As String         lpTitle As String         dwX As Long         dwY As Long         dwXSize As Long         dwYSize As Long         dwXCountChars As Long         dwYCountChars As Long         dwFillAttribute As Long         dwFlags As Long         wShowWindow As Integer         cbReserved2 As Integer         lpReserved2 As Long         hStdInput As Long         hStdOutput As Long         hStdError As Long      End Type      Private Declare Function CreateProcess Lib "kernel32" _         Alias "CreateProcessA" _         (ByVal lpApplicationName As String, _         ByVal lpCommandLine As String, _         lpProcessAttributes As Any, _         lpThreadAttributes As Any, _         ByVal bInheritHandles As Long, _         ByVal dwCreationFlags As Long, _         lpEnvironment As Any, _         ByVal lpCurrentDriectory As String, _         lpStartupInfo As STARTUPINFO, _         lpProcessInformation As PROCESS_INFORMATION) As Long      Private Declare Function OpenProcess Lib "kernel32.dll" _         (ByVal dwAccess As Long, _         ByVal fInherit As Integer, _         ByVal hObject As Long) As Long      Private Declare Function TerminateProcess Lib "kernel32" _         (ByVal hProcess As Long, _         ByVal uExitCode As Long) As Long      Private Declare Function CloseHandle Lib "kernel32" _         (ByVal hObject As Long) As Long      Const SYNCHRONIZE = 1048576      Const NORMAL_PRIORITY_CLASS = &H20&      Private Sub Form_Click()         Dim pInfo As PROCESS_INFORMATION         Dim sInfo As STARTUPINFO         Dim sNull As String         Dim lSuccess As Long         Dim lRetValue As Long         sInfo.cb = Len(sInfo)         lSuccess = CreateProcess(sNull, _                                 "Calc.exe", _                                 ByVal 0&, _                                 ByVal 0&, _                                 1&, _                                 NORMAL_PRIORITY_CLASS, _                                 ByVal 0&, _                                 sNull, _                                 sInfo, _                                 pInfo)         MsgBox "Calculator has been launched!"         lRetValue = TerminateProcess(pInfo.hProcess, 0&)         lRetValue = CloseHandle(pInfo.hThread)         lRetValue = CloseHandle(pInfo.hProcess)         MsgBox "Calculator has terminated!"      End Sub					
  3. On the Run menu, select Start, or press the F5 key to start the program. Click on the Form1 form to launch the Calculator application. A message box appears indicating the application has launched successfully. Click OK to close the message box and the Calculator application. Another message box appears indicating the application has successfully terminated.
For additional information, please see the following articles in the Microsoft Knowledge Base:
129796 How To Use a 32-Bit Application to Determine When a Shelled Process Ends
176391 How To Programmatically Close a Single Instance of a Windows-Based Program

Article ID: 129797 - Last Review: 12/04/2015 11:20:11 - Revision: 2.2

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, Microsoft Visual Basic 5.0 Enterprise Edition, Microsoft Visual Basic 6.0 Enterprise Edition, Microsoft Visual Basic 4.0 Standard Edition, Microsoft Visual Basic 4.0 Professional Edition, Microsoft Visual Basic 4.0 32-Bit Enterprise Edition

  • kbnosurvey kbarchive kbhowto kbapi KB129797