If you've ever used the Windows API, then you'll know that it has certain functions to execute and monitor shell applications. In this article Joe shows us how to execute and monitor a C++ program as a separate process using API's through a Visual Basic ActiveX DLL and ASP.
Executing And Tracking A Process With VB And ASP - Creating the ActiveX DLL (Page 3 of 3 )
Remember earlier how I said that we would be executing our C++ application via an ActiveX DLL? Well now we're going to actually create that DLL using Visual Basic. Fire it up and choose the "ActiveX DLL" option from the new project dialog.
Rename the project to "LegacyApp" and rename the default class module to "Sleeper". Also, add a module and name it "ModAPI":
In Visual Basic, we can use the shell function to start an instance of any program on our computer. The shell function's signature looks like this:
Shell(PathName, [WindowStyle As VbAppWinStyle = vbMinimizedFocus]) As Double
As you can see, it takes two arguments and returns a double, which is the process Id of the instance of the application that the call to shell has created (more on this soon). The first argument is the fully qualified path and filename of the application you wish to run an instance of. The second, optional parameter is the style of the window that the application will be run in.
So, if I wanted to shell to explorer from Visual Basic, I could use this code:
Dim dblProcId as Double
dblProcId = Shell("explorer.exe")
Notice that because explorer.exe is in the windows path by default, we don't need to explicitly specify its full directory path.
Windows has several API calls that allow us to track the progress of an application and detect when it is terminated. Using the process Id returned from the shell function, we can obtain a handle to the running instance of the process and detect when it has terminated (a handle is a special number that windows uses internally to refer to a specific process).
Our dummy C++ legacy app can take a command-line argument for the number of milliseconds to sleep. The API calls we're about to look at are perfect when you need to start a process but can not continue until you know for sure that process has terminated.
So, in a real-life situation, if our C++ legacy app actually did something useful suck as backing up a database, then it would make sense not to continue until it was completed fully.
To accomplish this, we need to add these constant variables and three API declarations to our module, ModAPI:
Public Const PROCESS_ALL_ACCESS = &H1F0FFF
Public Const PROCESS_STILL_ACTIVE = &H103
Public Const PROCESS_QUERY_INFORMATION = &H400
Public Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
Public Declare Function GetExitCodeProcess Lib "kernel32" (ByVal hProcess As Long, lpExitCode As Long) As Long
Public Declare Function CloseHandle Lib "kernel32.dll" (ByVal hObject As Long) As Long
The OpenProcess API takes three arguments and returns a handle to a process. Its first argument, dwDesiredAccess, specifies the access to the process. The second argument, bInheritHandle, specifies whether a new process created by the current process can inherit the returned handle. The third and final argument, dwProcessId, specifies the identifier of the process to open (which, in our example is the process Id returned from the shell command).
The GetExitCodeProcess API takes two arguments and returns the termination status of a specific process. Its first argument, hProcess, specifies the handle to the process. The second argument, lpExitCode, is a reference to a variable that will receive the termination status of the process.
As you will see shortly, we use a do…loop control to constantly poll our application for its termination status until it has actually terminated. The last API call that we need, CloseHandle, closes an open object handle and returns non-zero on success. It takes just one parameter, which is the handle of the object to close.
The variable declarations that we have included in our module will be used by our Sleeper class, which we will look at now.
DISCLAIMER: The content provided in this article is not warranted or guaranteed by Developer Shed, Inc. The content provided is intended for entertainment and/or educational purposes in order to introduce to the reader key ideas, concepts, and/or product reviews. As such it is incumbent upon the reader to employ real-world tactics for security and implementation of best practices. We are not liable for any negative consequences that may result from implementing any information covered in our articles or tutorials. If this is a hardware review, it is not recommended to open and/or modify your hardware.