Using a Resource File
Although C and C++ programmers are long accustomed to using resource files, Visual Basic programmers are not. And while their primary use in the Visual Basic environment is to support localized applications (by storing an application's strings in a variety of supported languages in the resource file), they can also be used to store cursors, icons, bitmaps, and custom resources.
Unless you prefer to use an external resource editor like ResEdit, you have to add the VB 6 Resource Editor add-in to the Visual Basic environment in order to use resources. You do this by opening the Add-In Manager dialog box (selecting Add-Ins -> Add-In Manager from Visual Basic's main menu), selecting the VB 6 Resource Editor in the Available Add-ins list box, and making sure that the Loaded/Unloaded box is checked. You can then add a resource file to your project by right-clicking in the Project Explorer, selecting Add -> Resource File from the pop-up menu, and entering the name of the resource file you'd like to create in the Open a Resource File dialog box. (The dialog box is a bit confusing, since it either creates a new resource file that it adds to your project or opens an existing resource file that it adds to your project.)
Once you've added the resource file, you can add icons to it by clicking on the Add Icon button on the Resource Editor's toolbar. As you add each icon, the editor automatically assigns it a resource identifier. You can change this, however, by double-clicking on the resource identifier to open the Edit Icon Properties dialog box, as shown in Figure 4.
Figure 4. The Edit Icon Properties dialog box
It's generally a good idea to add a set of constants that indicate the icon identifiers in your project. Even if you don't use the constants (as we haven't in our sample phases of the moon application), they provide documentation that reminds you what the icons' identifiers are. For example, in our sample application we've defined the following enumeration that indicates the icons' identifiers:
Private Enum Phases ' IDs in Resource File NEWMOON = 101 FIRSTMOON = 102 FULLMOON = 103 LASTMOON = 104 End Enum
Instead of adding the icons to an .frx file, as it did when we assigned an icon to a form's
Icon property or when we stored icons in an
ImageList control, Visual Basic creates a compiled resource (.res) file. The effect is the same as if the icons were stored in an .frx file: Visual Basic now retrieves the icons from the resource file and no longer needs the icon files to be physically present. When you compile your project, the resource file is included in the executable. It can be examined using any standard resource editor.
To retrieve an icon from the resource file, you use the
LoadResPicture function, which takes as arguments the icon's identifier and the
vbResIcon constant, which tells the function that you want to retrieve an icon rather than a bitmap (indicated by the
vbResBitmap constant) or a cursor (indicated by the
vbResCursor constant). The following code from our phases of the moon application is very similar to the previous code, except that it uses a resource file instead of the
Private Sub ShowMoonIcon(datPhase As Date) Dim intMonth As Integer, intCtr As Integer, intPhase As Phases Dim fIcon As Boolean Dim datArray As Variant, datNextArray As Variant intMonth = Month(datPhase) - 1 ' Iterate array datArray = aDates(intMonth) datNextArray = aDates(intMonth + 1) For intCtr = 0 To 3 If datPhase > datArray(intCtr) Then If intCtr <= 2 Then If datPhase < datArray(intCtr + 1) Then intPhase = intCtr fIcon = True Exit For End If Else If datPhase < datNextArray(0) Then intPhase = intCtr fIcon = True End If End If End If Next ' Iterate next array if not found If Not fIcon Then For intCtr = 0 To 2 If datPhase > datNextArray(intCtr) Then If datPhase < datNextArray(intCtr + 1) Then intPhase = intCtr fIcon = True Exit For End If End If Next End If Me.Icon = LoadResPicture(intPhase + 101, vbResIcon) End Sub
Extracting Windows Icons
There are times when you may not want to create your own icon. Instead you may simply want to use an existing icon that expresses the general function of your application. Windows itself provides hundreds of icons for this purpose, as suggested in Table 1, which lists some major files and the number of icons they contain. Stored inside of dynamic link libraries and executables, these icons are there for the taking as long as you know how to find them and extract them.
Table 1. Some system files containing icons
|Filename||Number of Icons|
To discover what icons are available, a good icon creation and extraction program is invaluable. For instance, Figure 5 shows ArtIcons Pro, a utility from Aha-Soft, displaying the first 35 of the 238 icons available in Shell32.dll. Notice that the status bar numbers each icon based on its ordinal position in the DLL. This is important, since we'll need to know the position of the icon we'd like to extract.
Figure 5. The icons in Shell32.dll
Extracting the icon from a file is easy enough; just call the Win32 ExtractIcon function, which has the syntax:
Private Declare Function ExtractIcon Lib "shell32.dll" _ Alias "ExtractIconA" _ (ByVal hInst As Long, _ ByVal lpszExeFileName As String, _ ByVal nIconIndex As Long) As Long
For simplicity, we're using
hInst is the instance handle of the application making the function call (for our application, its value is simply
lpszExeFileName is the name of the executable from which we wish to extract the icon, and
nIconIndex is the zero-based index of the icon to extract. If
nIconIndex is -1, the function returns the total number of icons in
lpszExeFileName. Otherwise, the function returns a handle to the extracted icon, a 1 (if
lpszExeFileName is not a DLL, executable, or icon file), or a NULL (if no icons were found in
These parameters are all fairly straightforward, except for
lpszExeFileName. Although you should know the name of the file from which you want to extract the icon, you can't necessarily be confident of its location on the user's system. Most of the folders with which you're likely to work when extracting icons, however, are system folders, so you can call the
SHGetFolderPath method and pass it a constant representing the folder whose path and name you'd like to retrieve. Once it returns the complete path, you don't have to deal with trimming it, possibly adding a path separator character, and appending our filename; you can simply call the Win32
PathAppend method, which handles all of the details for us.
Whenever you call
ExtractIcon to extract an icon, you must eventually destroy it by calling the
DestroyIcon function once you're finished with it. Its syntax is:
Private Declare Function DestroyIcon Lib "user32" _ (ByVal hIcon As Long) As Long
hIcon is the icon handle returned by an icon extraction or retrieval function.