|
|
![]() |
|
||
|
|
|||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||
| 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. |
|
|
|
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. |
|
|