|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Visual Basic Win32 Shell Routines Undocumented Windows: Change Icon Dialog The Change Icon Dialog |
||
Posted: | Wednesday August 6, 1997 | |
Updated: | Monday December 26, 2011 | |
Applies to: | VB4-32, VB5, VB6 | |
Developed with: | VB4-32, Windows 95 | |
OS restrictions: | None | |
Author: | Brad Martinez | |
Related: |
SHChangeNotifyRegister: Receive Shell Change Notifications Undocumented Windows: Overview Undocumented Windows: Shell Dialogs Undocumented Windows: Format Disk Dialog Undocumented Windows: Path Functions |
|
Prerequisites |
None. |
|
Third
in the undocumented Windows series demonstrates our SHChangeIconDialog API. Known in Shell32 as both _PickIcon and ordinal #62, it's another
totally undocumented call with no mention of it or related functions on the MSDN CDs.
Still worth repeating: as an undocumented API, it is not supported in any way, shape or form by Microsoft. And once again, the demo contains routines designed to check for NT (thereby requiring different string handling), and to provide the demo interface with drive, file and directory lists. The illustration below shows the demo form as it appears layout mode, where I've substituted control names for the control captions. Not indicated are five things: The Drive, File and Directory list boxes have the default control names (Drive1, File1 and Dir1). The two picture boxes are named picSmallIcon and picLargeIcon. If you can understand the code, you can figure which is which. The AutoRedraw and AutoSize properties of both are set to False. Finally, again the arrangement makes no difference, and the control and form names indicated match the code below.
|
BAS Module Code |
Once the form has been designed and saved, paste the following into the general declarations area of a file you name UndocSHChangeIcons.bas: |
|
Option Explicit '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Copyright ©1996-2011 VBnet/Randy Birch, All Rights Reserved. ' Some pages may also contain other copyrights by the author. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Distribution: You can freely use this code in your own ' applications, but you may not reproduce ' or publish this code on any web site, ' online service, or distribute as source ' on any media without express permission. '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' '------------------------------------------------------ 'Set to True if the current OS is WinNT. Public bIsWinNT As Boolean Public Declare Function GetVersionEx Lib "kernel32" _ Alias "GetVersionExA" _ (lpVersionInformation As OSVERSIONINFO) As Long Public Type OSVERSIONINFO dwOSVersionInfoSize As Long dwMajorVersion As Long dwMinorVersion As Long dwBuildNumber As Long dwPlatformId As Long szCSDVersion As String * 128 End Type Public Const VER_PLATFORM_WIN32s = 0 Public Const VER_PLATFORM_WIN32_WINDOWS = 1 Public Const VER_PLATFORM_WIN32_NT = 2 Public Declare Function IsTextUnicode Lib "advapi32" _ (lpBuffer As Any, _ ByVal cb As Long, _ lpi As Long) As Long Public Const IS_TEXT_UNICODE_ASCII16 = &H1 Public Const IS_TEXT_UNICODE_REVERSE_ASCII16 = &H10 Public Const IS_TEXT_UNICODE_STATISTICS = &H2 Public Const IS_TEXT_UNICODE_REVERSE_STATISTICS = &H20 Public Const IS_TEXT_UNICODE_CONTROLS = &H4 Public Const IS_TEXT_UNICODE_REVERSE_CONTROLS = &H40 Public Const IS_TEXT_UNICODE_SIGNATURE = &H8 Public Const IS_TEXT_UNICODE_REVERSE_SIGNATURE = &H80 Public Const IS_TEXT_UNICODE_ILLEGAL_CHARS = &H100 Public Const IS_TEXT_UNICODE_ODD_LENGTH = &H200 Public Const IS_TEXT_UNICODE_DBCS_LEADBYTE = &H400 Public Const IS_TEXT_UNICODE_NULL_BYTES = &H1000 Public Const IS_TEXT_UNICODE_UNICODE_MASK = &HF Public Const IS_TEXT_UNICODE_REVERSE_MASK = &HF0 Public Const IS_TEXT_UNICODE_NOT_UNICODE_MASK = &HF00 Public Const IS_TEXT_UNICODE_NOT_ASCII_MASK = &HF000 '------------------------------------------------------ 'The "Change Icon" dialog. '------------------------------------------------------ Public Declare Function SHChangeIconDialog Lib "shell32" _ Alias "#62" _ (ByVal hOwner As Long, _ ByVal szFilename As String, _ ByVal Reserved As Long, _ lpIconIndex As Long) As Long 'hOwner = Dialog owner, specify 0 for desktop '(will be top-level) 'szFilename = The initially displayed filename, filled ' on selection. Should be allocated to ' MAX_PATH (260) in order to receive the ' selected filename's path. 'Reserved = ? 'lpIconIndex = Pointer to the initially displayed filename's ' icon index, and is filled on icon selection. 'Returns non-zero on select, zero if cancelled. '------------------------------------------------------ 'A utilized undocumented Path function : '------------------------------------------------------ 'Inserts a backslash before the first null char in szPath. 'szPath is unchanged if it already contains a backslash 'before the first null char or contains no null char at all. 'Rtn pointer to? 'Does not check szPath for validity. '(the name almost fits...) Public Declare Function SHAddBackslash Lib "shell32" _ Alias "#32" _ (ByVal szPath As String) As Long '------------------------------- 'A few slightly more familiar APIs required... '------------------------------- 'Maximum long filename path-length Public Const MAX_PATH As Long = 260 Public Declare Function GetWindowsDirectory Lib "kernel32" _ Alias "GetWindowsDirectoryA" _ (ByVal lpBuffer As String, _ ByVal nSize As Long) As Long Public Declare Function ExtractIconEx Lib "shell32" _ Alias "ExtractIconExA" _ (ByVal lpszFile As String, _ ByVal nIconIndex As Long, _ phiconLarge As Long, _ phiconSmall As Long, _ ByVal nIcons As Long) As Long Public Declare Function DrawIconEx Lib "user32" _ (ByVal hDC As Long, _ ByVal xLeft As Long, _ ByVal yTop As Long, _ ByVal hIcon As Long, _ ByVal cxWidth As Long, _ ByVal cyWidth As Long, _ ByVal istepIfAniCur As Long, _ ByVal hbrFlickerFreeDraw As Long, _ ByVal diFlags As Long) As Boolean Public Declare Function DestroyIcon Lib "user32" _ (ByVal hIcon As Long) As Long 'Required DrawIconEx() diFlags values: Public Const DI_MASK = &H1 Public Const DI_IMAGE = &H2 Public Const DI_NORMAL = &H3 Public Const DI_COMPAT = &H4 Public Const DI_DEFAULTSIZE = &H8 'Handles overlapped source and destination blocks Public Declare Sub CopyMemory Lib "kernel32" _ Alias "RtlMoveMemory" _ (pDest As Any, _ pSource As Any, _ ByVal ByteLen As Long) Public Function MakeMaxPath(ByVal sPath As String) As String 'Terminates sPath w/ null chars making 'the return string MAX_PATH chars long. MakeMaxPath = sPath & String$(MAX_PATH - Len(sPath), 0) End Function Public Function IsUnicodeStr(sBuffer As String) As Boolean 'Returns True if sBuffer evaluates to a Unicode string Dim dwRtnFlags As Long dwRtnFlags = IS_TEXT_UNICODE_UNICODE_MASK IsUnicodeStr = IsTextUnicode(ByVal sBuffer, Len(sBuffer), dwRtnFlags) End Function Public Function GetStrFromBuffer(szStr As String) As String 'Returns string before first null char encountered (if any) 'from either an ANSII or Unicode string buffer. If IsUnicodeStr(szStr) Then szStr = StrConv(szStr, vbFromUnicode) If InStr(szStr, vbNullChar) Then GetStrFromBuffer = Left$(szStr, InStr(szStr, vbNullChar) - 1) Else GetStrFromBuffer = szStr End If End Function Public Function CheckString(msg As String) As String If bIsWinNT Then CheckString = StrConv(msg, vbUnicode) Else CheckString = msg End If End Function Public Function IsWinNT() As Boolean 'Returns True if the current operating system is WinNT Dim osvi As OSVERSIONINFO osvi.dwOSVersionInfoSize = Len(osvi) GetVersionEx osvi IsWinNT = (osvi.dwPlatformId = VER_PLATFORM_WIN32_NT) End Function Public Function NormalizePath(sPath As String) As String 'check the string type (ANSI or Unicode), 'converting as required. 'Check with If .. Then for a slash; if it's 'needed, add a trailing null string after the 'Checked string, as SHAddBackslash inserts a 'backslash before the first null char in szPath. sPath = CheckString(sPath) If Right$(sPath, 1) <> "\" Then 'do what is says sPath = sPath & vbNullChar SHAddBackslash sPath End If 'and return the string NormalizePath = sPath End Function |
Form Code |
To the project form illustrated above add the following code: |
|
Option Explicit Private Sub cmdEnd_Click() Unload Me End Sub Private Sub Dir1_Change() Dir1.Path = Drive1.Drive File1 = Dir1.Path txtIconPath = Dir1.Path End Sub Private Sub Drive1_Change() Dir1.Path = Drive1.Drive End Sub Private Sub File1_Click() txtIconPath = NormalizePath(File1.Path) & LCase$(File1) End Sub Private Sub File1_DblClick() DoIconDialog End Sub Private Sub Form_Load() Dim r As Long Dim sDirBuff As String 'We'll need this flag to determine if 'strings should be converted to Unicode bIsWinNT = IsWinNT Move (Screen.Width - Width) * 0.5, (Screen.Height - Height) * 0.5 'Setup the rest of the controls txtIconIdx = 0 sDirBuff = Space$(MAX_PATH) r = GetWindowsDirectory(sDirBuff, MAX_PATH) If r Then Drive1.Drive = LCase$(Left$(sDirBuff, 3)) 'ie "c:\" Dir1.Path = LCase$(GetStrFromBuffer(sDirBuff))'ie "c:\windows" End If End Sub Private Sub cmdIconDlg_Click() DoIconDialog End Sub Private Sub DoIconDialog() Dim sFileName As String Dim nIconIdx As Long '0 on init Dim hSmallIcon As Long Dim hLargeIcon As Long 'Allocate rtn buffer sFileName = MakeMaxPath(txtIconPath) 'convert it to Unicode if required sFileName = CheckString(sFileName) 'assign the icon number in txtIconIndex 'to a Long. If it's empty, assign 0 to 'prevent an error. If Val(txtIconIdx) Then nIconIdx = Val(txtIconIdx) Else nIconIdx = 0 End If 'Returns 1 if selection, 0 if cancelled If SHChangeIconDialog(Me.hWnd, sFileName, 0, nIconIdx) Then 'Display selection txtIconPath = GetStrFromBuffer(sFileName) txtIconIdx = nIconIdx 'Returns number of icons extracted, 0 on 'error, -1 if invalid filename. 'Creates specified number of icons and must 'all be destroyed when no longer need (frees 'the memory they occupy). If ExtractIconEx(sFileName, nIconIdx, hLargeIcon, hSmallIcon, 1) > 0 Then picSmallIcon.AutoRedraw = True picLargeIcon.AutoRedraw = True picSmallIcon.Cls picLargeIcon.Cls 'See MSKB article ID Q141933 for info on 'creating a picture object from an image handle '(which can then be assigned to a picture box 'picture property) DrawIconEx picSmallIcon.hDC, 1, 1, hSmallIcon, 0, 0, 0, 0, DI_NORMAL DrawIconEx picLargeIcon.hDC, 1, 1, hLargeIcon, 0, 0, 0, 0, DI_NORMAL DestroyIcon hSmallIcon DestroyIcon hLargeIcon picSmallIcon.AutoRedraw = False picLargeIcon.AutoRedraw = False End If End If End Sub |
Comments |
Save the project before running.
When a file containing icons is selected, the Change Icon dialog will display. If the file has no icons, the message "The file (filename) contains no icons. Choose an icon from the list or specify a different file". The default Shell32.dll icon library is presented for selection instead. Once the icons are in the picture boxes and the DoIconDialog() routine has completed, they can be saved to disk with the SavePicture method. |
|
|
|
|||||
|
|||||
|
|||||
Copyright ©1996-2011 VBnet and Randy Birch. All Rights Reserved. |