Diagnose This: Launching and Controlling System Processes with Visual Basic 6 and the .NET Framework
Swigart Consulting LLC
Visual Basic 6
Summary: This article explains how to use the Process class (in the System.Diagnostics section of the .NET Framework Class Library) from a Visual Basic 6 application, to launch and control system processes. (10 printed pages)
Click here to download the code sample for this article.
Continuing with the Visual Basic Fusion theme of "There's nothing in .NET that you can't access from Visual Basic 6," I want to take some time to dig into the functionality provided by the .NET Framework System.Diagnostics classes. In particular, I want to take a look at the very useful Process class, which lets you launch and control system processes, and show you how you can use this class from a Visual Basic 6 application.
Have you ever noticed how .NET demonstrations often degrade to "And all that with just one line of code!" It's almost like the coding version of "Name that Tune." In some ways, it's become a cliché.
Well, I'm a sucker for clichés, so take a look at the application in Figure 1, which shows extensive information about all the processes that are currently running.
Figure 1. Visual Basic .NET application that shows running process information (Click on the image for a larger picture)
And all that with just one line of code! (See Listing 1.)
Listing 1. Visual Basic .NET code to display process information
DataGrid1.DataSource = Process.GetProcesses()
The .NET Framework contains a class called Process. This class exposes functions that let you start processes, stop processes, and get information about running processes. The GetProcesses function returns an array of information about all the currently running processes. Visual Basic .NET supports databinding grids directly to arrays, and so all you have to do is set the DataSource property of the grid to the results returned from GetProcesses, and you get all the process information displayed in a grid.
Like most of the classes in the .NET Framework, the Process class is not directly available to a Visual Basic 6 application. Instead, you can expose the functionality of this class by creating a simple wrapper in Visual Basic .NET.
Listing 2 shows the code for the wrapper.
Listing 2. Visual Basic .NET wrapper class
Imports System.Diagnostics Public Class ProcessWrapper #Region "COM GUIDs" ' These GUIDs provide the COM identity for this class ' and its COM interfaces. If you change them, existing ' clients will no longer be able to access the class. Public Const ClassId As String = "C655826A-F52C-4DE8-91DF-61B6C439B839" Public Const InterfaceId As String = "2205598A-B161-421A-A6FF-2741418F2817" Public Const EventsId As String = "9A7918EE-E3BA-41C8-A514-04B8D18DE605" #End Region ' A creatable COM class must have a Public Sub New() ' with no parameters, otherwise, the class will not be ' registered in the COM registry and cannot be created ' via CreateObject. Public Sub New() MyBase.New() End Sub Public Function Start(ByVal command As String) As ProcessInfo Dim p As Process = Process.Start(command) Return New ProcessInfo(p) End Function End Class
This class was created by using the COM Class template in Visual Studio 2003, as follows:
- Start Visual Studio 200, click the File menu, and click New Project.
- Under Templates, select Class Library.
- In the Name text box, enter NetFrameworkWrappers, and click OK (see Figure 2).
Figure 2. Creating a new project
- Click the Project menu, and then click Add New Item.
- Under Templates, select COM Class. This allows you to create a class from Visual Basic .NET that will expose itself as a COM object.
- In the Name text box, enter ProcessWrapper.vb, and then click OK (see Figure 3).
Figure 3. Adding ProcessWrapper.vb
- At the top of the file, add the following line of code:
- Add the following method to the class:
Public Function Start(ByVal command As String) As ProcessInfo Dim p As Process = Process.Start(command) Return New ProcessInfo(p) End Function
- Click the Build menu, and then click Build Solution. This will compile the class and register it as a COM object.
At this point, you can just add a reference to NetFrameworkWrappers from a Visual Basic 6 application, and start using the ProcessWrapper class (see Listing 3).
Listing 3. Using the ProcessWrapper class from Visual Basic 6
Dim p As NetFrameworkWrappers.ProcessWrapper Set p = New NetFrameworkWrappers.ProcessWrapper p.Start ("calc.exe")
The Process class also exposes a GetProcesses method that will return information about every process running on the system. The return value of GetProcesses is an array of Process classes, and therefore it is not directly consumable by Visual Basic 6. I created a wrapper for this as well. The ProcessInfo wrapper class wraps the Process class to surface information in a way that's directly consumable by Visual Basic 6. I can then create an array of ProcessInfo classes, and return to my Visual Basic 6 code as shown in Listing 4.
Listing 4. Wrapping the results of GetProcesses so that it can be used from Visual Basic 6
Public Sub GetProcesses(ByRef procInfos() As ProcessInfo) Dim processes() As Process = Process.GetProcesses ReDim procInfos(processes.Length - 1) For i As Integer = 0 To processes.Length - 1 procInfos(i) = New ProcessInfo(processes(i)) Next End Sub
You can see that this calls GetProcesses to retrieve an array of Process classes for each running process. I then loop through each one, and convert it to a ProcessInfo class that was specifically designed to be consumable by Visual Basic 6. For example, the TotalProcessorTime property of the Process class used the .NET TimeSpan data type. This will not show up on the Visual Basic 6 side, and therefore the ProcessInfo class instead returns this information simply as a string.
I've created a Visual Basic 6 sample application (see Figure 4) that uses the Process wrappers to let you control all the processes on your machine. You can launch processes, change a process priority, and even kill a process.
Figure 4. Visual Basic 6 Process Manager
When the form loads, it calls the GetProcesses wrapper and places all the processes in a ListView control (see Listing 5).
Listing 5. Loading the Visual Basic 6 form with process information
Public Sub LoadList() ListView1.ListItems.Clear Dim p As NetFrameworkWrappers.ProcessWrapper Set p = New NetFrameworkWrappers.ProcessWrapper p.GetProcesses procs Dim i As Integer For i = 0 To UBound(procs) - 1 Dim subItem As ListItem Set subItem = ListView1.ListItems.Add(, , procs(i).ProcessName) subItem.SubItems(1) = procs(i).Id subItem.SubItems(2) = procs(i).BasePriority subItem.SubItems(3) = procs(i).PriorityClass subItem.SubItems(4) = procs(i).PriorityBoostEnabled subItem.SubItems(5) = procs(i).MainWindowTitle subItem.SubItems(6) = procs(i).MainWindowHandle subItem.SubItems(7) = FormatNumber(procs(i).VirtualMemorySize / 1048576, 2) & " MB" subItem.SubItems(8) = FormatNumber(procs(i).PeakVirtualMemorySize / 1048576, 2) & " MB" subItem.SubItems(9) = FormatNumber(procs(i).WorkingSet / 1048576, 2) & " MB" subItem.SubItems(10) = FormatNumber(procs(i).PeakWorkingSet / 1048576, 2) & " MB" subItem.SubItems(11) = procs(i).Responding subItem.SubItems(12) = procs(i).TotalProcessorTime subItem.SubItems(13) = procs(i).UserProcessorTime subItem.SubItems(14) = procs(i).HasExited Next End Sub
The LoadList method is used whenever the ListView needs to be repopulated with process information. It simply calls ProcessWrapper.GetProcesses, passing in an empty array of ProcessInfo classes. When the method returns, the array is populated, and the method simply loops through the results and adds them to the list view. Some values—for example, memory usage statistics—are formatted along the way, so that they are more readable.
The application contains a field where you can enter a process name and launch it (see Listing 6).
Listing 6. Launching a process from the Visual Basic 6 application
Private Sub cmdLaunch_Click() Dim p As NetFrameworkWrappers.ProcessWrapper Set p = New NetFrameworkWrappers.ProcessWrapper p.Start (txtProcessLaunch) LoadList End Sub
The application also lets you kill a process (see Listing 7).
Listing 7. Killing a process from the Visual Basic 6 application
Private Sub mnuKill_Click() CurrentProc.Kill LoadList End Sub
Note I don't think there's ever been an example of killing a process that didn't come with the warning that you really shouldn't go just killing processes willy-nilly. So consider yourself warned.
Finally, you can change the priority of a running process (see Listing 8).
Listing 8. Changing the priority of a process from the Visual Basic 6 application
Private Sub mnuSetPriority_Click() Set frmModifyProcess.CurrentProc = CurrentProc If frmModifyProcess.ShowDialog = vbOK Then CurrentProc.PriorityClass = frmModifyProcess.PriorityClass LoadList End If End Sub
This simply displays another form that prompts the user to select a process priority. When the user selects a priority and clicks OK (see Figure 5), the form closes, and the information is returned. The process priority can be set simply by setting the PriorityClass property of the ProcessInfo class. This passes the information to the Visual Basic .NET component, which changes the string back into the appropriate enumeration, and changes the process priority.
Figure 5. Selecting a new process priority from the Visual Basic 6 application
Included with this article is the Visual Basic 6 and Visual Basic .NET code for working with processes. To run the sample, complete the following procedures.
If you do not have Visual Studio 2005 installed, you need to download the (free) Microsoft .NET Framework, and the (free) Visual Basic Express:
- Download and install Visual Basic 2005 Express.
At this point, you can download and run the sample:
- Download and unzip the code for this article.
- Within the zip file, you will find a file called Build and Register.bat. Double-click this to build and register the Visual Basic .NET COM component.
- In the ProcController folder, you will find the Visual Basic 6 sample application.
Once again, you have seen that you can use powerful functionality in the Microsoft .NET Framework easily from a Visual Basic 6 application in order to get things done. The class used in this article was the Process class, one of the many classes in the System.Diagnostics section of the Framework Class Library.
About the Author
Scott Swigart spends his time consulting, authoring, and speaking about emerging and converging technologies. Scott has worked with a wide range of technologies over his career, beginning with Commodore 64 programming at the age of 12, writing hardware diagnostics for UNIX systems in C++, and building Windows desktop and Web applications. Over the years, Scott has worked with component development, XML technologies, .NET, Web services, and other languages, platforms, and paradigms. With this experience, Scott has seen how technology evolves over time, and he is focused on helping organizations get the most out of the technology of today while preparing for the technology of tomorrow. Scott is also a Microsoft MVP, and co-author of numerous books and articles. Scott can be reached at firstname.lastname@example.org.