Jump to content

SHGetFileInfo()


Recommended Posts

Why icon path will not be returned?

Thanks.

const $SHGFI_ICON = 0x0100
const $SHGFI_ICONLOCATION = 0x1000

const $Path = @WindowsDir & '\clock.avi'

local $tSHFILEINFO = DllStructCreate('ptr;int;dword;char[260];char[80]')
local $Ret = DllCall('shell32.dll', 'ptr', 'SHGetFileInfo', 'str', $Path, 'dword', 0x80, 'ptr', DllStructGetPtr($tSHFILEINFO), 'int', DllStructGetSize($tSHFILEINFO), 'int', BitOR($SHGFI_ICON, $SHGFI_ICONLOCATION))
ConsoleWrite('Icon Path: ' & DllStructGetData($tSHFILEINFO, 4) & @CR)
Link to comment
Share on other sites

Have you installed TortoiseSVN /CVS Then it won't work: http://www.eggheadcafe.com/conversation.as...readid=30166180

*GERMAN* [note: you are not allowed to remove author / modified info from my UDFs]My UDFs:[_SetImageBinaryToCtrl] [_TaskDialog] [AutoItObject] [Animated GIF (GDI+)] [ClipPut for Image] [FreeImage] [GDI32 UDFs] [GDIPlus Progressbar] [Hotkey-Selector] [Multiline Inputbox] [MySQL without ODBC] [RichEdit UDFs] [SpeechAPI Example] [WinHTTP]UDFs included in AutoIt: FTP_Ex (as FTPEx), _WinAPI_SetLayeredWindowAttributes

Link to comment
Share on other sites

Link to comment
Share on other sites

Link to comment
Share on other sites

Googling around the web suggests that this function doesn't necessarily return the file name:

http://groups.google.com/group/microsoft.p...d078bc3df9ecf8f

Link to comment
Share on other sites

Link to comment
Share on other sites

I'm working on a (partial) solution to this problem. I'll be posting some code sometime in the next 24 hours ...

WBD

Link to comment
Share on other sites

Link to comment
Share on other sites

OK. Here goes. It sort of works OK for me but there's probably more work required.

#include <WinAPI.au3>

Opt("ExpandEnvStrings", 1)

Global Const $LOAD_LIBRARY_AS_DATAFILE = 2
Global Const $RT_ICON = 3
Global Const $RT_STRING = 6
Global Const $RT_GROUP_ICON = 14
Global $aResNames[1]

Global $hKernel = DllOpen("kernel32.dll")
Global $hUser = DllOpen("user32.dll")

