The information in this article applies to:
- Standard and Professional Editions of Microsoft Visual Basic for
Windows, versions 2.0 and 3.0
- Microsoft Visual Basic programming system for Windows, version 1.0
- Microsoft Windows versions 3.0 and 3.1
SUMMARY
The example program included below demonstrates how to extract an
icon from a Windows program, whether it is currently running or not.
There are two different techniques depending on whether the program is
run in Windows version 3.0 or 3.1. The API function ExtractIcon,
introduced in Windows version 3.1, simplifies the process of extracting
the icon. In Windows version 3.0, a different approach is required.
Both methods are illustrated below.
MORE INFORMATION
The example program shown below displays the icon of an application in a
picture box. The example demonstrates the handling of the hDC property of
the picture box control, specifically the relationship between the Refresh
method, the Image property, and the AutoRedraw property. The code in the
Command3_Click event demonstrates how to transfer the captured icon image
to the Picture property of a picture box (Picture2).
Step-by-Step Example
- Start Visual Basic, or from the File menu, choose New Project (ALT,
F, N) if Visual Basic is already running. Form1 is created by default.
- Create the following controls with the default property settings:
- Picture1
- Picture2
- Command1
- Command2
- Command3
- Place the code below into the general Declarations section of Form1
taking care to enter each Declare statement on one, single line:
' API declarations used in Windows version 3.0 method.
Declare Function GetActiveWindow Lib "User" () As Integer
Declare Function PostMessage Lib "User" (ByVal hWnd As Integer,
ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As Any)
As Integer
Declare Function FindWindow Lib "User" (ByVal lpClassName As Any,
ByVal lpWindowName As Any) As Integer
Declare Function LoadLibrary Lib "Kernel" (ByVal lpLibFileName
As String) As Integer
Declare Function GetWindowWord Lib "User" (ByVal hWnd As Integer,
ByVal nIndex As Integer) As Integer
Declare Function LoadIcon Lib "User" (ByVal hInstance As Integer,
ByVal lpIconName As Any) As Integer
' API declarations used in Windows version 3.1 method.
Declare Function GetModuleHandle Lib "Kernel" (ByVal lpModuleName
As String) As Integer
Declare Function GetClassWord Lib "User" (ByVal hWnd As Integer,
ByVal nIndex As Integer) As Integer
Declare Function ExtractIcon Lib "SHELL" (ByVal hInst As Integer,
ByVal lpszexename As String, ByVal hIcon As Integer) As Integer
' API declaration used by both Windows version 3.0 and 3.1 methods.
Declare Function DrawIcon Lib "User" (ByVal hDC As Integer, ByVal x
As Integer, ByVal Y As Integer, ByVal hIcon As Integer) As Integer
' Window field offsets for GetClassWord() and GetWindowWord().
Const GWW_HINSTANCE = (-6)
Const GCW_HMODULE = (-16)
' Constants for SendMessage and PostMessage.
Const WM_CLOSE = &H10
' If using Visual Basic version 1.0, remove the single quotation mark
' from the following line of code:
' Const NULL = 0&
- Place the following code in the Form_Load event of Form1:
Sub Form_Load ()
Command1.Caption = " 3.0 method "
Command2.Caption = " 3.1 method "
Command3.Caption = " Transfer "
Form1.Caption = " Example of Extracting an Icon"
Form1.Width = Screen.Width * 2 / 3
Form1.Height = Screen.Height / 2
' Center the form on the screen.
' Enter the following two lines as one, single line:
Form1.Move (Screen.Width - Form1.Width) / 2,
(Screen.Height - Form1.Height) / 2
' Size and position the controls dynamically at run time.
' Enter the following two lines as one, single line:
Picture1.Move 0, 0, Form1.Width / 2,
Form1.Height - Command1.Height * 4
' Enter the following two lines as one, single line:
Picture2.Move Form1.Width / 2, 0, Form1.Width,
Form1.Height - Command2.Height * 4
' Enter the following two lines as one, single line:
Command1.Move (Form1.Width / 2 - Command1.Width) / 2,
Form1.Height - Command1.Height * 4
' Enter the following two lines as one, single line:
Command2.Move (Form1.Width / 2 - Command1.Width) / 2,
Form1.Height - Command1.Height * 3
' Enter the following two lines as one, single line:
Command3.Move (Form1.Width * 3 / 2 - Command2.Width) / 2,
Form1.Height - Command2.Height * 4
End Sub
- Place the following code in the Command1_Click event. Configure the code
to match your situation by removing the comment apostrophe from one of
the three methods and adding comment apostrophes to the other two -- to
effectively enable one of the methods and disable the other two.
Sub Command1_Click ()
Dim hInstance As Integer, handle As Integer, hIcon As Integer
Picture1.Picture = LoadPicture("") ' clear any previous image
' Three alternative ways to obtain the handle of the top-level window
' of the program whose icon you want to extract:
' Method 1: If the program is currently running and you don't know
' the class name.
' AppActivate ("Program Manager") ' Set focus to application.
' handle = GetActiveWindow() ' Get handle to window.
' Command1.SetFocus ' Return focus to button.
' Method 2: If program is running and you know the class name.
' Handle = FindWindow("Progman", "Program Manager")
' Method 3: If program is not running, use path and filename.
' Not_Running_Way "sysedit.exe" ' Call sub at general level.
' Exit Sub ' Bypass remaining code in this Sub.
' Now you have the handle -- use it to obtain the instance handle.
hInstance = GetWindowWord(handle, GWW_HINSTANCE)
Picture2.Print "3.O method "
Picture2.Print "handle="; Hex$(handle)
Picture2.Print "hInstance= "; Hex$(hInstance) ' Sanity check.
' Iterate through icon resource identifier values
' until you obtain a valid handle to an icon.
Do
hIcon = LoadIcon(hInstance, n&)
n& = n& + 1
Loop Until hIcon <> 0
Picture2.Print "hIcon= "; Hex$(hIcon)
Picture1.AutoRedraw = -1 ' Make hDC point to persistent bitmap.
r = DrawIcon(Picture1.hDC, 19, 19, hIcon) 'Draw the icon.
Picture1.Refresh ' Refresh from persistent bitmap to Picture.
End Sub
- Place the following code in the Command2_Click event. Note that the
first two methods commented out are provided for information and
contrast to the preferred method, method 3.
Sub Command2_Click ()
Dim myhInst As Integer, hIcon As Integer
Picture1.Picture = LoadPicture("") ' Clear the previous image.
' Listed below are three alternative methods that can be used to
' obtain the hInst of your program's module handle.
' Method 1: Use only with .EXE version of your program.
' myhInst = GetModuleHandle("Project1.exe")
' Method 2: Use only with your program running in the environment.
' myhInst = GetModuleHandle("VB.EXE")
' Method 3: The slick way that works in either case.
myhInst = GetClassWord(hWnd, GCW_HMODULE)
' The path and filename of program to extract icon from.
lpzxExeName$ = "moricons.dll" ' Can also use an .EXE file here.
' Get handle to icon.
hIcon = ExtractIcon(myhInst, lpzxExeName$, 0)
Picture2.Print "3.1 method "
Picture2.Print "myhInst= "; Hex$(myhInst) ' Sanity check.
Picture2.Print "hIcon= "; Hex$(hIcon) ' Sanity check.
Picture1.AutoRedraw = -1 ' Make the picture's hDC point to the
' persistent bitmap.
r% = DrawIcon(Picture1.hDC, 19, 19, hIcon)
Picture1.Refresh ' Cause Windows to paint from the persistent bitmap
' to show the icon.
End Sub
- Place the following code in the form's general Declarations section:
Sub Not_Running_Way (appname As String)
Dim hInstance As Integer, handle As Integer, hIcon As Integer
Dim hWndShelledWindow As Integer
Picture1.Picture = LoadPicture("") ' Clear any previous image.
hInstance = Shell(appname, 2)
Picture2.Print "3.0 method-application not running"
Picture2.Print "hInstance= "; Hex$(hInstance) ' Check return.
r = DoEvents() ' Allow time for shell to complete.
' The following technique is from another article that explains
' how to determine when a shelled process has terminated. It is
' used here to obtain the correct handle to the window of the
' application whose icon is being extracted. The handle is needed
' to close the application after the extraction is complete.
TimeOutPeriod = 5
fTimeOut = 0 ' Set to false.
s! = Timer
Do
r = DoEvents()
hWndShelledWindow = GetActiveWindow()
' Set timeout flag if time has expired.
If Timer - s! > TimeOutPeriod Then fTimeOut = True
Loop While hWndShelledWindow = Form1.hWnd And Not fTimeOut
' If a timeout occurred, display a timeout message and terminate.
If fTimeOut Then
MsgBox "Timeout waiting for shelled application", 16
Exit Sub
End If
' Iterate through icon resource identifier values
' until you obtain a valid handle to an icon.
Do
hIcon = LoadIcon(hInstance, n&)
n& = n& + 1
Loop Until hIcon <> 0
Picture2.Print "HICON= "; Hex$(hIcon)
Picture1.AutoRedraw = -1 ' Make hDC point to persistent bitmap.
r = DrawIcon(Picture1.hDC, 19, 19, hIcon)
Picture2.Print "return from DrawIcon="; r
Picture1.Refresh ' Refresh from persistent bitmap to picture.
' Now post a message to the window to close the application.
r = PostMessage(hWndShelledWindow, WM_CLOSE, NULL, NULL)
Picture2.Print "return from PostMessage="; r
End Sub
- Place the following code in the Command3_Click event:
Sub Command3_Click ()
' This code transfers the extracted icon's image to Picture2's
' Picture property and demonstrates that DrawIcon assigns the image
' to the hDC of Picture1, which points to the persistent bitmap
' (Image property), not to the Picture property.
Picture2.Picture = LoadPicture("") ' Clear old icon.
Picture2.currenty = 0 ' Reset coordinates for printing
' return values.
Picture2.currentx = 0
Picture2.Picture = Picture1.image ' Transfer persistent bitmap
image
' to the Picture property.
End Sub
Press ALT F, V to save the project. Then press F5 to run the program.
Click "3.0 method" to run the code that works in Windows version 3.0.
Click "3.1 method" to run the code that works in Windows version 3.1.
Click Command3 to copy the icon in Picture1 to Picture2 so that the
icon can be accessed as Picture2.Picture.
Both methods extract the first icon in the file. This can be
modified to find the second or succeeding icons by:
- Storing the value of n& in the Do Loop from the first extraction
and plugging that in as the starting point of the next search
in Windows version 3.0.
- Or -
- Setting the third parameter of the ExtractIcon function to a
specific index number in Windows version 3.1.
You could do this in a loop to find and examine each icon in the file.
The Windows version 3.0 method may take slightly longer to iterate and
find the icon resource ID number.
REFERENCES
"Microsoft Windows Software Development Kit Volume 2"
"Microsoft Press Programmer's Reference Library Volume 2"
|