The. NET Framework
upgrade to Microsoft. NET using the . NET Framework classes instead of API calls
Ken Getz
MCW Technologies
February 2002
Summary: by learning some of the specific and useful classes in the Microsoft. NET framework, you can reduce your reliance on WIN32 API calls. Each class discussed in this article can replace one or more Win32 API calls, whereas in Microsoft Visual Basic 6.0 You must invoke one or more Win32 APIs to accomplish the same task.
Goal
- Find a specific substitute for an existing Win32 API call.
- Learn about the Registry class.
- Use the FileVersionInfo class.
- Use environment information and system information.
Directory
- Avoid using the Win32 API
- Using the Registry
- Use a common dialog box
- Retrieving file version information
- Retrieving environment information
- Summarize
Avoid using the Win32 API
If you are a Microsoft Visual basic®6.0 developer, you cannot avoid invoking the Win32 API. The developer has too many tasks to complete, and Visual Basic does not provide any implementation methods. For example, in Visual Basic 6.0, you have difficulty completing the following tasks:
- Determines the file version information.
- Read and write at any location in the registry.
- Identify specific folders for users, such as Microsoft Windows® favorites or Personal folders.
- Retrieves a list of all available drives.
- Locate the user's logon or computer name.
- Retrieves a list of all open windows.
If you use only the tools provided in Visual Basic 6.0, you will not be able to resolve any of these issues. For each issue, developers need to use the Windows API. Many developers have found ways to accomplish these (and many other) tasks using the Windows API.
What is wrong with the Windows API?
Why not continue using the Windows APIs in the. NET environment? If you use the. NET platform invoke service (called "P/invoke"), you can certainly do so. From the Visual Basic Developer's perspective, calling the Windows APIs is no more difficult than using the Declare statement that they are familiar with. However, there are some serious drawbacks to using the Windows API in a. NET environment, and you may need to consider any possible measures to avoid these problems. For example:
- The. NET common language runtime is not affected by the platform. When you use the Windows API call, you bind the code to a specific platform that writes code (that is, a particular version of Windows or Windows itself) relative to the other operating system. If necessary, you need to convert the code to another platform, and doing so requires modifying each line of code that uses API calls.
- Calling the Windows API (or any unmanaged code in a DLL) from. NET is not as simple as in Visual Basic 6.0. For example, restrictions on how a structure works can make it difficult to pass a struct to an API call. In addition, the API declarations for Visual Basic 6.0 need to be changed due to changes in data types and more stringent type conversions.
- Depending on the language, the techniques for using the Windows API (and often the external code used) are different. If you plan to work in a multiple. NET locale, you will need to master the different skills of each language.
- Code that invokes the Windows API requires that the user who calls the code have the right to perform this operation. This affects the application's security protection scenarios, and you need to make early arrangements for this requirement.
This is a simple question: although you can continue to use the Windows APIs in Visual Basic. NET applications, you should normally find alternatives that are provided by the. NET Framework. Although the purpose of the. NET framework is not to prevent you from using Windows directly, the framework does provide a number of classes that can help you discard dependencies on Windows API calls.
It may be convenient to give a complete list of Win32 API calls and the appropriate methods (if any) to accomplish the same tasks in the. NET framework, although this is not covered in this article. In this article, you will learn about some of the specific and very useful classes provided by the. NET framework that can solve your problem. In each example, the classes discussed in this article can be used to override one or more Win32 API calls, whereas in Microsoft Visual Basic 6.0 You must invoke one or more Win32 APIs to accomplish the same task.
Using the Registry
If you are like most Visual Basic 6.0 developers, you will find the SaveSetting, GetSetting, Getallsetti that are built into Microsoft Visual Basic for Applications (VBA) NGS and DeleteSetting methods are useful, but they are likely to be exhausted by their limitations. All of these methods can only be used in the Registry's HKEY_CURRENT_USER\Software\VB and under the VBA program Settings. If you want to read or write registry keys or registry values elsewhere in the registry, you must use a complex API call or rely on someone else's code to handle the problem.
The. NET Framework provides a powerful class (Registry and RegistryKey) in the Microsoft.Win32 namespace, simplifying the use of the registry by eliminating the need for API calls!
As a demo, click the Work with the Registry(Use the Registry) button on the main form of the sample project. This form provides a list of all the registry values in the HKEY_LOCAL_MACHINE hive for the SOFTWARE\Microsoft\Windows\CurrentVersion\Run item. You can right-click any item in the list and choose to insert a new item, or edit or delete the selected item, as shown in Figure 1.
Tip: The sample form is also designed so that when you press
Enter in the list box, you can edit the currently selected item. Press the
delete key to delete the selected item and press the
Insert key to add a new value. These items correspond to the items in the context menu of the list box.
Figure 1: Easily retrieve and modify information in the Windows registry using the Registry and RegistryKey classes
The. NET Framework provides two very useful classes that make it easy for you to use the Windows registry. The first class is Registry, which provides the fields that correspond to the fields of the standard Registry hive:
- Classesroot (HKEY_CLASSES_ROOT)
- Currentconfig (Hkey_current_config)
- CurrentUser (HKEY_CURRENT_USER)
- DynData (HKEY_DYN_DATA)
- LocalMachine (HKEY_LOCAL_MACHINE)
- PerformanceData (Hkey_performance_data)
- Users (HKEY_USERS)
To use the Registry class, simply retrieve the reference for the desired hive. The Loadlist procedure for the sample form includes the following code to use the HKEY_LOCAL_MACHINE hive in the registry:
Imports Microsoft.win32dim reg as RegistryKey = Registry.localmachine
Another class is RegistryKey, which can do all the work. It provides a set of methods for using Registry. Table 1 lists all the useful methods for the RegistryKey class.
Table 1:registrykey class method
Method
DescriptionCreateSubKey creates a new subkey or opens an existing subkey DeleteSubKey deletes the specified subkey. Deletesubkeytree deletes the subkey and all subkeys of the subkey recursively. DeleteValue removes the specified item value from the item. Getsubkeynames retrieves an array of strings containing all the subkey names. GetValue retrieves the specified value. GetValueNames retrieves a string array that contains the names of all item values associated with this item. OpenSubKey retrieves the specified subkey with optional write permissions. SetValue sets the specified value.
The RegistryKey class also provides the following three properties:
- Name: Retrieves the names of the items.
- Subkeycount: Retrieves the number of subkeys associated with the item.
- Valuecount: Retrieves the number of item values associated with the item.
The Listload procedure for the sample form retrieves all the values in the requested item and adds the retrieved values to the form's list box:
Private Const Conregkey as String = _ "SOFTWARE\Microsoft\Windows\CurrentVersion\Run" Private Structure regdata Public Value As String public Data As String public Overrides _ Function ToString () As String return Me.va Lue End functionend structureprivate Sub listload () Dim reg As RegistryKey = Registry.LocalMachine
Dim astrvalues () as String Dim strvalue as string< C9/>dim Rd as Regdata ' clears an existing item in a list box. lstitems.beginupdate () lstItems.Items.Clear () opens the registry key, and then uses the value of the item to load the list box. reg = reg.OpenSubKey(conRegKey)
astrValues = reg.GetValueNames()
For each strvalue in astrvalues Rd. Value = strvalue.tostring rd.Data = reg.GetValue(strValue)
lstItems.Items.Add (RD) Next lstitems.endupdate () End Sub
To edit the values in the sample form or add new values, you need to run the following code:
Private Sub Addoredit (_ ByVal Rd as Regdata, _ ByVal Mode as Frmaddvalue.accessmode) Dim reg As RegistryKey = Registry.LocalMachine
Dim frm as New frmaddvalue ( Mode) frm. keyname = Rd. Value frm. KeyData = Rd. Data If frm. ShowDialog () = DialogResult.OK Then If frm. KeyName <> String.Empty Then reg = reg.OpenSubKey(conRegKey, True)
reg.SetValue(frm.KeyName, frm.KeyData)
listload () end If end IfEnd Sub
This code will open the registry key again, this time requesting permission to write the item value (this request is issued by the second parameter of OpenSubKey). The code then calls the SetValue method, passing the item name and item value in the dialog box form shown in Figure 1. To simplify your work, you can use the SetValue method to add new values or modify existing values. If the value of the item does not exist, the SetValue method adds an item value.
To delete an item value, the sample form invokes the following code:
Private Sub DeleteKey (ByVal Rd as Regdata) Dim strText As String Dim reg As RegistryKey = Registry.localmachine
if Lstitems.selectedindex =-1 Then Exit Sub end If ' deletes the selected item. StrText = String.Format (_ "Are you sure your want to delete" "{0}" "?", _ Rd. Value) If MessageBox.Show (StrText, _ "Delete Registry Value", _ Messageboxbuttons.yesno, _ messageboxicon.question) = Dialogresult.yes Then ' opens the entry to allow writing. reg = reg.OpenSubKey(conRegKey, True)
reg.DeleteValue(rd.Value)
' Reload the list box. listload () End IfEnd Sub
This code opens the item and requests a write operation on it, and then calls the DeleteValue method to delete the selected value.
With the information provided by the sample form and the documentation that came with the. NET framework, you can easily complete any tasks related to the registry without using the Windows API. This is a simple object model, but it provides functionality that is more powerful than the functionality previously owned by the Visual Basic 6.0 developers.
Tip: If you have the necessary permissions, you can also use the registry on the remote computer. Instead of simply using one of the Registry class properties, you can call the Registrykey.openremotebasekey method to retrieve a basic item on another computer to represent the Registry hive on your own computer.
Use a common dialog box
Windows provides a common set of dialog boxes that enable developers to easily request user information. You must have seen and used common dialog boxes for opening and saving files, colors, printers, and font settings. Visual Basic 6.0 developers have two choices when using these dialog boxes. They can:
- Using a Microsoft ActiveX® control, the control provides a simple object model that contains a common dialog box, but because the control has several different versions and the underlying DLL is different, the control has a serious deployment problem. (For many Visual Basic 6.0 developers, this problem is the most lethal DLL problem.) )
- Use the Windows API directly to send messages and provide callback functionality to manage each common dialog box.
None of the two solutions is perfect, and since the. NET framework has been updated, neither solution is currently required. When you view the System.Windows.Forms namespace, you will find ColorDialog, FileDialog, FontDialog, and PrintDialog classes. These classes are integrated into the framework (that is, neither API calls nor ActiveX controls are required), which makes it easy to incorporate these standard features into your application.
Each class provides a series of properties that you can use to set these properties before the dialog box is displayed by using the ShowDialog method of the class. This article will not discuss each class in detail, but use the FileDialog class in the sample project so that you can select the file. If you select the file version infobutton on the main form, you can use the Select afile button on the demo form to display file Open (Open File) dialog box, as shown in Figure 2.
Figure 2: Using the FileDialog class to display Windows common dialog boxes
Although the FileDialog class is not as flexible as using the Windows API directly, it provides a number of properties that you can use to control the actions of the dialog box. You can determine the source of the file, select one or more files, and retrieve the selected file name. Table 2 lists some of the properties and methods of the FileDialog class that might be used.
Table 2:filedialog Properties and methods of objects
Properties/Methods
DescriptionAddExtension indicates whether the dialog box automatically adds an extension to the file when the user omits the extension. Checkfileexists indicates whether the dialog box displays a warning message when the user-specified filename does not exist. Checkpathexists indicates whether the dialog box displays a warning message when the user-specified path does not exist. Defaultext The default file name extension. Dereferencelinks indicates whether the dialog box returns the location of the file referenced by the shortcut, or whether to return the location of the shortcut (. lnk). FileName The file name selected in the file dialog box. The file name of all selected files in the FileNames (read-only) dialog box. Filter the current file name filters the string to determine the options displayed in the dialog box, save as file type, or the Files of type box. The index of the filter currently selected in the FilterIndex file dialog box. The initial directory displayed by the InitialDirectory file dialog box. Restoredirectory indicates whether the dialog box restores the current directory before closing. SHOWHELP Indicates whether the Help button is displayed in the file dialog box. Title File dialog box. Validatenames indicates whether the dialog box accepts only valid file names. Reset (method) resets all properties to their default values. ShowDialog (method) Displays the file dialog box. If the user presses OK, it returns DialogResult.OK or returns DIALOGRESULT.CANCEL.
When you click Select afile (select files), the sample form Frmfileversioninfo invokes the following code:
Private Sub Btnselectfile_click (_ ByVal sender as System.Object, _ ByVal E As System.EventArgs) _ Handles btnselectfile.c Lick Dim ofd as OpenFileDialog = New OpenFileDialog () ofd. Filter = _ "executable Files (*.exe;*.dll;*.ocx) |" & _ "*.exe;*.dll;*.ocx|" & _ "Drivers (*.sys;*. DRV;*.FNT) | "& _ " *.sys;*.drv;*.fnt| "& _ " All Files (*.*) |*.* " ofd. FilterIndex = 1 ofd. ShowReadOnly = False ofd. Restoredirectory = True If ofd. ShowDialog () = DialogResult.OK Then If ofd. Filename.length > 0 Then ' displays file version information. Displayfileinfo (OFD. FileName) End If IfEnd Sub
tip: As with the Visual Basic 6.0 CommonDialog ActiveX control, you can set the Filter property of the FileDialog class to a string that contains a pair of vertical bar-delimited values. As shown below: "description| Filespec ".
In the example above, once you select a filename, the sample form displays information about the file in the form's ListView control. The next section discusses the FileVersionInfo class, which enables you to do this.
Retrieving file version information
Developers and compilers can embed version information into executable files, DLL files, and driver files. You may need to retrieve some or all of the version information as part of your application, which requires a large amount of API calls to perform this operation in Visual Basic 6.0. You need to invoke the Getversioninfosize, VerQueryValue, and GetFileVersionInfo Win32 API functions, and it's not easy to use any of these functions in Visual Basic.
This situation once again shows the power of the. NET framework: Using FileVersionInfo objects makes these tasks very simple. All you need to do is call the shared GetVersionInfo method of the FileVersionInfo object, pass a filename, and all the problems will be solved. The sample form uses the following code:
Dim Fvi as FileVersionInfo = _ Fileversioninfo.getversioninfo (strfile)
After you have done this, retrieving the properties of the FileVersionInfo object is a very simple matter. The sample form uses a short program shown below to add each property name and value to the form's ListView control:
Private Sub AddItem (_byval strproperty As String, _byval strvalue as String) with lvwInfo.Items.Add (strproperty)
. SubItems.Add (strvalue) End WithEnd Sub
What really works is the code, and the code simply calls AddItem repeatedly, and each property is invoked once:
AddItem ("Comments", fvi.comments) AddItem ("CompanyName", Fvi.companyname) AddItem ("Language", Fvi. Language) ' Here deleted some lines ... AddItem ("Product", Fvi. ProductName) AddItem ("Productprivatepart", _ Fvi. Productprivatepart.tostring ()) AddItem ("ProductVersion", Fvi. ProductVersion) AddItem ("Specialbuild", Fvi. Specialbuild)
The resulting form shown in Figure 3 shows all version information that can be used programmatically.
Figure 3: Retrieving file version information using the FileVersionInfo class
Retrieving environment information
The Win32 API provides a series of functions that allow you to determine the user's environment settings. GetSystemMetrics and SystemParametersInfo are two of these functions. You can continue to call these API functions from a. NET application, but you probably don't need to. The Environment class (located in the System namespace) and the SystemInformation class (located in the System.Windows.Forms namespace) provide much the same information as API functions. In this section, we will demonstrate the capabilities of these two classes through an example.
Warning: Don't waste time looking for ways to set user environment settings from these classes. All the information shown here is read-only. If you still want to modify the environment settings, you will need to look for additional methods.
Using the System.Environment class
The System.Environment class provides a number of different information that, if not available, requires multiple Windows API calls. Use System.Environment to retrieve:
- Information about available drives (GetLogicalDrives method)
- Number of milliseconds after Windows starts (TickCount property)
- General environment settings (by CurrentDirectory, MachineName, OSVersion, Systemdirectory, UserDomainName, Userinteractive, UserName, and WorkingSet Property provided)
- A list of specific folders (provided using the GetFolderPath method)
If you have used the Windows API, you will know that selection methods and properties will replace many API calls, including GetTickCount, GetLogicalDrives, GetSystemDirectory, GetComputerName, GetUserName and GetVersionEx and so on.
In the example form shown in Figure 4 (Click Environment Info on the main form), the result of the Execute GetLogicalDrives method is displayed in the list box near the top, including a list of all the specific folders (using GetFolderPath method Retrieval). In the list box at the bottom of the form, the results of many of the properties of the class are displayed.
Figure 4: A form showing the properties and methods used by the System.Environment class
Also, to test the TickCount property, click Test clickcountto display the results of the stopwatch class that you defined in the sample form, and use the following code:
Public Class stopwatch Private Mintstart as Integer public Sub Start () Mintstart = Environment.tickcount End Sub The Public Function Elapsed () as Integer return Environment.tickcount-mintstart the end Function is public Overrides Function ToString () as String return String.Format (_ "started: {0}, Elapsed: {1}", _ Mintstart, me.elapsed ) End FunctionEnd Class
The Fillproperties method shown here uses a copy of the previously displayed AddItem method to fill the property name and result into the ListView control, as follows:
private Sub fillproperties () AddItem ("CurrentDirectory", _
AddItem ("MachineName", environment.machinename)
AddItem ("Osversion.platform", _ Environment.OSVersion.Platform.
ToString) AddItem ("Osversion.version", _ Environment.OSVersion.Version.
ToString) AddItem ("Systemdirectory", _ Environment.systemdirectory)
AddItem (" UserDomainName ", environment.userdomainname)
AddItem (" Userinteractive ", _ Environm Ent. userinteractive) AddItem ("UserName", Environment.username) AddItem ("WorkingSet", Environment.workingset) End SUB
In addition to using the Environment class, Fillfolderlist actually contains some interesting code. The purpose of this process is to recycle all members of the SpecialFolder enumeration provided by the environment class. (This enumeration contains logical names for physical folders, such as Favorites and history.) This procedure adds the name of each enumeration value to the ListView control on the form, and adds the result of passing the enumeration value to the GetFolderPath method of the Environment object. The procedure shown below can do all of the work:
Private Sub fillfolderlist () Dim strName As String Dim Astrnames () As String Dim aintvalues As Array Dim I As Integer ' uses the name in the SpecialFolder enumeration ' to fill in the first column of the ListView control. Astrnames = System.Enum.GetNames (_ GetType (environment.specialfolder)) aintvalues = System.Enum.GetValues (_ GetType (Environment.SpecialFolder)) for i = 0 to astrnames.length-1 with LVWFOLDERS.ITEMS.ADD (Astrnames (i)) . SubItems.Add (_ Environment.getfolderpath (Aintvalues (i))) End with NextEnd Sub
The example does not hard-code the parameters sent to the environment object, but instead uses the shared GetNames and GetValues methods of the Enum class. By passing the result of the call to the Visual Basic. NET GetType function to GetNames (passing the specified enumeration type), you can retrieve the array that was filled in with the names of all the enumeration members. Repeating the procedure containing the GetValues method returns an Array object that contains all the enumeration values.
Astrnames = System.Enum.GetNames (_ GetType (environment.specialfolder)) Aintvalues = System.Enum.GetValues (_ GetType ( Environment.SpecialFolder))
After these two arrays are given, the remainder of the program is cycled in both arrays, the values in Astrnames are added to ListView, and then the GetFolderPath method of the Environment class is invoked to retrieve the appropriate path:
For i = 0 to astrnames.length-1 with lvwFolders.Items.Add (Astrnames (i)) . SubItems.Add (_ Environment.getfolderpath (Aintvalues (i))) End WithNext
The upper ListView control in Figure 4 contains the output of the code.
Tip:The Enum gives you some tips that are not available in Visual Basic 6.0, such as the GetNames and GetValues methods shown in the example. For more information about using the features of the Enum class, see the. NET Framework documentation.
Using the Windows.Forms.SystemInformation class
When you provide a well-designed user interface, you often need to determine the current Windows settings, such as the height and width of the icon, or the width of the scroll bar. In Visual Basic 6.0, you can use the GetSystemMetrics and SystemParametersInfo Windows API functions to determine many of these settings. In the. NET framework, you can use the SystemInformation class provided by the Windows.Forms namespace.
Although the code used by Frmsysteminformation in Figure 5 is not very interesting, it does show all the properties that the class provides. (Click systeminformation Info [System Information] on the main form to test this sample form.) The sample form operates on all the properties of the SystemInformation class, displaying the name and current value of each property in the form's ListView control.
Figure 5: Sample form showing all properties of the Windows.Forms.SystemInformation class
The sample form uses the AddItem method described earlier to simply loop and display output in all 60 properties of the SystemInformation class:
AddItem ("ArrangeDirection", _ Systeminformation.arrangedirection) AddItem ("Startingposition", _ systeminformation.arrangestartingposition) AddItem ("Bootmode", systeminformation.bootmode) ' et cetera ...
Summarize
- Although you can use platform invoke services (P/invoke) in Visual Basic. NET to handle unmanaged code and then call the Windows API directly, you should still look for alternatives when creating Visual Basic. NET Applications. However, you don't have to worry about p/invoke details, because the Declare statement will deal with these details for you.
- The. NET Framework does not encapsulate all the Windows API features, but actions you might want to use with API calls in Visual Basic 6.0 can also be implemented in the. NET Framework.
- The Registry and RegistryKey classes simplify the operation of the Windows registry, helping developers avoid a large number of API calls.
- The FileDialog, ColorDialog, FontDialog, and Printerdialog classes make it easy for you to use common dialog boxes in Windows. You do not need to call the Windows APIs directly, nor do you need to use the dreaded CommonDialog ActiveX control.
- You can use the FileVersionInfo class to retrieve all file version information built into executable files, driver files, and DLL files. This class can replace some of the complex Windows API code that is required in Visual Basic 6.0.
- The environment and SystemInformation classes allow you to easily retrieve system settings, and if they are not, you need to invoke many different API functions.
About the author
Ken Getz is a senior advisor to MCW Technologies, whose job involves programming, writing and training. He is proficient in tools and applications written in Microsoft Access, Visual Basic, and Office and BackOffice suites. He has also written many books with others, including: "Access Developer's Handbook", co-authored by Paul Litwin and Mike Gilbert, and the Ac from Paul Litwin and Mike Gilbert Cess Developer's Handbooks, "Access Gunderloy 2002 's Developer", co-authored by Paul Litwin and Mike Handbooks, and Mike Gilbert, co-author of " Visual Basic Language Developer ' s Handbook, and the VBA Sybex ' Developer, co-authored by Mike Gilbert (Handbook). He also participated in the preparation of the AppDev training materials and engaged in the teaching work in this field. Ken has often spoken at the technical meeting, and since 1994 he has delivered speeches at every Microsoft tech*ed meeting. Ken is a technical editor for Access/vb/sql Advisor and an electronic writer for the Microsoft Office Solutions magazine under informant communication Group.
About Informant Communications Group
Informant Communications Group, Inc. (www.informant.com) is a multimedia company focused on the information technology industry. Founded in 1990, ICG is dedicated to the fields of publications, conferences, catalogues, and WEB sites related to software development. With offices in the United States and the UK, ICG has become a prestigious media and marketing content integrator and has been meeting the growing needs of IT personnel with high quality technical information.
©2002 informant Communications Group and Microsoft Corporation are all copyrighted.
Technical Editor: KnG Consulting