KnowledgeBase Archive

An Archive of Early Microsoft KnowledgeBase Articles

View on GitHub

Q129797: HOWTO: Launch a Win32 Application from Visual Basic

Article: Q129797
Product(s): Microsoft Visual Basic for Windows
Version(s): WINDOWS:4.0,5.0,6.0
Operating System(s): 
Keyword(s): kbAPI kbVBp kbVBp400 kbVBp500 kbVBp600 kbGrpDSVB kbDSupport
Last Modified: 11-JAN-2001

-------------------------------------------------------------------------------
The information in this article applies to:

- Microsoft Visual Basic Learning Edition for Windows, versions 5.0, 6.0 
- Microsoft Visual Basic Professional Edition for Windows, versions 5.0, 6.0 
- Microsoft Visual Basic Enterprise Edition for Windows, versions 5.0, 6.0 
- Microsoft Visual Basic Standard Edition, 32-bit, for Windows, version 4.0 
- Microsoft Visual Basic Professional Edition, 32-bit, for Windows, version 4.0 
- Microsoft Visual Basic Enterprise Edition, 32-bit, for Windows, version 4.0 
-------------------------------------------------------------------------------

SUMMARY
=======

A Windows application can consist of more than one process, and a process can
consist of more than one thread. The Microsoft Win32 application program
interface (API) supports multitasking, which creates the effect of simultaneous
execution of multiple processes and threads. This article describes processes
and threads, and explains how to create and use them from Microsoft Visual
Basic, with a step-by-step example.

MORE INFORMATION
================

A process is a program that is loaded into memory and prepared for execution.
Each process has a private virtual address space. A process consists of the
code, data, and other system resources such as files, pipes, and synchronization
objects that are accessible to the threads of the process. Each process is
started with a single thread, but additional independently executing threads can
be created.

A thread can execute any part of the program's code, including a part executed by
another thread. Threads are the basic entity to which the operating system
allocates CPU time. Each thread maintains a set of structures for saving its
context while waiting to be scheduled for processing time. The context includes
the thread's set of machine registers, the kernel stack, a thread environment
block, and a user stack in the address space of the thread's process. All
threads of a process share the virtual address space and can access the global
variables and system resources of the process.

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

Because each time slice is small (approximately 20 milliseconds), it appears that
multiple threads are executing at the same time. This is actually the case on
multiprocessor systems where the executable threads are distributed among the
available processors. On a single processor system, however, using multiple
threads does not result in more instructions being executed. In fact, the system
can slow down if it is forced 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 Microsoft Visual
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 used with
other Win32 APIs such as TerminateProcess to manipulate the newly launched
application.

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

When CreateProcess opens these objects, the usage count for each increments to
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 can result
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 with
OpenProcess. In this case too, the usage count is incremented by one, and unless
the handle is closed, the process object will remain in memory even when 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.

REFERENCES
==========

For additional information, please see the following articles in the Microsoft
Knowledge Base:

  Q129796 HOWTO: 32-Bit App Can Determine When a Shelled Process Ends

  Q176391 HOWTO: Programmatically Close a Separate Application

Additional query words:

======================================================================
Keywords          : kbAPI kbVBp kbVBp400 kbVBp500 kbVBp600 kbGrpDSVB kbDSupport 
Technology        : kbVBSearch kbAudDeveloper kbZNotKeyword6 kbZNotKeyword2 kbVB500Search kbVB600Search kbVBA500 kbVBA600 kbVB500 kbVB600 kbVB400Search kbVB400
Version           : WINDOWS:4.0,5.0,6.0
Issue type        : kbhowto

=============================================================================

THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY.

Copyright Microsoft Corporation 1986-2002.