Sign in to follow this  
Followers 0
KaFu

AutoItObject suitable to retrieve IExtractImage Interface Pointer from ShellFolder?

17 posts in this topic

#1 ·  Posted (edited)

HiHo Forum,

for quite some time now I've tried to extract shell thumbnail previews of files. The way to go seems to be the IExtractImage interface. But how to access that one? I've found quite a good tutorial for delphi here (google cache as the website seems to be down).

Retrieving the files PIDL seems quite straight forward using Yashieds WinApiEx functions (step 1+2). But then the hard part, how to access the interface itself? AutoItObject might be the right tool for this, but... as already stated in the title I've clearly not understood AutoItObject (yet) :x...

Maybe one of the (real) pros is willing to take a deeper look?

#cs ----------------------------------------------------------------------------
    
    AutoIt Version: 3.3.6.1
    Author:         KaFu
    
    Script Function:
    IExtracteImage Shell Interface Example
    
#ce ----------------------------------------------------------------------------

#include <WinApiEx.au3>

$sFile_BMP_Path = StringLeft(@AutoItExe, StringInStr(@AutoItExe, "\", 0, -1)) & "Examples\GUI\Advanced\Images\"
$sFile_BMP_File = $sFile_BMP_Path & "Blue.bmp"

#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>

GUICreate("IExtractImage Example")
GUICtrlCreatePic($sFile_BMP_File, 10, 10)

#cs
    ; http://webcache.googleusercontent.com/search?q=cache:Ta2k4JCcIbQJ:www.delphi3000.com/article.asp%3FID%3D3806+iextractimage+c&cd=8&hl=de&ct=clnk&gl=de&client=firefox-a
    IExtractImage Interface Type Declaration
    ============
    
    MIDL_INTERFACE("BB2E617C-0920-11d1-9A0B-00C04FC2D6C1")
    IExtractImage : public IUnknown
    {
    public:
    virtual HRESULT STDMETHODCALLTYPE GetLocation(
    /* [size_is][out] */ LPWSTR pszPathBuffer,
    /* [in] */ DWORD cch,
    /* [unique][out][in] */ DWORD *pdwPriority,
    /* [in] */ const SIZE *prgSize,
    /* [in] */ DWORD dwRecClrDepth,
    /* [in] */ DWORD *pdwFlags) = 0;
    
    virtual HRESULT STDMETHODCALLTYPE Extract(
    /* [out] */ HBITMAP *phBmpThumbnail) = 0;
    
    };
    
#ce

#cs
    Step #1: Retrieving IShellFolder Interface Pointer (skipped)
    Step #2: Retrieving Relative PIDL for A System File (done directly via _WinApiEx calls below (?)
#ce

$hPath_PIDL = _WinAPI_ShellILCreateFromPath($sFile_BMP_File)
ConsoleWrite(@error & @TAB & $hPath_PIDL & @CRLF)
ConsoleWrite(_WinAPI_ShellGetPathFromIDList($hPath_PIDL) & @CRLF)

#cs
    ============
    Step #3: Retrieving IExtractImage Interface Pointer from ShellFolder
    Now to really get the IExtractImage interface pointer, we use IShellFolder's method: GetUIObjectOf().
    This is the method to obtain an aforementioned indirectly-exposed interface from IShellFolder interface.
    
    TargetFolder.GetUIObjectOf(0, 1, ItemIDList, IExtractImage,
    nil, XtractImg);
    Malloc.Free(ItemIDList);
    
    ============
    Step #4: Final Step - IExtractImage In Action
    Once we obtain an IExtractImage interface pointer, there are two steps to the process. First, use
    GetLocation() to request the path description of an image and specify how the image should be rendered. Then, call Extract() to extract the image.
    
    var
    ...
    Bmp: TBitmap;
    BitmapHandle: HBITMAP;
    Buf: array[0..MAX_PATH] of WideChar;
    ColorDepth, Priority, Flags: DWORD;
    begin
    ...
    { Specify thumbnail image size we want. We want the image to
    fit the size of TImage component. }
    Size.cx := Image1.Width;  // desired thumbnail image width
    Size.cy := Image1.Height; // desired thumnbail image height
    
    { Specify Flag bits for GetLocation() method. }
    Flags := IEIFLAG_SCREEN   // Used to tell the object to render
    or               // as if for the screen.
    IEIFLAG_OFFLINE; // Used to tell the object to use
    // only local content for rendering.
    
    Priority := 0; // normal priority. usefull if extraction
    // process executed within background thread
    ColorDepth := 32; // we want thumbnail image of type pf32bit
    GetLocationRes := XtractImg.GetLocation(Buf, sizeof(Buf), Priority,
    Size, ColorDepth, Flags);
    if (GetLocationRes = NOERROR) or (GetLocationRes = E_PENDING) then
    begin
    Bmp := TBitmap.Create;
    try
    OleCheck(XtractImg.Extract(BitmapHandle));
    Bmp.Handle := BitmapHandle;
    Image1.Picture.Assign(Bmp);
    finally
    Bmp.Free;
    end;
    end;
    ...
    
#ce

$iRes = _WinAPI_CoTaskMemFree($hPath_PIDL)
ConsoleWrite(@error & @TAB & $iRes & @CRLF)

GUISetState(@SW_SHOW)

While 1
    $msg = GUIGetMsg()

    If $msg = $GUI_EVENT_CLOSE Then ExitLoop
WEnd
GUIDelete()

Regards

Edited by KaFu

Share this post


Link to post
Share on other sites



#2 ·  Posted (edited)

Follow that tutorial precisely (all steps) and there will be no problems. Add code shortcuts later. The biggest job is to define the interfaces. After that it's nothing but joy.

You need IShellFolder and IExtractImage, meaning $dtagIShellFolder and $dtagIExtractImage.

Edited by trancexx

♡♡♡

.

eMyvnE

Share this post


Link to post
Share on other sites

#3 ·  Posted (edited)

Okay, went back to step 1 :P. Retrieved the IShellFolder interface for the desktop folder and defined the $tagIShellFolder. But how do I glue this together to form an object :x?

#include "AutoItObject.au3"

_AutoItObject_Startup()

; Step by Step Tutorial for IExtractImage in Delphi
; http://webcache.googleusercontent.com/search?q=cache:Ta2k4JCcIbQJ:www.delphi3000.com/article.asp%3FID%3D3806+iextractimage+c&cd=8&hl=de&ct=clnk&gl=de&client=firefox-a

; Step #1: Retrieving IShellFolder Interface Pointer

$strIShellFolder = DllStructCreate("ptr;")
$p_strIShellFolder = DllStructGetPtr($strIShellFolder)
; SHGetDesktopFolder = http://msdn.microsoft.com/de-de/library/bb762175%28v=VS.85%29.aspx
$iRes = DllCall("shell32.dll", "int", "SHGetDesktopFolder", "ptr", $p_strIShellFolder)
ConsoleWrite($iRes[0] & @TAB & DllStructGetData($strIShellFolder, 1) & @CRLF)

; IShellFolder Interface = http://msdn.microsoft.com/de-de/library/bb775075%28v=VS.85%29.aspx
$tagIShellFolder = "QueryInterface long(ptr;ptr;ptr);" & _
        "AddRef ulong();" & _
        "Release ulong();" & _
        "BindToObject hresult(hwnd);" & _
        "BindToStorage hresult(hwnd);" & _
        "CompareIDs hresult(hwnd);" & _
        "CreateViewObject hresult(hwnd);" & _
        "EnumObjects hresult(hwnd);" & _
        "GetAttributesOf hresult(hwnd);" & _
        "GetDisplayNameOf hresult(hwnd);" & _
        "GetUIObjectOf hresult(hwnd);" & _
        "ParseDisplayName hresult(hwnd);" & _
        "SetNameOf hresult(hwnd);"

; http://social.msdn.microsoft.com/forums/en-US/netfxbcl/thread/05884106-9acd-4213-8f1d-1e6b1bba9262
$IID_IShellFolder = _AutoItObject_CLSIDFromString("{000214E6-0000-0000-C000-000000000046}")
$oIShellFolder = _AutoItObject_ObjCreate($IID_IShellFolder, $IID_IShellFolder, $tagIShellFolder)

$strReceiver = DllStructCreate("ptr;")
; ParseDisplayName = http://msdn.microsoft.com/de-de/library/bb775090%28v=VS.85%29.aspx
$oIShellFolder.ParseDisplayName(0, "", "c:\windows", 0, DllStructGetPtr($strReceiver), 0)
ConsoleWrite(DllStructGetData($strReceiver, 1) & @CRLF)

$oIShellFolder = 0

_AutoItObject_Shutdown()
Edited by KaFu

Share this post


Link to post
Share on other sites

#4 ·  Posted (edited)

I just created an example yesterday. Not very clean but hey, it works.

#include<AutoItObject.au3>
#include<WinAPI.au3>
#include<WinAPIEx.au3>
#include<WindowsConstants.au3>
#include<Constants.au3>
#include<GUIConstantsEx.au3>

#include-once
;===============================================================================
#API "Extracting Image"
; IShellFolder
; IExtractImage
;===============================================================================

;.......written by ProgAndy

;===============================================================================
#interface "IShellFolder"
$sIID_IShellFolder = "{000214E6-0000-0000-C000-000000000046}"
; Definition
Global Const $dtagIShellFolder = $dtagIUnknown & _
        "ParseDisplayName hresult(hwnd;ptr;wstr;dword*;ptr*;dword*);" & _
        "EnumObjects hresult(hwnd;dword;ptr*);" & _
        "BindToObject hresult(ptr;ptr;ptr;ptr*);" & _
        "BindToStorage hresult(ptr;ptr;ptr;ptr*);" & _
        "CompareIDs hresult(lparam;ptr;ptr);" & _
        "CreateViewObject hresult(hwnd;ptr;ptr*);" & _
        "GetAttributesOf hresult(UINT;ptr;ulong*);" & _
        "GetUIObjectOf hresult(hwnd;uint;ptr;ptr;uint*;ptr*);" & _
        "GetDisplayNameOf hresult(ptr;uint;ptr);" & _
        "SetNameOf hresult(hwnd;ptr;wstr;dword;ptr*);"
; List
Global Const $ltagIShellFolder = $ltagIUnknown & _
        "ParseDisplayName;" & _
        "EnumObjects;" & _
        "BindToObject;" & _
        "BindToStorage;" & _
        "CompareIDs;" & _
        "CreateViewObject;" & _
        "GetAttributesOf;" & _
        "GetUIObjectOf;" & _
        "GetDisplayNameOf;" & _
        "SetNameOf;"
;===============================================================================


;===============================================================================
#interface "IExtractImage"
Global Const $sIID_IExtractImage = "{BB2E617C-0920-11d1-9A0B-00C04FC2D6C1}"
; Definition
Global Const $dtagIExtractImage = $dtagIUnknown & _
        "GetLocation hresult(wstr;DWORD;DWORD*;ptr;dword;DWORD*);" & _
        "Extract hresult(ptr*);"
; List
Global Const $ltagIExtractImage = $ltagIUnknown & _
        "GetLocation;" & _
        "Extract;"
;===============================================================================

;===============================================================================
#interface "IShellItemImageFactory"
Global Const $sIID_IShellItemImageFactory = "{bcc18b79-ba16-442f-80c4-8a59c30c463b}"
; Definition
Global Const $dtagIShellItemImageFactory = $dtagIUnknown & _
        "GetImage hresult(uint64;dword;ptr*);" ; <==== uint64 instead of long;long
; List
Global Const $ltagIShellItemImageFactory = $ltagIUnknown & _
        "GetImage;"
;===============================================================================

;===============================================================================
#interface "IShellItem"
Global Const $IID_IShellItem = "{43826d1e-e718-42ee-bc55-a1e261c37bfe}"
Global Const $dtagIShellItem = $dtagIUnknown & _
        "BindToHandler hresult(ptr;ptr;ptr;ptr*);" & _
        "GetParent hresult(ptr*);" & _
        "GetDisplayName hresult(dword;ptr*);" & _
        "GetAttributes hresult(dword;dword*);" & _
        "Compare hresult(ptr;dword;int*);"
Global Const $ltagIShellItem = $ltagIUnknown & _
        "BindToHandler;" & _
        "GetParent;" & _
        "GetDisplayName;" & _
        "GetAttributes;" & _
        "Compare;"
;===============================================================================

Global $hDCB, $hBmp
_AutoItObject_StartUp()
OnAutoItExitRegister("_close")
Func _close()
    _WinAPI_DeleteDC($hDCB)
    _WinAPI_DeleteObject($hBmp)
    _AutoItObject_Shutdown()
EndFunc   ;==>_close

$fUseAlphaBlend = False
$sFileName = "D:\Eigene Bilder\test.png"
$tIIDImgFact = _AutoItObject_CLSIDFromString($sIID_IShellItemImageFactory)
Dim $pImgFact
If 0 = _SHCreateItemFromParsingName($sFileName, 0, DllStructGetPtr($tIIDImgFact), $pImgFact) And $pImgFact Then
    $IImgFact = _AutoItObject_WrapperCreate($pImgFact, $dtagIShellItemImageFactory)
    $r = $IImgFact.GetImage(_MakeUINT64(128, 128), 0, 0)  ; <==== _MakeUINT64 added
    $hBmp = $r[3]  ; <==== parameter count was changed, so fixed it here

Else
    $pidl = _ILCreateFromPath($sFileName)

    Dim $pIShellFolder, $pRelative
    $tRIID = _AutoItObject_CLSIDFromString($sIID_IShellFolder)
    $tRIIDExtract = _AutoItObject_CLSIDFromString($sIID_IExtractImage)
    If StringInStr(FileGetAttrib($sFileName), "D", 1) Then
        MsgBox(0, '', "Cannot create preview for Folders on Windows prior to Vista")
        Exit
    Else
        _SHBindToParent($pidl, DllStructGetPtr($tRIID), $pIShellFolder, $pRelative)
        $IShellFolder = _AutoItObject_WrapperCreate($pIShellFolder, $dtagIShellFolder)

        $tSTRRET = DllStructCreate("uint uType;ptr data;")
        $r = $IShellFolder.GetDisplayNameOf(Number($pRelative), 0, Number(DllStructGetPtr($tSTRRET)))

        Dim $name
        _StrRetToBuf(DllStructGetPtr($tSTRRET), 0, $name, 512)
        $tSTRRET = 0

        MsgBox(0, 'name of item', $name)

        $tArray = DllStructCreate("ptr")
        DllStructSetData($tArray, 1, $pRelative)

        $r = $IShellFolder.GetUIObjectOf(0, 1, Number(DllStructGetPtr($tArray)), Number(DllStructGetPtr($tRIIDExtract)), 0, 0)
        $IExtractImage = _AutoItObject_WrapperCreate($r[6], $dtagIExtractImage)
    EndIf
    $tSize = DllStructCreate("long;long")
    DllStructSetData($tSize, 1, 128)
    DllStructSetData($tSize, 2, 128)
    $r = $IExtractImage.GetLocation("", 1024, 0, Number(DllStructGetPtr($tSize)), 32, 0)
    MsgBox(0, '', $r[1])
    $r = $IExtractImage.Extract(0)
    $hBmp = $r[1]


    $IShellFolder = 0
    _CoTaskMemFree($pidl)
EndIf

$hGUI = GUICreate("test", 256, 128)
GUIRegisterMsg($WM_PAINT, "_WM_PAINT")
$btnColor = GUICtrlCreateButton("ColorChange", 130, 20, 100, 20)
$hDC = _WinAPI_GetDC(0)
$hDCB = _WinAPI_CreateCompatibleDC($hDC)
_WinAPI_SelectObject($hDCB, $hBmp)
_WinAPI_ReleaseDC(0, $hDC)

$IExtractImage = 0

GUISetState()
While 1
    Switch GUIGetMsg()
        Case -3
            ExitLoop
        Case $btnColor
            GUISetBkColor(Random(0, 0xFFFFFF, 1))
    EndSwitch
WEnd

Func _WM_PAINT($hWnd, $uMsg, $wParam, $lParam)
    Local $tPS
    Local $hDC = _WinAPI_BeginPaint($hWnd, $tPS)
    $x = DllStructGetData($tPS, "rPaint", 1)
    $y = DllStructGetData($tPS, "rPaint", 2)
    $w = DllStructGetData($tPS, "rPaint", 3) - $x
    $h = DllStructGetData($tPS, "rPaint", 4) - $y
    If $x <= 128 Then
        If $x + $w > 128 Then $w = 128 - $x
        If $fUseAlphaBlend Then
            _WinAPI_AlphaBlend($hDC, $x, $y, $w, $h, $hDCB, $x, $y, $w, $h, 255, True)
        Else
            _WinAPI_BitBlt($hDC, $x, $y, $w, $h, $hDCB, $x, $y, $SRCCOPY)
        EndIf
    EndIf
    _WinAPI_EndPaint($hWnd, $tPS)
    Return $GUI_RUNDEFMSG
EndFunc   ;==>_WM_PAINT

Func _MakeUINT64($long1, $long2)
    Local $d = DllStructCreate("align 4;dword[2]")
    DllStructSetData($d, 1, $long1, 1)
    DllStructSetData($d, 1, $long2, 2)
    Return DllStructGetData(DllStructCreate("uint64", DllStructGetPtr($d)),1)
EndFunc

Func _CoTaskMemFree($pMem)
    Local $aRes = DllCall("Ole32.dll", "none", "CoTaskMemFree", "ptr", $pMem)
    If @error Then SetError(1)
EndFunc   ;==>_CoTaskMemFree
Func _ILCreateFromPath($sPath)
    Local $aRes = DllCall("shell32.dll", "ptr", "ILCreateFromPathW", "wstr", $sPath)
    If @error Then Return SetError(1, 0, 0)
    Return $aRes[0]
EndFunc   ;==>_ILCreateFromPath

Func _SHCreateItemFromParsingName($szPath, $pbc, $riid, ByRef $pv)
    Local $aRes = DllCall("shell32.dll", "long", "SHCreateItemFromParsingName", "wstr", $szPath, "ptr", $pbc, "ptr", $riid, "ptr*", 0)
    If @error Then Return SetError(1, 0, 0)
    $pv = $aRes[4]
    Return $aRes[0]
EndFunc   ;==>_SHCreateItemFromParsingName
Func _SHBindToObject($psf, $pidl, $pbc, $riid, ByRef $pv)
    Local $aRes = DllCall("Shell32.dll", "long", "SHBindToObject", "ptr", $psf, "ptr", $pidl, "ptr", $pbc, "ptr", $riid, "ptr*", 0)
    If @error Then Return SetError(1, 0, 0)
    $pv = $aRes[5]
    Return $aRes[0]
EndFunc   ;==>_SHBindToObject
Func _SHBindToParent($pidl, $riid, ByRef $pv, ByRef $pidlLast)
    Local $aRes = DllCall("Shell32.dll", "long", "SHBindToParent", "ptr", $pidl, "ptr", $riid, "ptr*", 0, "ptr*", 0)
    If @error Then Return SetError(1, 0, 0)
    $pv = $aRes[3]
    $pidlLast = $aRes[4]
    Return $aRes[0]
EndFunc   ;==>_SHBindToParent
Func _StrRetToBuf($pSTRRET, $pidl, ByRef $sName, $iLength = 512)
    Local $aRes = DllCall("shlwapi.dll", "long", "StrRetToBufW", "ptr", $pSTRRET, "ptr", $pidl, "wstr", $sName, "uint", $iLength)
    If @error Then Return SetError(1, 0, 0)
    $sName = $aRes[3]
    Return $aRes[0]
EndFunc   ;==>_StrRetToBuf

Exit

Edit: Modified sp that $IImgFact.GetImage should work on x64, too. (look at ; <==== )

Edited by ProgAndy

*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

Share this post


Link to post
Share on other sites

Great ProgAndy. We should really implement structure-parameter.


♡♡♡

.

eMyvnE

Share this post


Link to post
Share on other sites

Great ProgAndy. We should really implement structure-parameter.

Yep, maybe we should begin with a simpler version, though. Somthing like "struct,64", DLLStructGetPtr($tStruct) and then copy the data from the struct in the parameter as a byte array with given length (here 64)

*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

Share this post


Link to post
Share on other sites

#8 ·  Posted (edited)

Whoooha :shifty:, just fucking awesome how easy it was to integrate into SMF :x...

Andy, thanks again for this great piece of code :nuke: ...

(btw, you don't know by "accident" how to center the bitmaps if the ratio does not fit :P ?)

Edit: Looking at the IShellItemImageFactory::GetImage Method setting the flag SIIGBF_BIGGERSIZEOK and resizing the returned bitmap myself seems to be the way to go... will check it out and post when done :lol:...

Posted Image

Edited by KaFu

Share this post


Link to post
Share on other sites

This is an example including centering of the image and a cleaner calcualtion of the image portion to draw:

#include<AutoItObject.au3>
#include<WinAPI.au3>
#include<WinAPIEx.au3>
#include<WindowsConstants.au3>
#include<Constants.au3>
#include<GUIConstantsEx.au3>

#include-once
;===============================================================================
#API "Extracting Image"
; IShellFolder
; IExtractImage
;===============================================================================

;.......written by ProgAndy

;===============================================================================
#interface "IShellFolder"
$sIID_IShellFolder = "{000214E6-0000-0000-C000-000000000046}"
; Definition
Global Const $dtagIShellFolder = $dtagIUnknown & _
        "ParseDisplayName hresult(hwnd;ptr;wstr;dword*;ptr*;dword*);" & _
        "EnumObjects hresult(hwnd;dword;ptr*);" & _
        "BindToObject hresult(ptr;ptr;ptr;ptr*);" & _
        "BindToStorage hresult(ptr;ptr;ptr;ptr*);" & _
        "CompareIDs hresult(lparam;ptr;ptr);" & _
        "CreateViewObject hresult(hwnd;ptr;ptr*);" & _
        "GetAttributesOf hresult(UINT;ptr;ulong*);" & _
        "GetUIObjectOf hresult(hwnd;uint;ptr;ptr;uint*;ptr*);" & _
        "GetDisplayNameOf hresult(ptr;uint;ptr);" & _
        "SetNameOf hresult(hwnd;ptr;wstr;dword;ptr*);"
; List
Global Const $ltagIShellFolder = $ltagIUnknown & _
        "ParseDisplayName;" & _
        "EnumObjects;" & _
        "BindToObject;" & _
        "BindToStorage;" & _
        "CompareIDs;" & _
        "CreateViewObject;" & _
        "GetAttributesOf;" & _
        "GetUIObjectOf;" & _
        "GetDisplayNameOf;" & _
        "SetNameOf;"
;===============================================================================


;===============================================================================
#interface "IExtractImage"
Global Const $sIID_IExtractImage = "{BB2E617C-0920-11d1-9A0B-00C04FC2D6C1}"
; Definition
Global Const $dtagIExtractImage = $dtagIUnknown & _
        "GetLocation hresult(wstr;DWORD;DWORD*;ptr;dword;DWORD*);" & _
        "Extract hresult(ptr*);"
; List
Global Const $ltagIExtractImage = $ltagIUnknown & _
        "GetLocation;" & _
        "Extract;"
;===============================================================================

;===============================================================================
#interface "IShellItemImageFactory"
Global Const $sIID_IShellItemImageFactory = "{bcc18b79-ba16-442f-80c4-8a59c30c463b}"
; Definition
Global Const $dtagIShellItemImageFactory = $dtagIUnknown & _
        "GetImage hresult(uint64;dword;ptr*);"
; List
Global Const $ltagIShellItemImageFactory = $ltagIUnknown & _
        "GetImage;"
;===============================================================================

;===============================================================================
#interface "IShellItem"
Global Const $IID_IShellItem = "{43826d1e-e718-42ee-bc55-a1e261c37bfe}"
Global Const $dtagIShellItem = $dtagIUnknown & _
        "BindToHandler hresult(ptr;ptr;ptr;ptr*);" & _
        "GetParent hresult(ptr*);" & _
        "GetDisplayName hresult(dword;ptr*);" & _
        "GetAttributes hresult(dword;dword*);" & _
        "Compare hresult(ptr;dword;int*);"
Global Const $ltagIShellItem = $ltagIUnknown & _
        "BindToHandler;" & _
        "GetParent;" & _
        "GetDisplayName;" & _
        "GetAttributes;" & _
        "Compare;"
;===============================================================================

Global $hDCB, $hBmp
_AutoItObject_StartUp()
OnAutoItExitRegister("_close")
Func _close()
    _WinAPI_DeleteDC($hDCB)
    _WinAPI_DeleteObject($hBmp)
    _AutoItObject_Shutdown()
EndFunc   ;==>_close

$fUseAlphaBlend = False
$sFileName = "D:\Eigene Bilder\Auto.png"
If Not FileExists($sFileName) Then
    MsgBox(0, '', "Invalid File Name")
    Exit
EndIf
$tIIDImgFact = _AutoItObject_CLSIDFromString($sIID_IShellItemImageFactory)
Dim $pImgFact
If 0 = _SHCreateItemFromParsingName($sFileName, 0, DllStructGetPtr($tIIDImgFact), $pImgFact) And $pImgFact Then
    $IImgFact = _AutoItObject_WrapperCreate($pImgFact, $dtagIShellItemImageFactory)
    $r = $IImgFact.GetImage(_MakeUINT64(128, 128), 0, 0)
    $hBmp = $r[3]

Else
    $pidl = _WinAPI_ShellILCreateFromPath($sFileName)

    Dim $pIShellFolder, $pRelative
    $tRIID = _AutoItObject_CLSIDFromString($sIID_IShellFolder)
    $tRIIDExtract = _AutoItObject_CLSIDFromString($sIID_IExtractImage)
    If StringInStr(FileGetAttrib($sFileName), "D", 1) Then
        MsgBox(0, '', "Cannot create preview for Folders on Windows prior to Vista")
        Exit
    Else
        _SHBindToParent($pidl, DllStructGetPtr($tRIID), $pIShellFolder, $pRelative)
        $IShellFolder = _AutoItObject_WrapperCreate($pIShellFolder, $dtagIShellFolder)

        $tSTRRET = DllStructCreate("uint uType;ptr data;")
        $r = $IShellFolder.GetDisplayNameOf(Number($pRelative), 0, Number(DllStructGetPtr($tSTRRET)))

        Dim $name
        _StrRetToBuf(DllStructGetPtr($tSTRRET), 0, $name, 512)
        $tSTRRET = 0

        MsgBox(0, 'name of item', $name)

        $tArray = DllStructCreate("ptr")
        DllStructSetData($tArray, 1, $pRelative)

        $r = $IShellFolder.GetUIObjectOf(0, 1, Number(DllStructGetPtr($tArray)), Number(DllStructGetPtr($tRIIDExtract)), 0, 0)
        $IExtractImage = _AutoItObject_WrapperCreate($r[6], $dtagIExtractImage)
    EndIf
    $tSize = DllStructCreate("long;long")
    DllStructSetData($tSize, 1, 128)
    DllStructSetData($tSize, 2, 128)
    $r = $IExtractImage.GetLocation("", 1024, 0, Number(DllStructGetPtr($tSize)), 32, 0)
    MsgBox(0, '', $r[1])
    $r = $IExtractImage.Extract(0)
    $hBmp = $r[1]


    $IShellFolder = 0
    _WinAPI_CoTaskMemFree($pidl)
EndIf


$tBMP = DllStructCreate($tagBITMAP)
Global $bmWidth = 128, $bmHeight = 128
If _WinAPI_GetObject($hBmp, DllStructGetSize($tBMP), DllStructGetPtr($tBMP)) Then _
    Global $bmWidth = DllStructGetData($tBMP, "bmWidth"), $bmHeight = Abs(DllStructGetData($tBMP, "bmHeight"))

$hGUI = GUICreate("test", 256, 128)
GUIRegisterMsg($WM_PAINT, "_WM_PAINT")
$btnColor = GUICtrlCreateButton("ColorChange", 130, 20, 100, 20)
$hDC = _WinAPI_GetDC(0)
$hDCB = _WinAPI_CreateCompatibleDC($hDC)
_WinAPI_SelectObject($hDCB, $hBmp)
_WinAPI_ReleaseDC(0, $hDC)


$IExtractImage = 0

GUISetState()
While 1
    Switch GUIGetMsg()
        Case -3
            ExitLoop
        Case $btnColor
            GUISetBkColor(Random(0, 0xFFFFFF, 1))
    EndSwitch
WEnd

Func _WM_PAINT($hWnd, $uMsg, $wParam, $lParam)
    Local $tPS
    Local $hDC = _WinAPI_BeginPaint($hWnd, $tPS)
    Local $x = DllStructGetData($tPS, "rPaint", 1)
    Local $y = DllStructGetData($tPS, "rPaint", 2)
    Local $x2 = DllStructGetData($tPS, "rPaint", 3)
    Local $y2 = DllStructGetData($tPS, "rPaint", 4)
    If $x <= 128 And $x2 >= 0 And $y <= 128 And $y2 >= 0 Then
        If $x2 > 128 Then $x2 = 128
        If $x < 0 Then $x = 0
        If $y < 0 Then $y = 0
        If $y2 > 128 Then $y2 = 128
        Local $ImgX = $x-0, $ImgY = $y-0
        If $bmWidth < 127 Then $x += Int((128-$bmWidth)/2)
        If $bmHeight < 127 Then $y += Int((128-$bmHeight)/2)
        Local $ImgW = $x2-$x, $ImgH = $y2-$y
        If $ImgW > $bmWidth Then $ImgW = $bmWidth
        If $ImgH > $bmHeight Then $ImgH = $bmHeight

        If $x < $x2 And $y < $y2 Then
            If $fUseAlphaBlend Then
                _WinAPI_AlphaBlend($hDC, $x, $y, $ImgW, $ImgH, $hDCB, $ImgX, $ImgY, $ImgW, $ImgH, 255, True)
            Else
                _WinAPI_BitBlt($hDC, $x, $y, $ImgW, $ImgH, $hDCB, $ImgX, $ImgY, $SRCCOPY)
            EndIf
        EndIf
    EndIf
    _WinAPI_EndPaint($hWnd, $tPS)
    Return $GUI_RUNDEFMSG
EndFunc   ;==>_WM_PAINT

Func _MakeUINT64($long1, $long2)
    Local $d = DllStructCreate("align 4;dword[2]")
    DllStructSetData($d, 1, $long1, 1)
    DllStructSetData($d, 1, $long2, 2)
    Return DllStructGetData(DllStructCreate("uint64", DllStructGetPtr($d)),1)
EndFunc

Func _SHCreateItemFromParsingName($szPath, $pbc, $riid, ByRef $pv)
    Local $aRes = DllCall("shell32.dll", "long", "SHCreateItemFromParsingName", "wstr", $szPath, "ptr", $pbc, "ptr", $riid, "ptr*", 0)
    If @error Then Return SetError(1, 0, 0)
    $pv = $aRes[4]
    Return $aRes[0]
EndFunc   ;==>_SHCreateItemFromParsingName
Func _SHBindToObject($psf, $pidl, $pbc, $riid, ByRef $pv)
    Local $aRes = DllCall("Shell32.dll", "long", "SHBindToObject", "ptr", $psf, "ptr", $pidl, "ptr", $pbc, "ptr", $riid, "ptr*", 0)
    If @error Then Return SetError(1, 0, 0)
    $pv = $aRes[5]
    Return $aRes[0]
EndFunc   ;==>_SHBindToObject
Func _SHBindToParent($pidl, $riid, ByRef $pv, ByRef $pidlLast)
    Local $aRes = DllCall("Shell32.dll", "long", "SHBindToParent", "ptr", $pidl, "ptr", $riid, "ptr*", 0, "ptr*", 0)
    If @error Then Return SetError(1, 0, 0)
    $pv = $aRes[3]
    $pidlLast = $aRes[4]
    Return $aRes[0]
EndFunc   ;==>_SHBindToParent
Func _StrRetToBuf($pSTRRET, $pidl, ByRef $sName, $iLength = 512)
    Local $aRes = DllCall("shlwapi.dll", "long", "StrRetToBufW", "ptr", $pSTRRET, "ptr", $pidl, "wstr", $sName, "uint", $iLength)
    If @error Then Return SetError(1, 0, 0)
    $sName = $aRes[3]
    Return $aRes[0]
EndFunc   ;==>_StrRetToBuf

*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

Share this post


Link to post
Share on other sites

#11 ·  Posted (edited)

KaFu, why do not use GDI+? Or you need a thumbnails not only for images?

Hi Yashied, yep, I want the have a thumbnail for every file, GDIs not enough :x (but part of the solution).

Andy, thanks for the heads up. Currently I'm working out the IShellItemImageFactory part for Win7. I want to add the bitmaps to an Imagelist to use with the Listview. Now I found this passage on google:

"Another thing to watch out for is that the API sometimes returns bitmaps that use pre-multiplied alpha and sometimes ones that use normal alpha, with no proper way (except heuristics, which can go wrong) to tell which. It's a pretty poor API. :P – Leo Davidson Dec 13 at 20:12"

Resizing already works quite good, but there indeed seem to be problems with certain Alpha values (background black for .png and .ico files).

Edit: Added jpg example (works fine too).

; http://www.autoitscript.com/forum/topic/123365-autoitobject-suitable-to-retrieve-iextractimage-interface-pointer-from-shellfolder/page__view__findpost__p__856882
; ProgAndy

#cs

    Another thing to watch out for is that the API sometimes returns bitmaps that use pre-multiplied alpha and sometimes ones that use normal alpha,
    with no proper way (except heuristics, which can go wrong) to tell which. It's a pretty poor API. :( – Leo Davidson Dec 13 at 20:12

#ce

#include <WindowsConstants.au3>
#include <Constants.au3>
#include <GDIPlus.au3>
#include <GUIConstantsEx.au3>
#include <GuiListView.au3>
#include <GuiImageList.au3>

#include<AutoItObject.au3>
#include<WinAPIEx.au3>

#include-once
;===============================================================================
#API "Extracting Image"
; IShellFolder
; IExtractImage
;===============================================================================

;.......written by ProgAndy

;===============================================================================
#interface "IShellFolder"
$sIID_IShellFolder = "{000214E6-0000-0000-C000-000000000046}"
; Definition
Global Const $dtagIShellFolder = $dtagIUnknown & _
        "ParseDisplayName hresult(hwnd;ptr;wstr;dword*;ptr*;dword*);" & _
        "EnumObjects hresult(hwnd;dword;ptr*);" & _
        "BindToObject hresult(ptr;ptr;ptr;ptr*);" & _
        "BindToStorage hresult(ptr;ptr;ptr;ptr*);" & _
        "CompareIDs hresult(lparam;ptr;ptr);" & _
        "CreateViewObject hresult(hwnd;ptr;ptr*);" & _
        "GetAttributesOf hresult(UINT;ptr;ulong*);" & _
        "GetUIObjectOf hresult(hwnd;uint;ptr;ptr;uint*;ptr*);" & _
        "GetDisplayNameOf hresult(ptr;uint;ptr);" & _
        "SetNameOf hresult(hwnd;ptr;wstr;dword;ptr*);"
; List
Global Const $ltagIShellFolder = $ltagIUnknown & _
        "ParseDisplayName;" & _
        "EnumObjects;" & _
        "BindToObject;" & _
        "BindToStorage;" & _
        "CompareIDs;" & _
        "CreateViewObject;" & _
        "GetAttributesOf;" & _
        "GetUIObjectOf;" & _
        "GetDisplayNameOf;" & _
        "SetNameOf;"
;===============================================================================


;===============================================================================
#interface "IExtractImage"
Global Const $sIID_IExtractImage = "{BB2E617C-0920-11d1-9A0B-00C04FC2D6C1}"
; Definition
Global Const $dtagIExtractImage = $dtagIUnknown & _
        "GetLocation hresult(wstr;DWORD;DWORD*;ptr;dword;DWORD*);" & _
        "Extract hresult(ptr*);"
; List
Global Const $ltagIExtractImage = $ltagIUnknown & _
        "GetLocation;" & _
        "Extract;"
;===============================================================================

;===============================================================================
#interface "IShellItemImageFactory"
Global Const $sIID_IShellItemImageFactory = "{bcc18b79-ba16-442f-80c4-8a59c30c463b}"
; Definition
Global Const $dtagIShellItemImageFactory = $dtagIUnknown & _
        "GetImage hresult(uint64;dword;ptr*);" ; <==== uint64 instead of long;long
; List
Global Const $ltagIShellItemImageFactory = $ltagIUnknown & _
        "GetImage;"
;===============================================================================

;===============================================================================
#interface "IShellItem"
Global Const $IID_IShellItem = "{43826d1e-e718-42ee-bc55-a1e261c37bfe}"
Global Const $dtagIShellItem = $dtagIUnknown & _
        "BindToHandler hresult(ptr;ptr;ptr;ptr*);" & _
        "GetParent hresult(ptr*);" & _
        "GetDisplayName hresult(dword;ptr*);" & _
        "GetAttributes hresult(dword;dword*);" & _
        "Compare hresult(ptr;dword;int*);"
Global Const $ltagIShellItem = $ltagIUnknown & _
        "BindToHandler;" & _
        "GetParent;" & _
        "GetDisplayName;" & _
        "GetAttributes;" & _
        "Compare;"
;===============================================================================


_AutoItObject_StartUp()

Global $h_IShellFolder_Bmp
Global $h_IShellFolder_DCB
Global $f_IShellFolder_UseAlphaBlend = False

Global $i_IShellFolder_Preview_Size = 128
OnAutoItExitRegister("_IShellFolder_Exit")
_GDIPlus_Startup()

$tIIDImgFact = _AutoItObject_CLSIDFromString($sIID_IShellItemImageFactory)

$sBaseDir = StringLeft(@AutoItExe, StringInStr(@AutoItExe, "\", 0, -1))
$sFileName1 = $sBaseDir & "Examples\GUI"
$sFileName2 = $sFileName1 & "\Advanced\Images\Blue.bmp"
$sFileName3 = $sFileName1 & "\merlin.gif"
$sFileName4 = $sFileName1 & "\Torus.png"
$sFileName5 = $sBaseDir & "icons\au3.ico"
$sFileName6 = $sFileName1 & "\mslogo.jpg"


#region LV-Example
GUICreate("ListView Set Image List", 500, 800)
$hListView = GUICtrlCreateListView("", 2, 2, 496, 796)
GUISetState()

; Load images
$hImage = _GUIImageList_Create($i_IShellFolder_Preview_Size, $i_IShellFolder_Preview_Size, 5, 3, 1)
_GUIImageList_Add($hImage, _IShellFolder_Extract_hBMP($sFileName1))
_GUIImageList_Add($hImage, _IShellFolder_Extract_hBMP($sFileName2))
_GUIImageList_Add($hImage, _IShellFolder_Extract_hBMP($sFileName3))
_GUIImageList_Add($hImage, _IShellFolder_Extract_hBMP($sFileName4))
_GUIImageList_Add($hImage, _IShellFolder_Extract_hBMP($sFileName5))
_GUIImageList_Add($hImage, _IShellFolder_Extract_hBMP($sFileName6))
_GUICtrlListView_SetImageList($hListView, $hImage, 1)

; Add columns
_GUICtrlListView_AddColumn($hListView, "Filename", 400)

; Add items
_GUICtrlListView_AddItem($hListView, $sFileName1, 0)
_GUICtrlListView_AddItem($hListView, $sFileName2, 1)
_GUICtrlListView_AddItem($hListView, $sFileName3, 2)
_GUICtrlListView_AddItem($hListView, $sFileName4, 3)
_GUICtrlListView_AddItem($hListView, $sFileName5, 4)
_GUICtrlListView_AddItem($hListView, $sFileName6, 5)

; Loop until user exits
Do
Until GUIGetMsg() = $GUI_EVENT_CLOSE
GUIDelete()
#endregion LV-Example


Func _IShellFolder_Exit()
    _GDIPlus_Shutdown ()
    _WinAPI_DeleteObject($h_IShellFolder_Bmp)
    _AutoItObject_Shutdown()
EndFunc   ;==>_IShellFolder_Exit

Func _IShellFolder_Extract_hBMP($sFileName)
    If Not FileExists($sFileName) Then Return SetError(1)
    If IsHWnd($h_IShellFolder_Bmp) Then _WinAPI_DeleteObject($h_IShellFolder_Bmp)

    Dim $pImgFact

    If 0 = _IShellFolder_SHCreateItemFromParsingName($sFileName, 0, DllStructGetPtr($tIIDImgFact), $pImgFact) And $pImgFact Then
        $IImgFact = _AutoItObject_WrapperCreate($pImgFact, $dtagIShellItemImageFactory)
        $r = $IImgFact.GetImage(_IShellFolder_MakeUINT64($i_IShellFolder_Preview_Size, $i_IShellFolder_Preview_Size), 8, 0) ; <==== _IShellFolder_MakeUINT64 added
        ConsoleWrite($sFileName & @tab & $r[3] & @crlf)
        If $r[3] = 0 Or StringInStr(FileGetAttrib($sFileName), "D") Then ; no thumbnail available OR target is folder
            $r = $IImgFact.GetImage(_IShellFolder_MakeUINT64($i_IShellFolder_Preview_Size, $i_IShellFolder_Preview_Size), 0, 0) ; <==== _IShellFolder_MakeUINT64 added
            $h_IShellFolder_Bmp = $r[3]
        Else
            $r = $IImgFact.GetImage(_IShellFolder_MakeUINT64($i_IShellFolder_Preview_Size, $i_IShellFolder_Preview_Size), 1, 0) ; <==== _IShellFolder_MakeUINT64 added
            $h_IShellFolder_Bmp = _IShellFolder_GetImage($r[3], $i_IShellFolder_Preview_Size, $i_IShellFolder_Preview_Size)
        EndIf
        ;EndIf
    Else
        $pidl = _IShellFolder_ILCreateFromPath($sFileName)
        Dim $pIShellFolder, $pRelative
        $tRIID = _AutoItObject_CLSIDFromString($sIID_IShellFolder)
        $tRIIDExtract = _AutoItObject_CLSIDFromString($sIID_IExtractImage)
        If StringInStr(FileGetAttrib($sFileName), "D", 1) Then
            Return 1
            ;MsgBox(0, '', "Cannot create preview for Folders on Windows prior to Vista")
            ;Exit
        Else
            _SHBindToParent($pidl, DllStructGetPtr($tRIID), $pIShellFolder, $pRelative)
            $IShellFolder = _AutoItObject_WrapperCreate($pIShellFolder, $dtagIShellFolder)

            $tSTRRET = DllStructCreate("uint uType;ptr data;")
            $r = $IShellFolder.GetDisplayNameOf(Number($pRelative), 0, Number(DllStructGetPtr($tSTRRET)))

            Dim $name
            _IShellFolder_StrRetToBuf(DllStructGetPtr($tSTRRET), 0, $name, 512)
            $tSTRRET = 0

            ;MsgBox(0, 'name of item', $name)

            $tArray = DllStructCreate("ptr")
            DllStructSetData($tArray, 1, $pRelative)

            $r = $IShellFolder.GetUIObjectOf(0, 1, Number(DllStructGetPtr($tArray)), Number(DllStructGetPtr($tRIIDExtract)), 0, 0)
            $IExtractImage = _AutoItObject_WrapperCreate($r[6], $dtagIExtractImage)
        EndIf
        $tSize = DllStructCreate("long;long")
        DllStructSetData($tSize, 1, $i_IShellFolder_Preview_Size)
        DllStructSetData($tSize, 2, $i_IShellFolder_Preview_Size)
        $r = $IExtractImage.GetLocation("", 1024, 0, Number(DllStructGetPtr($tSize)), 32, 0)
        ;MsgBox(0, '', $r[1])
        $r = $IExtractImage.Extract(0)
        $h_IShellFolder_Bmp = $r[1]

        $IShellFolder = 0
        _IShellFolder_CoTaskMemFree($pidl)
    EndIf

    $IExtractImage = 0

    Return $h_IShellFolder_Bmp

EndFunc   ;==>_IShellFolder_Extract_hBMP

Func _IShellFolder_GetImage($hBmp_Source, $i_TargetWidth = 32, $i_TargetHeight = 32)
    Local $hBmp1, $hBitmap, $hGraphic, $hImage, $iW, $iH, $aGS, $hBmp2

    $hBmp1 = _WinAPI_CreateBitmap($i_TargetWidth, $i_TargetHeight, 1, 32)
    $hBitmap = _GDIPlus_BitmapCreateFromHBITMAP($hBmp1)
    $hGraphic = _GDIPlus_ImageGetGraphicsContext($hBitmap)
    _WinAPI_DeleteObject($hBmp1)

    _GDIPlus_GraphicsClear($hGraphic, 0xFFFFFFFF)

    $hImage = _GDIPlus_BitmapCreateFromHBITMAP($hBmp_Source)
    $iW = _GDIPlus_ImageGetWidth($hImage)
    $iH = _GDIPlus_ImageGetHeight($hImage)
    $aGS = _IShellFolder_GetScale($iW, $iH, $i_TargetWidth)
    _GDIPlus_GraphicsDrawImageRect($hGraphic, $hImage, $aGS[0], $aGS[1], $aGS[2], $aGS[3])
    _GDIPlus_ImageDispose($hImage)
    _GDIPlus_GraphicsDispose($hGraphic)

    $hBmp2 = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBitmap)
    _GDIPlus_BitmapDispose($hBitmap)

    Return $hBmp2
EndFunc   ;==>_IShellFolder_GetImage

Func _IShellFolder_GetScale($iW, $iH, $i_TargetWidth)
    Local $aRet[4]
    If $iW <= $i_TargetWidth And $iH <= $i_TargetWidth Then
        $aRet[2] = $iW
        $aRet[3] = $iH
        $aRet[0] = ($i_TargetWidth - $aRet[2]) / 2
        $aRet[1] = ($i_TargetWidth - $aRet[3]) / 2
    ElseIf $iW > $iH Then
        $aRet[2] = $i_TargetWidth
        $aRet[3] = $iH / ($iW / $i_TargetWidth)
        $aRet[0] = 0
        $aRet[1] = ($i_TargetWidth - $aRet[3]) / 2
    ElseIf $iW < $iH Then
        $aRet[2] = $iW / ($iH / $i_TargetWidth)
        $aRet[3] = $i_TargetWidth
        $aRet[0] = ($i_TargetWidth - $aRet[2]) / 2
        $aRet[1] = 0
    ElseIf $iW = $iH Then
        $aRet[2] = $i_TargetWidth
        $aRet[3] = $i_TargetWidth
        $aRet[0] = 0
        $aRet[1] = 0
    EndIf
    Return $aRet
EndFunc   ;==>_IShellFolder_GetScale


#cs
    Func _WM_PAINT($hWnd, $uMsg, $wParam, $lParam)
    Local $tPS
    Local $hDC = _WinAPI_BeginPaint($hWnd, $tPS)
    $x = DllStructGetData($tPS, "rPaint", 1)
    $y = DllStructGetData($tPS, "rPaint", 2)
    $w = DllStructGetData($tPS, "rPaint", 3) - $x
    $h = DllStructGetData($tPS, "rPaint", 4) - $y
    If $x <= 128 Then
    If $x + $w > 128 Then $w = 128 - $x
    If $f_IShellFolder_UseAlphaBlend Then
    _WinAPI_AlphaBlend($hDC, $x, $y, $w, $h, $h_IShellFolder_DCB, $x, $y, $w, $h, 255, True)
    Else
    _WinAPI_BitBlt($hDC, $x, $y, $w, $h, $h_IShellFolder_DCB, $x, $y, $SRCCOPY)
    EndIf
    EndIf
    _WinAPI_EndPaint($hWnd, $tPS)
    Return $GUI_RUNDEFMSG
    EndFunc   ;==>_WM_PAINT
#ce

Func _IShellFolder_MakeUINT64($long1, $long2)
    Local $d = DllStructCreate("align 4;dword[2]")
    DllStructSetData($d, 1, $long1, 1)
    DllStructSetData($d, 1, $long2, 2)
    Return DllStructGetData(DllStructCreate("uint64", DllStructGetPtr($d)), 1)
EndFunc   ;==>_IShellFolder_MakeUINT64

Func _IShellFolder_CoTaskMemFree($pMem)
    Local $aRes = DllCall("Ole32.dll", "none", "CoTaskMemFree", "ptr", $pMem)
    If @error Then SetError(1)
EndFunc   ;==>_IShellFolder_CoTaskMemFree

Func _IShellFolder_ILCreateFromPath($sPath)
    Local $aRes = DllCall("shell32.dll", "ptr", "ILCreateFromPathW", "wstr", $sPath)
    If @error Then Return SetError(1, 0, 0)
    Return $aRes[0]
EndFunc   ;==>_IShellFolder_ILCreateFromPath

Func _IShellFolder_SHCreateItemFromParsingName($szPath, $pbc, $riid, ByRef $pv)
    Local $aRes = DllCall("shell32.dll", "long", "SHCreateItemFromParsingName", "wstr", $szPath, "ptr", $pbc, "ptr", $riid, "ptr*", 0)
    If @error Then Return SetError(1, 0, 0)
    $pv = $aRes[4]
    Return $aRes[0]
EndFunc   ;==>_IShellFolder_SHCreateItemFromParsingName

Func _IShellFolder_SHBindToObject($psf, $pidl, $pbc, $riid, ByRef $pv)
    Local $aRes = DllCall("Shell32.dll", "long", "SHBindToObject", "ptr", $psf, "ptr", $pidl, "ptr", $pbc, "ptr", $riid, "ptr*", 0)
    If @error Then Return SetError(1, 0, 0)
    $pv = $aRes[5]
    Return $aRes[0]
EndFunc   ;==>_IShellFolder_SHBindToObject

Func _SHBindToParent($pidl, $riid, ByRef $pv, ByRef $pidlLast)
    Local $aRes = DllCall("Shell32.dll", "long", "SHBindToParent", "ptr", $pidl, "ptr", $riid, "ptr*", 0, "ptr*", 0)
    If @error Then Return SetError(1, 0, 0)
    $pv = $aRes[3]
    $pidlLast = $aRes[4]
    Return $aRes[0]
EndFunc   ;==>_SHBindToParent

Func _IShellFolder_StrRetToBuf($pSTRRET, $pidl, ByRef $sName, $iLength = 512)
    Local $aRes = DllCall("shlwapi.dll", "long", "StrRetToBufW", "ptr", $pSTRRET, "ptr", $pidl, "wstr", $sName, "uint", $iLength)
    If @error Then Return SetError(1, 0, 0)
    $sName = $aRes[3]
    Return $aRes[0]
EndFunc   ;==>_IShellFolder_StrRetToBuf
Edited by KaFu

Share this post


Link to post
Share on other sites

#12 ·  Posted (edited)

Sooo, after playing around with IExtractImage (used for XP) I came up with an update example.

On XP it will show the same GUI two times. On Vista+ the first example is created with the IShellItemImageFactory interface and the second with the IExtractImage interface. I added replacements of the thumbnails in IExtractImage with the corresponding icons, if the thumbnail could not be created (Directories, other files without a preview (e.g. the .chm file)).

Overall it already looks really good, but there's an alpha (? - default background color, should be white) problem in IShellItemImageFactory and IExtractImage too (or I'm messing up at some point and do not realize it :x ).

#region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_UseUpx=n
#AutoIt3Wrapper_UseX64=n
#endregion ;**** Directives created by AutoIt3Wrapper_GUI ****
; http://www.autoitscript.com/forum/topic/123365-autoitobject-suitable-to-retrieve-iextractimage-interface-pointer-from-shellfolder/page__view__findpost__p__856882
; ProgAndy

#cs

    Another thing to watch out for is that the API sometimes returns bitmaps that use pre-multiplied alpha and sometimes ones that use normal alpha,
    with no proper way (except heuristics, which can go wrong) to tell which. It's a pretty poor API. :( – Leo Davidson Dec 13 at 20:12

#ce

#include <WindowsConstants.au3>
#include <Constants.au3>
#include <GDIPlus.au3>
#include <GUIConstantsEx.au3>
#include <GuiListView.au3>
#include <GuiImageList.au3>

#include<AutoItObject.au3>
#include<WinAPIEx.au3>

#include-once
;===============================================================================
#API "Extracting Image"
; IShellFolder
; IExtractImage
;===============================================================================

;.......written by ProgAndy

;===============================================================================
#interface "IShellFolder"
$sIID_IShellFolder = "{000214E6-0000-0000-C000-000000000046}"
; Definition
Global Const $dtagIShellFolder = $dtagIUnknown & _
        "ParseDisplayName hresult(hwnd;ptr;wstr;dword*;ptr*;dword*);" & _
        "EnumObjects hresult(hwnd;dword;ptr*);" & _
        "BindToObject hresult(ptr;ptr;ptr;ptr*);" & _
        "BindToStorage hresult(ptr;ptr;ptr;ptr*);" & _
        "CompareIDs hresult(lparam;ptr;ptr);" & _
        "CreateViewObject hresult(hwnd;ptr;ptr*);" & _
        "GetAttributesOf hresult(UINT;ptr;ulong*);" & _
        "GetUIObjectOf hresult(hwnd;uint;ptr;ptr;uint*;ptr*);" & _
        "GetDisplayNameOf hresult(ptr;uint;ptr);" & _
        "SetNameOf hresult(hwnd;ptr;wstr;dword;ptr*);"
; List
Global Const $ltagIShellFolder = $ltagIUnknown & _
        "ParseDisplayName;" & _
        "EnumObjects;" & _
        "BindToObject;" & _
        "BindToStorage;" & _
        "CompareIDs;" & _
        "CreateViewObject;" & _
        "GetAttributesOf;" & _
        "GetUIObjectOf;" & _
        "GetDisplayNameOf;" & _
        "SetNameOf;"
;===============================================================================


;===============================================================================
#interface "IExtractImage"
Global Const $sIID_IExtractImage = "{BB2E617C-0920-11d1-9A0B-00C04FC2D6C1}"
; Definition
Global Const $dtagIExtractImage = $dtagIUnknown & _
        "GetLocation hresult(wstr;DWORD;DWORD*;ptr;dword;DWORD*);" & _
        "Extract hresult(ptr*);"
; List
Global Const $ltagIExtractImage = $ltagIUnknown & _
        "GetLocation;" & _
        "Extract;"
;===============================================================================

;===============================================================================
#interface "IShellItemImageFactory"
Global Const $sIID_IShellItemImageFactory = "{bcc18b79-ba16-442f-80c4-8a59c30c463b}"
; Definition
Global Const $dtagIShellItemImageFactory = $dtagIUnknown & _
        "GetImage hresult(uint64;dword;ptr*);" ; <==== uint64 instead of long;long
; List
Global Const $ltagIShellItemImageFactory = $ltagIUnknown & _
        "GetImage;"
;===============================================================================

;===============================================================================
#interface "IShellItem"
Global Const $IID_IShellItem = "{43826d1e-e718-42ee-bc55-a1e261c37bfe}"
Global Const $dtagIShellItem = $dtagIUnknown & _
        "BindToHandler hresult(ptr;ptr;ptr;ptr*);" & _
        "GetParent hresult(ptr*);" & _
        "GetDisplayName hresult(dword;ptr*);" & _
        "GetAttributes hresult(dword;dword*);" & _
        "Compare hresult(ptr;dword;int*);"
Global Const $ltagIShellItem = $ltagIUnknown & _
        "BindToHandler;" & _
        "GetParent;" & _
        "GetDisplayName;" & _
        "GetAttributes;" & _
        "Compare;"
;===============================================================================


_AutoItObject_StartUp()

Global $h_IShellFolder_Bmp
Global $h_IShellFolder_DCB

Global $b_IExtractImage_Force = False ; default is to use IShellItemImageFactory if available (Vista+) or IExtractImage on older system (XP), set to true to force IExtractImage usage on Vista+

Global $i_IShellFolder_Preview_Size = 48
OnAutoItExitRegister("_IShellFolder_Exit")
_GDIPlus_Startup()

$tIIDImgFact = _AutoItObject_CLSIDFromString($sIID_IShellItemImageFactory)

_LV_Example()
$b_IExtractImage_Force = True
_LV_Example()

Func _LV_Example()

    $sBaseDir = StringLeft(@AutoItExe, StringInStr(@AutoItExe, "\", 0, -1))
    $sFileName1 = $sBaseDir & "Examples\GUI"
    $sFileName2 = $sFileName1 & "\Advanced\Images\Blue.bmp"
    $sFileName3 = $sFileName1 & "\merlin.gif"
    $sFileName4 = $sFileName1 & "\Torus.png"
    $sFileName5 = $sBaseDir & "icons\au3.ico"
    $sFileName6 = $sFileName1 & "\mslogo.jpg"
    $sFileName7 = $sBaseDir & "AutoIt.chm"

    #region LV-Example
    Switch $b_IExtractImage_Force
        Case True
            GUICreate("ListView Example - IExtractImage Interface", 500, 800)
        Case Else
            GUICreate("ListView Example - IShellItemImageFactory Interface", 500, 800)
    EndSwitch

    $hListView = GUICtrlCreateListView("", 2, 2, 496, 796)
    GUISetState()

    ; Load images
    $hImage = _GUIImageList_Create($i_IShellFolder_Preview_Size, $i_IShellFolder_Preview_Size, 5, 3, 1)
    _IShellFolder_GUIImageList_Add($hImage, $sFileName1)
    _IShellFolder_GUIImageList_Add($hImage, $sFileName2)
    _IShellFolder_GUIImageList_Add($hImage, $sFileName3)
    _IShellFolder_GUIImageList_Add($hImage, $sFileName4)
    _IShellFolder_GUIImageList_Add($hImage, $sFileName5)
    _IShellFolder_GUIImageList_Add($hImage, $sFileName6)
    _IShellFolder_GUIImageList_Add($hImage, $sFileName7)
    _GUICtrlListView_SetImageList($hListView, $hImage, 1)

    ; Add columns
    _GUICtrlListView_AddColumn($hListView, "Filename", 400)

    ; Add items
    _GUICtrlListView_AddItem($hListView, $sFileName1, 0)
    _GUICtrlListView_AddItem($hListView, $sFileName2, 1)
    _GUICtrlListView_AddItem($hListView, $sFileName3, 2)
    _GUICtrlListView_AddItem($hListView, $sFileName4, 3)
    _GUICtrlListView_AddItem($hListView, $sFileName5, 4)
    _GUICtrlListView_AddItem($hListView, $sFileName6, 5)
    _GUICtrlListView_AddItem($hListView, $sFileName7, 6)

    ; Loop until user exits
    Do
    Until GUIGetMsg() = $GUI_EVENT_CLOSE
    GUIDelete()
    #endregion LV-Example
EndFunc   ;==>_LV_Example

Func _IShellFolder_Exit()
    _GDIPlus_Shutdown()
    _WinAPI_DeleteObject($h_IShellFolder_Bmp)
    _AutoItObject_Shutdown()
EndFunc   ;==>_IShellFolder_Exit

Func _IShellFolder_GUIImageList_Add($hIML, $sFilename)
    $hBMP = _IShellFolder_Extract_hBMP($sFilename)
    Switch $hBMP
        Case 1 ; Folder under XP
            If $i_IShellFolder_Preview_Size >= 48 Then
                _GUIImageList_AddIcon($hIML, @SystemDir & "\shell32.dll", 3, True)
            Else
                _GUIImageList_AddIcon($hIML, @SystemDir & "\shell32.dll", 3, False)
            EndIf
        Case 2 ;
            If $i_IShellFolder_Preview_Size >= 48 Then
                $hIcon = _WinAPI_ShellExtractAssociatedIcon($sFilename, 0)
                _GUIImageList_ReplaceIcon($hIML, -1, $hIcon)
                _WinAPI_DestroyIcon($hIcon)
            Else
                $hIcon = _WinAPI_ShellExtractAssociatedIcon($sFilename, 1)
                _GUIImageList_ReplaceIcon($hIML, -1, $hIcon)
                _WinAPI_DestroyIcon($hIcon)
            EndIf
        Case Else
            _GUIImageList_Add($hIML, $hBMP)
    EndSwitch
EndFunc   ;==>_IShellFolder_GUIImageList_Add

Func _IShellFolder_Extract_hBMP($sFilename)
    If Not FileExists($sFilename) Then Return SetError(1)
    If IsHWnd($h_IShellFolder_Bmp) Then _WinAPI_DeleteObject($h_IShellFolder_Bmp)

    Dim $pImgFact

    If 0 = _IShellFolder_SHCreateItemFromParsingName($sFilename, 0, DllStructGetPtr($tIIDImgFact), $pImgFact) And $pImgFact And Not $b_IExtractImage_Force Then
        $IImgFact = _AutoItObject_WrapperCreate($pImgFact, $dtagIShellItemImageFactory)
        $r = $IImgFact.GetImage(_IShellFolder_MakeUINT64($i_IShellFolder_Preview_Size, $i_IShellFolder_Preview_Size), 8, 0) ; <==== _IShellFolder_MakeUINT64 added
        ;ConsoleWrite($sFileName & @TAB & $r[3] & @CRLF)
        If $r[3] = 0 Or StringInStr(FileGetAttrib($sFilename), "D") Then ; no thumbnail available OR target is folder
            $r = $IImgFact.GetImage(_IShellFolder_MakeUINT64($i_IShellFolder_Preview_Size, $i_IShellFolder_Preview_Size), 0, 0) ; <==== _IShellFolder_MakeUINT64 added
            $h_IShellFolder_Bmp = $r[3]
        Else
            $r = $IImgFact.GetImage(_IShellFolder_MakeUINT64($i_IShellFolder_Preview_Size, $i_IShellFolder_Preview_Size), 1, 0) ; <==== _IShellFolder_MakeUINT64 added
            $h_IShellFolder_Bmp = _IShellFolder_GetImage($r[3], $i_IShellFolder_Preview_Size, $i_IShellFolder_Preview_Size)
        EndIf
        ;EndIf
    Else
        $pidl = _IShellFolder_ILCreateFromPath($sFilename)
        Dim $pIShellFolder, $pRelative
        $tRIID = _AutoItObject_CLSIDFromString($sIID_IShellFolder)
        $tRIIDExtract = _AutoItObject_CLSIDFromString($sIID_IExtractImage)
        ;ConsoleWrite($pidl & @crlf)
        If StringInStr(FileGetAttrib($sFilename), "D", 1) Then
            _IShellFolder_CoTaskMemFree($pidl)
            Return 1
            ;MsgBox(0, '', "Cannot create preview for Folders on Windows prior to Vista")
            ;Exit
        Else
            _SHBindToParent($pidl, DllStructGetPtr($tRIID), $pIShellFolder, $pRelative)
            $IShellFolder = _AutoItObject_WrapperCreate($pIShellFolder, $dtagIShellFolder)
            ;ConsoleWrite(IsObj($IShellFolder) & @crlf)

            $tSTRRET = DllStructCreate("uint uType;ptr data;")
            $r = $IShellFolder.GetDisplayNameOf(Number($pRelative), 0, Number(DllStructGetPtr($tSTRRET)))

            Dim $name
            _IShellFolder_StrRetToBuf(DllStructGetPtr($tSTRRET), 0, $name, 512)
            $tSTRRET = 0

            ;MsgBox(0, 'name of item', $name)

            $tArray = DllStructCreate("ptr")
            DllStructSetData($tArray, 1, $pRelative)

            $r = $IShellFolder.GetUIObjectOf(0, 1, Number(DllStructGetPtr($tArray)), Number(DllStructGetPtr($tRIIDExtract)), 0, 0)
            $IExtractImage = _AutoItObject_WrapperCreate($r[6], $dtagIExtractImage)
        EndIf

        If Not IsObj($IExtractImage) Then
            Return 2
        Else
            $tSize = DllStructCreate("long;long")
            DllStructSetData($tSize, 1, $i_IShellFolder_Preview_Size)
            DllStructSetData($tSize, 2, $i_IShellFolder_Preview_Size)
            $r = $IExtractImage.GetLocation("", 1024, 0, Number(DllStructGetPtr($tSize)), 32, 0x0020 + 0x0200) ;IEIFLAG_SCREEN + IEIFLAG_QUALITY
            ;MsgBox(0, '', $r[1])
            $r = $IExtractImage.Extract(0)
            $h_IShellFolder_Bmp = $r[1]

            ; ConsoleWrite($name & @TAB & $h_IShellFolder_Bmp & @CRLF)

            $IShellFolder = 0
            _IShellFolder_CoTaskMemFree($pidl)

            $h_IShellFolder_Bmp2 = _IShellFolder_GetImage($h_IShellFolder_Bmp, $i_IShellFolder_Preview_Size, $i_IShellFolder_Preview_Size)
            _WinAPI_DeleteObject($h_IShellFolder_Bmp)
            $h_IShellFolder_Bmp = $h_IShellFolder_Bmp2
        EndIf
    EndIf

    $IExtractImage = 0

    Return $h_IShellFolder_Bmp

EndFunc   ;==>_IShellFolder_Extract_hBMP

Func _IShellFolder_GetImage($hBmp_Source, $i_TargetWidth = 32, $i_TargetHeight = 32)
    Local $hBmp1, $hBitmap, $hGraphic, $hImage, $iW, $iH, $aGS, $hBmp2

    $hBmp1 = _WinAPI_CreateBitmap($i_TargetWidth, $i_TargetHeight, 1, 32)
    $hBitmap = _GDIPlus_BitmapCreateFromHBITMAP($hBmp1)
    $hGraphic = _GDIPlus_ImageGetGraphicsContext($hBitmap)
    _WinAPI_DeleteObject($hBmp1)

    _GDIPlus_GraphicsClear($hGraphic, 0xFFFFFFFF)

    $hImage = _GDIPlus_BitmapCreateFromHBITMAP($hBmp_Source)
    $iW = _GDIPlus_ImageGetWidth($hImage)
    $iH = _GDIPlus_ImageGetHeight($hImage)
    $aGS = _IShellFolder_GetScale($iW, $iH, $i_TargetWidth)
    _GDIPlus_GraphicsDrawImageRect($hGraphic, $hImage, $aGS[0], $aGS[1], $aGS[2], $aGS[3])
    _GDIPlus_ImageDispose($hImage)
    _GDIPlus_GraphicsDispose($hGraphic)

    $hBmp2 = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBitmap)
    _GDIPlus_BitmapDispose($hBitmap)

    Return $hBmp2
EndFunc   ;==>_IShellFolder_GetImage

Func _IShellFolder_GetScale($iW, $iH, $i_TargetWidth)
    Local $aRet[4]
    If $iW <= $i_TargetWidth And $iH <= $i_TargetWidth Then
        $aRet[2] = $iW
        $aRet[3] = $iH
        $aRet[0] = ($i_TargetWidth - $aRet[2]) / 2
        $aRet[1] = ($i_TargetWidth - $aRet[3]) / 2
    ElseIf $iW > $iH Then
        $aRet[2] = $i_TargetWidth
        $aRet[3] = $iH / ($iW / $i_TargetWidth)
        $aRet[0] = 0
        $aRet[1] = ($i_TargetWidth - $aRet[3]) / 2
    ElseIf $iW < $iH Then
        $aRet[2] = $iW / ($iH / $i_TargetWidth)
        $aRet[3] = $i_TargetWidth
        $aRet[0] = ($i_TargetWidth - $aRet[2]) / 2
        $aRet[1] = 0
    ElseIf $iW = $iH Then
        $aRet[2] = $i_TargetWidth
        $aRet[3] = $i_TargetWidth
        $aRet[0] = 0
        $aRet[1] = 0
    EndIf
    Return $aRet
EndFunc   ;==>_IShellFolder_GetScale


Func _IShellFolder_MakeUINT64($long1, $long2)
    Local $d = DllStructCreate("align 4;dword[2]")
    DllStructSetData($d, 1, $long1, 1)
    DllStructSetData($d, 1, $long2, 2)
    Return DllStructGetData(DllStructCreate("uint64", DllStructGetPtr($d)), 1)
EndFunc   ;==>_IShellFolder_MakeUINT64

Func _IShellFolder_CoTaskMemFree($pMem)
    Local $aRes = DllCall("Ole32.dll", "none", "CoTaskMemFree", "ptr", $pMem)
    If @error Then SetError(1)
EndFunc   ;==>_IShellFolder_CoTaskMemFree

Func _IShellFolder_ILCreateFromPath($sPath)
    Local $aRes = DllCall("shell32.dll", "ptr", "ILCreateFromPathW", "wstr", $sPath)
    If @error Then Return SetError(1, 0, 0)
    Return $aRes[0]
EndFunc   ;==>_IShellFolder_ILCreateFromPath

Func _IShellFolder_SHCreateItemFromParsingName($szPath, $pbc, $riid, ByRef $pv)
    Local $aRes = DllCall("shell32.dll", "long", "SHCreateItemFromParsingName", "wstr", $szPath, "ptr", $pbc, "ptr", $riid, "ptr*", 0)
    If @error Then Return SetError(1, 0, 0)
    $pv = $aRes[4]
    Return $aRes[0]
EndFunc   ;==>_IShellFolder_SHCreateItemFromParsingName

Func _IShellFolder_SHBindToObject($psf, $pidl, $pbc, $riid, ByRef $pv)
    Local $aRes = DllCall("Shell32.dll", "long", "SHBindToObject", "ptr", $psf, "ptr", $pidl, "ptr", $pbc, "ptr", $riid, "ptr*", 0)
    If @error Then Return SetError(1, 0, 0)
    $pv = $aRes[5]
    Return $aRes[0]
EndFunc   ;==>_IShellFolder_SHBindToObject

Func _SHBindToParent($pidl, $riid, ByRef $pv, ByRef $pidlLast)
    Local $aRes = DllCall("Shell32.dll", "long", "SHBindToParent", "ptr", $pidl, "ptr", $riid, "ptr*", 0, "ptr*", 0)
    If @error Then Return SetError(1, 0, 0)
    $pv = $aRes[3]
    $pidlLast = $aRes[4]
    Return $aRes[0]
EndFunc   ;==>_SHBindToParent

Func _IShellFolder_StrRetToBuf($pSTRRET, $pidl, ByRef $sName, $iLength = 512)
    Local $aRes = DllCall("shlwapi.dll", "long", "StrRetToBufW", "ptr", $pSTRRET, "ptr", $pidl, "wstr", $sName, "uint", $iLength)
    If @error Then Return SetError(1, 0, 0)
    $sName = $aRes[3]
    Return $aRes[0]
EndFunc   ;==>_IShellFolder_StrRetToBuf
Edited by KaFu

Share this post


Link to post
Share on other sites

_GDIPlus_BitmapCreateFromHBITMAP does not take care of premultiplied alpha or "normal" alpha-channels.

You have to use GetDIBits, check whether to create the GDI+-image premultiplied or not, then use GDI+-LockBits and copy all Bitmapdata from the GDI-DIB to the GDI+-Bitmap manually. then UnlockBits and free the GDI-Bitmap and you should have a transparent GDI+-Bitmap.

Of course you could manipulate the DIBits and use SetDIBits to set them Back to the GDI32-Hbitmap (e.g. premulitply them or merge with background-coor) if you don't need GDI+.


*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

Share this post


Link to post
Share on other sites

Took a while, I'm not that good with graphics yet :x, thanks god it Christmas :P. Thanks to Andy for the heads-up and Yashied for his excellent _WinAPI_AlphaBlend() example in the WinApiEx UDF help-file!

#region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_UseUpx=n
#AutoIt3Wrapper_UseX64=n
#endregion ;**** Directives created by AutoIt3Wrapper_GUI ****
; http://www.autoitscript.com/forum/topic/123365-autoitobject-suitable-to-retrieve-iextractimage-interface-pointer-from-shellfolder/page__view__findpost__p__856882
; ProgAndy

#cs

    Another thing to watch out for is that the API sometimes returns bitmaps that use pre-multiplied alpha and sometimes ones that use normal alpha,
    with no proper way (except heuristics, which can go wrong) to tell which. It's a pretty poor API. :( – Leo Davidson Dec 13 at 20:12

#ce

#include <WindowsConstants.au3>
#include <Constants.au3>
#include <GDIPlus.au3>
#include <GUIConstantsEx.au3>
#include <GuiListView.au3>
#include <GuiImageList.au3>

#include<SMF_Func_AutoItObject.au3>
#include<SMF_Func_WinAPIEx_v3.0.au3>

#include-once
;===============================================================================
#API "Extracting Image"
; IShellFolder
; IExtractImage
;===============================================================================

;.......written by ProgAndy

;===============================================================================
#interface "IShellFolder"
$sIID_IShellFolder = "{000214E6-0000-0000-C000-000000000046}"
; Definition
Global Const $dtagIShellFolder = $dtagIUnknown & _
        "ParseDisplayName hresult(hwnd;ptr;wstr;dword*;ptr*;dword*);" & _
        "EnumObjects hresult(hwnd;dword;ptr*);" & _
        "BindToObject hresult(ptr;ptr;ptr;ptr*);" & _
        "BindToStorage hresult(ptr;ptr;ptr;ptr*);" & _
        "CompareIDs hresult(lparam;ptr;ptr);" & _
        "CreateViewObject hresult(hwnd;ptr;ptr*);" & _
        "GetAttributesOf hresult(UINT;ptr;ulong*);" & _
        "GetUIObjectOf hresult(hwnd;uint;ptr;ptr;uint*;ptr*);" & _
        "GetDisplayNameOf hresult(ptr;uint;ptr);" & _
        "SetNameOf hresult(hwnd;ptr;wstr;dword;ptr*);"
; List
Global Const $ltagIShellFolder = $ltagIUnknown & _
        "ParseDisplayName;" & _
        "EnumObjects;" & _
        "BindToObject;" & _
        "BindToStorage;" & _
        "CompareIDs;" & _
        "CreateViewObject;" & _
        "GetAttributesOf;" & _
        "GetUIObjectOf;" & _
        "GetDisplayNameOf;" & _
        "SetNameOf;"
;===============================================================================


;===============================================================================
#interface "IExtractImage"
Global Const $sIID_IExtractImage = "{BB2E617C-0920-11d1-9A0B-00C04FC2D6C1}"
; Definition
Global Const $dtagIExtractImage = $dtagIUnknown & _
        "GetLocation hresult(wstr;DWORD;DWORD*;ptr;dword;DWORD*);" & _
        "Extract hresult(ptr*);"
; List
Global Const $ltagIExtractImage = $ltagIUnknown & _
        "GetLocation;" & _
        "Extract;"
;===============================================================================

;===============================================================================
#interface "IShellItemImageFactory"
Global Const $sIID_IShellItemImageFactory = "{bcc18b79-ba16-442f-80c4-8a59c30c463b}"
; Definition
Global Const $dtagIShellItemImageFactory = $dtagIUnknown & _
        "GetImage hresult(uint64;dword;ptr*);" ; <==== uint64 instead of long;long
; List
Global Const $ltagIShellItemImageFactory = $ltagIUnknown & _
        "GetImage;"
;===============================================================================

;===============================================================================
#interface "IShellItem"
Global Const $IID_IShellItem = "{43826d1e-e718-42ee-bc55-a1e261c37bfe}"
Global Const $dtagIShellItem = $dtagIUnknown & _
        "BindToHandler hresult(ptr;ptr;ptr;ptr*);" & _
        "GetParent hresult(ptr*);" & _
        "GetDisplayName hresult(dword;ptr*);" & _
        "GetAttributes hresult(dword;dword*);" & _
        "Compare hresult(ptr;dword;int*);"
Global Const $ltagIShellItem = $ltagIUnknown & _
        "BindToHandler;" & _
        "GetParent;" & _
        "GetDisplayName;" & _
        "GetAttributes;" & _
        "Compare;"
;===============================================================================


_AutoItObject_StartUp()

Global $h_IShellFolder_Bmp
Global $h_IShellFolder_DCB

Global $b_IExtractImage_Force = False ; default is to use IShellItemImageFactory if available (Vista+) or IExtractImage on older system (XP), set to true to force IExtractImage usage on Vista+

Global $i_IShellFolder_Preview_Size = 48
OnAutoItExitRegister("_IShellFolder_Exit")
_GDIPlus_Startup()

$tIIDImgFact = _AutoItObject_CLSIDFromString($sIID_IShellItemImageFactory)

_LV_Example()
$b_IExtractImage_Force = True
_LV_Example()

Func _LV_Example()

    $sBaseDir = StringLeft(@AutoItExe, StringInStr(@AutoItExe, "\", 0, -1))
    $sFileName1 = $sBaseDir & "Examples\GUI"
    $sFileName2 = $sFileName1 & "\Advanced\Images\Blue.bmp"
    $sFileName3 = $sFileName1 & "\merlin.gif"
    $sFileName4 = $sFileName1 & "\Torus.png"
    $sFileName5 = $sBaseDir & "icons\au3.ico"
    $sFileName6 = $sFileName1 & "\mslogo.jpg"
    $sFileName7 = $sBaseDir & "AutoIt.chm"

    #region LV-Example
    Switch $b_IExtractImage_Force
        Case True
            GUICreate("ListView Example - IExtractImage Interface", 500, 800)
        Case Else
            GUICreate("ListView Example - IShellItemImageFactory Interface", 500, 800)
    EndSwitch

    $hListView = GUICtrlCreateListView("", 2, 2, 496, 796)
    GUISetState()

    ; Load images
    $hImage = _GUIImageList_Create($i_IShellFolder_Preview_Size, $i_IShellFolder_Preview_Size, 5, 3, 1)
    _IShellFolder_GUIImageList_Add($hImage, $sFileName1)
    _IShellFolder_GUIImageList_Add($hImage, $sFileName2)
    _IShellFolder_GUIImageList_Add($hImage, $sFileName3)
    _IShellFolder_GUIImageList_Add($hImage, $sFileName4)
    _IShellFolder_GUIImageList_Add($hImage, $sFileName5)
    _IShellFolder_GUIImageList_Add($hImage, $sFileName6)
    _IShellFolder_GUIImageList_Add($hImage, $sFileName7)
    _GUICtrlListView_SetImageList($hListView, $hImage, 1)

    ; Add columns
    _GUICtrlListView_AddColumn($hListView, "Filename", 400)

    ; Add items
    _GUICtrlListView_AddItem($hListView, $sFileName1, 0)
    _GUICtrlListView_AddItem($hListView, $sFileName2, 1)
    _GUICtrlListView_AddItem($hListView, $sFileName3, 2)
    _GUICtrlListView_AddItem($hListView, $sFileName4, 3)
    _GUICtrlListView_AddItem($hListView, $sFileName5, 4)
    _GUICtrlListView_AddItem($hListView, $sFileName6, 5)
    _GUICtrlListView_AddItem($hListView, $sFileName7, 6)

    ; Loop until user exits
    Do
    Until GUIGetMsg() = $GUI_EVENT_CLOSE
    GUIDelete()
    #endregion LV-Example
EndFunc   ;==>_LV_Example

Func _IShellFolder_Exit()
    _GDIPlus_Shutdown()
    _WinAPI_DeleteObject($h_IShellFolder_Bmp)
    _AutoItObject_Shutdown()
EndFunc   ;==>_IShellFolder_Exit

Func _IShellFolder_GUIImageList_Add($hIML, $sFilename)
    $hBMP = _IShellFolder_Extract_hBMP($sFilename)
    Switch $hBMP
        Case 1 ; Folder under XP
            If $i_IShellFolder_Preview_Size >= 48 Then
                _GUIImageList_AddIcon($hIML, @SystemDir & "\shell32.dll", 3, True)
            Else
                _GUIImageList_AddIcon($hIML, @SystemDir & "\shell32.dll", 3, False)
            EndIf
        Case 2 ;
            If $i_IShellFolder_Preview_Size >= 48 Then
                $hIcon = _WinAPI_ShellExtractAssociatedIcon($sFilename, 0)
                _GUIImageList_ReplaceIcon($hIML, -1, $hIcon)
                _WinAPI_DestroyIcon($hIcon)
            Else
                $hIcon = _WinAPI_ShellExtractAssociatedIcon($sFilename, 1)
                _GUIImageList_ReplaceIcon($hIML, -1, $hIcon)
                _WinAPI_DestroyIcon($hIcon)
            EndIf
        Case Else
            _GUIImageList_Add($hIML, $hBMP)
    EndSwitch
EndFunc   ;==>_IShellFolder_GUIImageList_Add

Func _IShellFolder_Extract_hBMP($sFilename)
    If Not FileExists($sFilename) Then Return SetError(1)
    If IsHWnd($h_IShellFolder_Bmp) Then _WinAPI_DeleteObject($h_IShellFolder_Bmp)

    Dim $pImgFact

    If 0 = _IShellFolder_SHCreateItemFromParsingName($sFilename, 0, DllStructGetPtr($tIIDImgFact), $pImgFact) And $pImgFact And Not $b_IExtractImage_Force Then
        $IImgFact = _AutoItObject_WrapperCreate($pImgFact, $dtagIShellItemImageFactory)
        $r = $IImgFact.GetImage(_IShellFolder_MakeUINT64($i_IShellFolder_Preview_Size, $i_IShellFolder_Preview_Size), 8, 0) ; <==== _IShellFolder_MakeUINT64 added
        ;ConsoleWrite($sFileName & @TAB & $r[3] & @CRLF)
        If $r[3] = 0 Or StringInStr(FileGetAttrib($sFilename), "D") Then ; no thumbnail available OR target is folder
            $r = $IImgFact.GetImage(_IShellFolder_MakeUINT64($i_IShellFolder_Preview_Size, $i_IShellFolder_Preview_Size), 0, 0) ; <==== _IShellFolder_MakeUINT64 added
            $h_IShellFolder_Bmp = $r[3]
        Else
            $r = $IImgFact.GetImage(_IShellFolder_MakeUINT64($i_IShellFolder_Preview_Size, $i_IShellFolder_Preview_Size), 1, 0) ; <==== _IShellFolder_MakeUINT64 added
            $h_IShellFolder_Bmp = _IShellFolder_GetImage($r[3], $i_IShellFolder_Preview_Size, $i_IShellFolder_Preview_Size)
        EndIf
        ;EndIf
    Else
        $pidl = _IShellFolder_ILCreateFromPath($sFilename)
        Dim $pIShellFolder, $pRelative
        $tRIID = _AutoItObject_CLSIDFromString($sIID_IShellFolder)
        $tRIIDExtract = _AutoItObject_CLSIDFromString($sIID_IExtractImage)
        ;ConsoleWrite($pidl & @crlf)
        If StringInStr(FileGetAttrib($sFilename), "D", 1) Then
            _IShellFolder_CoTaskMemFree($pidl)
            Return 1
            ;MsgBox(0, '', "Cannot create preview for Folders on Windows prior to Vista")
            ;Exit
        Else
            _SHBindToParent($pidl, DllStructGetPtr($tRIID), $pIShellFolder, $pRelative)
            $IShellFolder = _AutoItObject_WrapperCreate($pIShellFolder, $dtagIShellFolder)
            ;ConsoleWrite(IsObj($IShellFolder) & @crlf)

            $tSTRRET = DllStructCreate("uint uType;ptr data;")
            $r = $IShellFolder.GetDisplayNameOf(Number($pRelative), 0, Number(DllStructGetPtr($tSTRRET)))

            Dim $name
            _IShellFolder_StrRetToBuf(DllStructGetPtr($tSTRRET), 0, $name, 512)
            $tSTRRET = 0

            ;MsgBox(0, 'name of item', $name)

            $tArray = DllStructCreate("ptr")
            DllStructSetData($tArray, 1, $pRelative)

            $r = $IShellFolder.GetUIObjectOf(0, 1, Number(DllStructGetPtr($tArray)), Number(DllStructGetPtr($tRIIDExtract)), 0, 0)
            $IExtractImage = _AutoItObject_WrapperCreate($r[6], $dtagIExtractImage)
        EndIf

        If Not IsObj($IExtractImage) Then
            Return 2
        Else
            $tSize = DllStructCreate("long;long")
            DllStructSetData($tSize, 1, $i_IShellFolder_Preview_Size)
            DllStructSetData($tSize, 2, $i_IShellFolder_Preview_Size)
            $r = $IExtractImage.GetLocation("", 1024, 0, Number(DllStructGetPtr($tSize)), 32, 0x0020 + 0x0200) ;IEIFLAG_SCREEN + IEIFLAG_QUALITY
            ;MsgBox(0, '', $r[1])
            $r = $IExtractImage.Extract(0)
            $h_IShellFolder_Bmp = $r[1]

            ; ConsoleWrite($name & @TAB & $h_IShellFolder_Bmp & @CRLF)

            $IShellFolder = 0
            _IShellFolder_CoTaskMemFree($pidl)

            $h_IShellFolder_Bmp2 = _IShellFolder_GetImage($h_IShellFolder_Bmp, $i_IShellFolder_Preview_Size, $i_IShellFolder_Preview_Size)
            _WinAPI_DeleteObject($h_IShellFolder_Bmp)
            $h_IShellFolder_Bmp = $h_IShellFolder_Bmp2
        EndIf
    EndIf

    $IExtractImage = 0

    Return $h_IShellFolder_Bmp

EndFunc   ;==>_IShellFolder_Extract_hBMP

Func _IShellFolder_GetImage($hBmp_Source, $i_TargetWidth = 32, $i_TargetHeight = 32)

    $hImage = _GDIPlus_BitmapCreateFromHBITMAP($hBmp_Source)
    $iW = _GDIPlus_ImageGetWidth($hImage)
    $iH = _GDIPlus_ImageGetHeight($hImage)
    $aGS = _IShellFolder_GetScale($iW, $iH, $i_TargetWidth)
    _GDIPlus_ImageDispose($hImage)

    $hDC = _WinAPI_GetDC(0)
    $hDestDC = _WinAPI_CreateCompatibleDC($hDC)
    $hBMP = _WinAPI_CreateCompatibleBitmapEx($hDC, $i_TargetWidth, $i_TargetHeight, 0xFFFFFF)
    $hDestSv = _WinAPI_SelectObject($hDestDC, $hBMP)
    $hSrcDC = _WinAPI_CreateCompatibleDC($hDC)
    $hSrcSv = _WinAPI_SelectObject($hSrcDC, $hBmp_Source)
    ;$Result = _WinAPI_AlphaBlend($hDestDC, 0, 0, $i_TargetWidth, $i_TargetHeight, $hSrcDC, 0, 0, $iW, $iH, 255, 0)
    $Result = _WinAPI_AlphaBlend($hDestDC, $aGS[0], $aGS[1], $aGS[2], $aGS[3], $hSrcDC, 0, 0, $iW, $iH, 255, 0)
    _WinAPI_ReleaseDC(0, $hDC)
    _WinAPI_SelectObject($hDestDC, $hDestSv)
    _WinAPI_SelectObject($hSrcDC, $hSrcSv)
    _WinAPI_DeleteDC($hDestDC)
    _WinAPI_DeleteDC($hSrcDC)

    Return $hBMP

EndFunc   ;==>_IShellFolder_GetImage

Func _IShellFolder_GetScale($iW, $iH, $i_TargetWidth)
    Local $aRet[4]
    If $iW <= $i_TargetWidth And $iH <= $i_TargetWidth Then
        $aRet[2] = $iW
        $aRet[3] = $iH
        $aRet[0] = ($i_TargetWidth - $aRet[2]) / 2
        $aRet[1] = ($i_TargetWidth - $aRet[3]) / 2
    ElseIf $iW > $iH Then
        $aRet[2] = $i_TargetWidth
        $aRet[3] = $iH / ($iW / $i_TargetWidth)
        $aRet[0] = 0
        $aRet[1] = ($i_TargetWidth - $aRet[3]) / 2
    ElseIf $iW < $iH Then
        $aRet[2] = $iW / ($iH / $i_TargetWidth)
        $aRet[3] = $i_TargetWidth
        $aRet[0] = ($i_TargetWidth - $aRet[2]) / 2
        $aRet[1] = 0
    ElseIf $iW = $iH Then
        $aRet[2] = $i_TargetWidth
        $aRet[3] = $i_TargetWidth
        $aRet[0] = 0
        $aRet[1] = 0
    EndIf
    Return $aRet
EndFunc   ;==>_IShellFolder_GetScale


Func _IShellFolder_MakeUINT64($long1, $long2)
    Local $d = DllStructCreate("align 4;dword[2]")
    DllStructSetData($d, 1, $long1, 1)
    DllStructSetData($d, 1, $long2, 2)
    Return DllStructGetData(DllStructCreate("uint64", DllStructGetPtr($d)), 1)
EndFunc   ;==>_IShellFolder_MakeUINT64

Func _IShellFolder_CoTaskMemFree($pMem)
    Local $aRes = DllCall("Ole32.dll", "none", "CoTaskMemFree", "ptr", $pMem)
    If @error Then SetError(1)
EndFunc   ;==>_IShellFolder_CoTaskMemFree

Func _IShellFolder_ILCreateFromPath($sPath)
    Local $aRes = DllCall("shell32.dll", "ptr", "ILCreateFromPathW", "wstr", $sPath)
    If @error Then Return SetError(1, 0, 0)
    Return $aRes[0]
EndFunc   ;==>_IShellFolder_ILCreateFromPath

Func _IShellFolder_SHCreateItemFromParsingName($szPath, $pbc, $riid, ByRef $pv)
    Local $aRes = DllCall("shell32.dll", "long", "SHCreateItemFromParsingName", "wstr", $szPath, "ptr", $pbc, "ptr", $riid, "ptr*", 0)
    If @error Then Return SetError(1, 0, 0)
    $pv = $aRes[4]
    Return $aRes[0]
EndFunc   ;==>_IShellFolder_SHCreateItemFromParsingName

Func _IShellFolder_SHBindToObject($psf, $pidl, $pbc, $riid, ByRef $pv)
    Local $aRes = DllCall("Shell32.dll", "long", "SHBindToObject", "ptr", $psf, "ptr", $pidl, "ptr", $pbc, "ptr", $riid, "ptr*", 0)
    If @error Then Return SetError(1, 0, 0)
    $pv = $aRes[5]
    Return $aRes[0]
EndFunc   ;==>_IShellFolder_SHBindToObject

Func _SHBindToParent($pidl, $riid, ByRef $pv, ByRef $pidlLast)
    Local $aRes = DllCall("Shell32.dll", "long", "SHBindToParent", "ptr", $pidl, "ptr", $riid, "ptr*", 0, "ptr*", 0)
    If @error Then Return SetError(1, 0, 0)
    $pv = $aRes[3]
    $pidlLast = $aRes[4]
    Return $aRes[0]
EndFunc   ;==>_SHBindToParent

Func _IShellFolder_StrRetToBuf($pSTRRET, $pidl, ByRef $sName, $iLength = 512)
    Local $aRes = DllCall("shlwapi.dll", "long", "StrRetToBufW", "ptr", $pSTRRET, "ptr", $pidl, "wstr", $sName, "uint", $iLength)
    If @error Then Return SetError(1, 0, 0)
    $sName = $aRes[3]
    Return $aRes[0]
EndFunc   ;==>_IShellFolder_StrRetToBuf

Share this post


Link to post
Share on other sites

Great, but this is some better code to get the dimensions of a HBITMAP without the need of GDI+:

Local $tBMP = DllStructCreate($tagBITMAP)
_WinAPI_GetObject($hBmp_Source, DllStructGetSize($tBMP), DllStructGetPtr($tBMP))
Local $iW = DllStructGetData($tBMP, "bmWidth"), $iH = Abs(DllStructGetData($tBMP, "bmHeight"))
Local $aGS = _IShellFolder_GetScale($iW, $iH, $i_TargetWidth)

*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

Share this post


Link to post
Share on other sites

#16 ·  Posted (edited)

Excellent, thanks a lot :x. In IExtractImage there seem to be even more cases then directories, where the system can not extract a preview. On this occasions I wrote a fallback to extract the respective icons from the systems imagelist. My code is now already heavily integrate into SMF, but maybe beginning of next year I'll create a full stand-alone example.

Posted Image

Edited by KaFu

Share this post


Link to post
Share on other sites

KaFu you pyro you...


♡♡♡

.

eMyvnE

Share this post


Link to post
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
Sign in to follow this  
Followers 0