Microsoft KB Archive/142815

= How to Extract a Windows Program Icon--Running or Not =

Article ID: 142815

Article Last Modified on 1/8/2003

-

APPLIES TO


 * Microsoft Visual Basic 4.0 Professional Edition
 * Microsoft Visual Basic 4.0 16-bit Enterprise Edition

-



This article was previously published under Q142815



SUMMARY
The example program included below demonstrates how to extract an icon from a Microsoft Windows program, whether it is currently running or not. There are two different techniques depending on whether the program is run in Microsoft Windows version 3.0 or 3.1. The ExtractIcon API function, 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 on the File menu, click 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</li></ul> </li>  Add the code below to 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. Private Declare Function GetActiveWindow Lib "User" As Integer Private Declare Function PostMessage Lib "User" _ (ByVal hWnd As Integer, ByVal wMsg As Integer, _      ByVal wParam As Integer, ByVal lParam As Any) As Integer Private Declare Function FindWindow Lib "User" _ (ByVal lpClassName As Any, ByVal lpWindowName As Any) As Integer Private Declare Function LoadLibrary Lib "Kernel" _ (ByVal lpLibFileName As String) As Integer Private Declare Function GetWindowWord Lib "User" _ (ByVal hWnd As Integer, ByVal nIndex As Integer) As Integer Private Declare Function LoadIcon Lib "User" _ (ByVal hInstance As Integer, ByVal lpIconName As Any) As Integer

' API declarations used in Windows version 3.1 method. Private Declare Function GetModuleHandle Lib "Kernel" _ (ByVal lpModuleName As String) As Integer Private Declare Function GetClassWord Lib "User" _ (ByVal hWnd As Integer, ByVal nIndex As Integer) As Integer Private 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. Private 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&

</li>  Place the following code in the Form_Load event of Form1: Private 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. Form1.Move (Screen.Width - Form1.Width) / 2, _ (Screen.Height - Form1.Height) / 2 ' Size and position the controls dynamically at run time. Picture1.Move 0, 0, Form1.Width / 2, _ Form1.Height - Command1.Height * 4 Picture2.Move Form1.Width / 2, 0, Form1.Width, _ Form1.Height - Command2.Height * 4 Command1.Move (Form1.Width / 2 - Command1.Width) / 2, _ Form1.Height - Command1.Height * 4 Command2.Move (Form1.Width / 2 - Command1.Width) / 2, _ Form1.Height - Command1.Height * 3 Command3.Move (Form1.Width * 3 / 2 - Command2.Width) / 2, _ Form1.Height - Command2.Height * 4 End Sub

</li>  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. Private 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 do not 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

</li>  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. Private 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

</li>  Place the following code in the form's general Declarations section: Private 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

</li>  Place the following code in the Command3_Click event: Private 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

</li> 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:

<ul> 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-</li> Setting the third parameter of the ExtractIcon function to a specific index number in Windows version 3.1.</li></ul>

You could perform this functionality 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.</li></ol>

<div class="references_section">