oreilly.comSafari Books Online.Conferences.


AddThis Social Bookmark Button

Working with Icons in Visual Basic
Pages: 1, 2, 3, 4

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
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 ImageList control:

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
            If datPhase < datNextArray(0) Then
               intPhase = intCtr
               fIcon = True
            End If
         End If
      End If

   ' 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
   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
compstui.dll 99
comres.dll 38
cryptui.dll 20
csc.dll 22
dsuiext.dll 35
explorer.exe 18
iexplore.exe 23
inetcpl.cpl 34
inetcpl.dll 14
mmcndmgr.dll 129
mmsys.cpl 40
moricons.dll 140
netshell.dll 157
ntbackup.exe 26
pfmgr.dll 38
progman.exe 48
setupapi.dll 37
shell32.dll 238
stobject.dll 31
wiashext.dll 23
wmploc.dll 60
xpsp2res.dll 19

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
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 ExtractIcon here. You may prefer, though, to use ExtractIconEx, which lets you retrieve an array of handles to large and small icons. This allows you to assign a new icon in the most appropriate format, rather than allowing Windows to resize an icon in whatever format ExtractIcon retrieves.

where hInst is the instance handle of the application making the function call (for our application, its value is simply App.hInstance), 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 lpszExeFileName).

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

where hIcon is the icon handle returned by an icon extraction or retrieval function.

Pages: 1, 2, 3, 4

Next Pagearrow