Global $sExt = "avi"
Global $sType = RegRead("HKEY_CLASSES_ROOT\." & $sExt, "")
Global $sIcon = RegRead("HKEY_CLASSES_ROOT\" & $sType & "\DefaultIcon", "")
Global $fhTemp
Global $aIconInfo = StringSplit($sIcon, ",")
If @error Then
    $fhTemp = FileOpen(@TempDir & "\temp." & $sExt, 2)
    FileWrite($fhTemp, "0")
    FileClose($fhTemp)
    $sIcon = _WinAPI_FindExecutable($fhTemp) & ",0"
    FileDelete(@TempDir & "\temp." & $sExt)
    $aIconInfo = StringSplit($sIcon, ",")
    If @error Then Exit
EndIf
Global $sExe = $aIconInfo[1]
If StringLeft($sExe, 1) = """" Then $sExe = StringMid($sExe, 2, StringLen($sExe) - 2)
Global $nIcon = Number($aIconInfo[2])

Global $hGUI = GUICreate("Icon", 128, 128)
Global $picIcon = GUICtrlCreatePic("", 40, 40, 48, 48)
GuISetState()
Global $hDC = _WinAPI_GetDC(GUICtrlGetHandle($picIcon))
Global $hIcon, $nLibH
If $nIcon < 0 Then
    $nLibH = DllCall($hKernel, "long", "LoadLibraryEx", "str", $sExe, "long", 0, "long", $LOAD_LIBRARY_AS_DATAFILE)
    $hIcon = _GetAssociatedIconHandle($nLibH[0], Abs($nIcon), $RT_GROUP_ICON, 48)
Else
    $hIcon = _GetAssociatedIconBySize($sExe, $nIcon, 48)
EndIf
If $hIcon <> 0 Then _WinAPI_DrawIconEx($hDC, 0, 0, $hIcon)
Do
Until GUIGetMsg() = -3
GUIDelete()
Exit

Func _GetAssociatedIconBySize($sModule, $nIcon, $nSize)
    Local $nLibH, $nIcoIDS[1], $retval = 0
    Local $hCallback = DllCallbackRegister("_EnumResNamesProc", "long", "long;long;long;long")
    $nLibH = DllCall($hKernel, "long", "LoadLibraryEx", "str", $sModule, "long", 0, "long", $LOAD_LIBRARY_AS_DATAFILE)
    If $nLibH[0] <> 0 Then
        ReDim $aResNames[1]
        DllCall($hKernel, "long", "EnumResourceNames", "long", $nLibH[0], "long", $RT_GROUP_ICON, "long", DllCallbackGetPtr($hCallback), "long", 0)
        If $nIcon < UBound($aResNames) Then
            $retval = _GetAssociatedIconHandle($nLibH[0], $aResNames[$nIcon], $RT_GROUP_ICON, $nSize)
        EndIf
        DllCall($hKernel, "long", "FreeLibrary", "long", $nLibH)
    EndIf
    Return $retval
EndFunc

Func _EnumResNamesProc($hMod, $lpszType, $lpszName, $lParam)
    Local $strName, $lngName, $bytData, $lngLen, $hStruct
    If BitAND($lpszName, 0xffff0000) = 0 Then
        $lngName = BitAND($lpszName, 0xffff)
        $aResNames[UBound($aResNames) - 1] = $lngName
    Else
        $lngLen = DllCall($hKernel, "long", "lstrlen", "long", $lpszName)
        If ($lngLen[0] > 0) Then
            $hStruct = DllStructCreate("char[256]", $lpszName)
            $strName = DllStructGetData($hStruct, 1)
        EndIf
        $aResNames[UBound($aResNames) - 1] = $strName
    EndIf
    If StringLen($aResNames[UBound($aResNames) - 1]) > 0 Then
        Redim $aResNames[UBound($aResNames) + 1]
    EndIf
    Return 1
EndFunc

Func _GetAssociatedIconHandle($lngLibHandle, $varNameOrID, $lngType, $nSize)
    Local $lngResInfo, $lngResHandle
    Local $lngResPtr, $lngResLen, $lngResBuff
    Local $lngResID, $retval
    If IsString($varNameOrID) Then
        $lngResInfo = DllCall($hKernel, "long", "FindResource", "long", $lngLibHandle, "str", $varNameOrID, "long", $lngType)
    Else
        $lngResInfo = DllCall($hKernel, "long", "FindResource", "long", $lngLibHandle, "long", $varNameOrID, "long", $lngType)
    EndIf
    If $lngResInfo[0] <> 0 Then
        $lngResHandle = DllCall($hKernel, "long", "LoadResource", "long", $lngLibHandle, "long", $lngResInfo[0])
        If $lngResHandle[0] <> 0 Then
            $lngResPtr = DllCall($hKernel, "long", "LockResource", "long", $lngResHandle[0])
            If $lngResPtr[0] <> 0 Then
                $lngResLen = DllCall($hKernel, "long", "SizeofResource", "long", $lngLibHandle, "long", $lngResInfo[0])
                $lngResBuff = DllStructCreate("byte[" & $lngResLen[0] & "]", $lngResPtr[0])
                If $lngType = $RT_GROUP_ICON Then
                    $lngResID = DllCall($hUser, "long", "LookupIconIdFromDirectoryEx", "ptr", DllStructGetPtr($lngResBuff), "int", 1, "long", $nSize, "long", $nSize, "long", 0)
                    If $lngResID[0] <> 0 Then
                        $retval = _GetAssociatedIconHandle($lngLibHandle, $lngResID[0], $RT_ICON, $nSize)
                    EndIf
                    Return $retval
                EndIf
                $retval = DllCall($hUser, "long", "CreateIconFromResourceEx", "ptr", DllStructGetPtr($lngResBuff), "long", $lngResLen[0], "int", 1, "long", 0x30000, "long", $nSize, "long", $nSize, "long", 0)
                $retval = $retval[0]
            EndIf
        EndIf
    EndIf
    Return $retval
EndFunc

Edited by WideBoyDixon
Link to comment
Share on other sites

UPDATE: I've re-written this in to a UDF and posted in the "Example Scripts" forum. I hope you find it useful.

WBD

Link to comment
Share on other sites

WideBoyDixon, many thanks to you for your work, I appreciate it. But you missed one function - PrivateExtractIcons(). It can extract icons of arbitrary size. In this case, your code x8 will be less. Actually the problem is that I want to use large icons (eg 128x128), but almost all of the functions return the icons according to the system metric values (default is 32x32 and 16x16 for large and small icons, respectively). It is not suitable for me. The only way that I see at this time - an analysis of the registry. I do want to avoid. Using SHGetFileInfo() with SHGFI_ICONLOCATION flag would be a good solution (knowing the path to the file, I get the icon of any size from this file by PrivateExtractIcons() function), but this function does not work as designed by Microsoft. A pity. On the Internet many people are faced with this unpleasant problem. I do not believe that there is no way to get the icon for the registered file types, avoiding an analysis of the registry. Perhaps I am very opinionated. In your example, you also got the path to the icon file from the registry. By the way, in your example you are wrong to display the icon (HIcon) in Control. See my _SetHIcon() function.

Thanks again.

func _WinAPI_PrivateExtractIcon($sIcon, $iIndex, $iWidth, $iHeight)
    
    local $hIcon, $tIcon = DllStructCreate('hwnd'), $tID = DllStructCreate('hwnd')
    local $ret
    
    $ret = DllCall('user32.dll', 'int', 'PrivateExtractIcons', 'str', $sIcon, 'int', $iIndex, 'int', $iWidth, 'int', $iHeight, 'ptr', DllStructGetPtr($tIcon), 'ptr', DllStructGetPtr($tID), 'int', 1, 'int', 0)
    if (@error) or ($ret[0] = 0)then
        return SetError(1, 0, 0)
    endif
    
    $hIcon = DllStructGetData($tIcon, 1)
    
    if ($hIcon = Ptr(0)) or (not IsPtr($hIcon)) then
        return SetError(1, 0, 0)
    endif
    
    return SetError(0, 0, $hIcon)
endfunc; _WinAPI_PrivateExtractIconoÝ÷ Ù«­¢+ÙÕ¹}MÑ!%½¸ ÀÌØí½¹Ñɽ±%°ÀÌØí¡%½¸¤($(%½¹ÍÐÀÌØíMQ5}MQ%5ôÁàÀÄÜÈ($(%±½°ÀÌØí¡]¹°ÀÌØíMÑå±(($ÀÌØí¡]¹ôU%
ÑɱÑ!¹± ÀÌØí½¹Ñɽ±%¤(%¥ÀÌØí¡]¹ôÀÑ¡¸($%ÉÑÕɸMÑÉÉ½È Ä°À°À¤(%¹¥($ÀÌØíMÑå±ô}]¥¹A%}Ñ]¥¹½Ý1½¹ ÀÌØí¡]¹°ÀÌØí]1}MQe1¤(%¥ÉɽÈÑ¡¸($%ÉÑÕɸMÑÉÉ½È Ä°À°À¤(%¹¥(%}]¥¹A%}]¥¹½Ý1½¹ ÀÌØí¡]¹°ÀÌØí]1}MQe1°  ¥Ñ=H ÀÌØíMÑå±°!à ÀÌØíMM}%
=8¤¤¤(%¥ÉɽÈÑ¡¸($%ÉÑÕɸMÑÉÉ½È Ä°À°À¤(%¹¥(%}]¥¹A%}±Ñ=©Ð¡}5ÍÍ ÀÌØí¡]¹°ÀÌØíMQ5}MQ%5°ÀÌØí%5}%
=8°À¤¤(%}5ÍÍ ÀÌØí¡]¹°ÀÌØíMQ5}MQ%5°ÀÌØí%5}%
=8°ÀÌØí¡%½¸¤(%¥ÉɽÈÑ¡¸($%ÉÑÕɸMÑÉÉ½È Ä°À°À¤(%¹¥(%ÉÑÕɸÄ)¹Õ¹ì}MÑ!%½¸

PS.

I like Mario kart.

^_^

Link to comment
Share on other sites

Although you can access this function by using LoadLibrary and GetProcAddress combined in Windows versions prior to Windows XP, the function was not accessible using the standard Include file and library linkage. In Windows XP Service Pack 1 (SP1) and Windows Server 2003 this function is now documented and made accessible using the appropriate include file and library linkage. However, this function is deprecated not intended for general use. It is recommended that you do not use it in new programs because it might be altered or unavailable in subsequent versions of Windows.

http://msdn.microsoft.com/en-us/library/ms648075.aspx

My other function handles folders as well. Without accessing the registry (which is the right way) how will you ever know which icon index to extract for a file? I think you should try my function in the Example Scripts and see what you think.

It's Rainbow Road all the way ^_^

WBD

Edited by WideBoyDixon
Link to comment
Share on other sites

_SetHIcon() didn't work on my picture control?

Link to comment
Share on other sites

_SetHIcon() didn't work on my picture control?

_SetHIcon() work on icon control only. See my examples.

EDIT: _SetHIcon() same as _SetIcon(), only for the icon handles.

PrivateExtractIcons() is present in Vista and Windows 7, and works very well. It seems that Microsoft specifically "places a stick in the wheel".

Edited by Yashied
Link to comment
Share on other sites

  • 8 months later...

Did you come to solution for this problem?

I have the exactly the same problem of how to extract the associated icon in a bigger size. I would be very interested in a solution (if there is one).

UTA

Link to comment
Share on other sites

Did you come to solution for this problem?

I have the exactly the same problem of how to extract the associated icon in a bigger size. I would be very interested in a solution (if there is one).

UTA

Look at _WinAPI_AssocQueryString() function from the WinAPIEx.au3 library. Edited by Yashied
Link to comment
Share on other sites

Look at _WinAPI_AssocQueryString() function from the WinAPIEx.au3 library.

Oh perfect, works like a charm for any file-extension. Together with your Icons.au3 the painted results are perfect.

But what have to be done, if I want to get the defaulticon for a Path (e.g. directory or drive) ? _WinAPI_AssocQueryString together with a file-extension isn't possible - I don't have an extension... The other possibilities for the parameter "$sAssoc" doesn't mean anything to me ;)

EDIT: I could use your idea with SHGETFILEINFO of the first post, but it wouldn't feel like a neat solution (to use AssocQueryString on file and SHGetFileInfo on Paths).

UTA

Edited by UTA
Link to comment
Share on other sites

Use _WinAPI_AssocQueryString() for files, _WinAPI_ShellGetFileInfo() - for disks and folders.

#Include <WinAPIEx.au3>

$tSHFILEINFO = _WinAPI_ShellGetFileInfo(_WinAPI_ShellGetSpecialFolderPath($CSIDL_MYPICTURES), $SHGFI_ICONLOCATION)

$Icon = DllStructGetData($tSHFILEINFO, 'DisplayName')
$Index = DllStructGetData($tSHFILEINFO, 'iIcon')

; For GUICtrlCreateIcon() only!
If $Index < 0 Then
    $Index = -$Index
Else
    $Index = -($Index + 1)
EndIf

GUICreate('MyGUI', 128, 128)
GUICtrlCreateIcon($Icon, $Index, 40, 40, 48, 48)
GUISetState()

Do
Until GUIGetMsg() = -3
Edited by Yashied
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...