Microsoft KB Archive/88944

= VB3 How To Extract a Windows Program Icon--Running or Not =

Article ID: 88944

Article Last Modified on 12/12/2003

-

APPLIES TO


 * Microsoft Visual Basic 2.0 Standard Edition
 * Microsoft Visual Basic 3.0 Professional Edition
 * Microsoft Visual Basic 2.0 Professional Edition
 * Microsoft Visual Basic 3.0 Professional Edition
 * Microsoft Visual Basic 1.0 Standard Edition
 * Microsoft Windows 3.0 Standard Edition
 * Microsoft Windows 3.1 Standard Edition

-



This article was previously published under Q88944



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</li></ul> </li>  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 &quot;User&quot; As Integer Declare Function PostMessage Lib &quot;User&quot; (ByVal hWnd As Integer,     ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As Any) As Integer Declare Function FindWindow Lib &quot;User&quot; (ByVal lpClassName As Any,     ByVal lpWindowName As Any) As Integer Declare Function LoadLibrary Lib &quot;Kernel&quot; (ByVal lpLibFileName     As String) As Integer Declare Function GetWindowWord Lib &quot;User&quot; (ByVal hWnd As Integer,     ByVal nIndex As Integer) As Integer Declare Function LoadIcon Lib &quot;User&quot; (ByVal hInstance As Integer,     ByVal lpIconName As Any) As Integer

' API declarations used in Windows version 3.1 method. Declare Function GetModuleHandle Lib &quot;Kernel&quot; (ByVal lpModuleName     As String) As Integer Declare Function GetClassWord Lib &quot;User&quot; (ByVal hWnd As Integer,     ByVal nIndex As Integer) As Integer Declare Function ExtractIcon Lib &quot;SHELL&quot; (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 &quot;User&quot; (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: Sub Form_Load Command1.Caption = &quot; 3.0 method &quot; Command2.Caption = &quot; 3.1 method &quot; Command3.Caption = &quot; Transfer &quot; Form1.Caption = &quot; Example of Extracting an Icon&quot; 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

</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. Sub Command1_Click Dim hInstance As Integer, handle As Integer, hIcon As Integer Picture1.Picture = LoadPicture(&quot;&quot;) ' 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 (&quot;Program Manager&quot;) ' 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(&quot;Progman&quot;, &quot;Program Manager&quot;)

' Method 3: If program is not running, use path and filename. ' Not_Running_Way &quot;sysedit.exe&quot; ' 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 &quot;3.O method &quot; Picture2.Print &quot;handle=&quot;; Hex$(handle) Picture2.Print &quot;hInstance= &quot;; 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&amp; = n& + 1 Loop Until hIcon <> 0 Picture2.Print &quot;hIcon= &quot;; 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. Sub Command2_Click Dim myhInst As Integer, hIcon As Integer Picture1.Picture = LoadPicture(&quot;&quot;) ' 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(&quot;Project1.exe&quot;)

' Method 2: Use only with your program running in the environment. ' myhInst = GetModuleHandle(&quot;VB.EXE&quot;)

' 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$ = &quot;moricons.dll&quot; ' Can also use an .EXE file here.

' Get handle to icon. hIcon = ExtractIcon(myhInst, lpzxExeName$, 0) Picture2.Print &quot;3.1 method &quot; Picture2.Print &quot;myhInst= &quot;; Hex$(myhInst) ' Sanity check. Picture2.Print &quot;hIcon= &quot;; 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: Sub Not_Running_Way (appname As String) Dim hInstance As Integer, handle As Integer, hIcon As Integer Dim hWndShelledWindow As Integer Picture1.Picture = LoadPicture(&quot;&quot;) ' Clear any previous image. hInstance = Shell(appname, 2) Picture2.Print &quot;3.0 method-application not running&quot; Picture2.Print &quot;hInstance= &quot;; 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 &quot;Timeout waiting for shelled application&quot;, 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&amp;) n& = n& + 1 Loop Until hIcon <> 0

Picture2.Print &quot;HICON= &quot;; Hex$(hIcon) Picture1.AutoRedraw = -1 ' Make hDC point to persistent bitmap. r = DrawIcon(Picture1.hDC, 19, 19, hIcon) Picture2.Print &quot;return from DrawIcon=&quot;; 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 &quot;return from PostMessage=&quot;; r  End Sub

</li>  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(&quot;&quot;) ' 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 &quot;3.0 method&quot; to run the code that works in Windows version 3.0. Click &quot;3.1 method&quot; 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 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.</li></ol>

<div class="references_section">