Sign in to follow this  
Followers 0
Trolleule

how to use interface pointer

6 posts in this topic

Hi

I'm trying to make a custom filtering with the shell function SHBrowseForFolder and i actually work with the example from the autoit help file. I catch the IUnknown event and the lparam contains a pointer to an IUnknown interface. Can someone explain please what i can generally do with an interface pointer.

And how can i get an single level pidl from an absolute pidl. I study the msdn sites for days but i dont get it. I only understand how i can make an object with an specified interface to use its methods. But the most methods need a pidl item and i only have an pidl folder.

Thanks for help!

Share this post


Link to post
Share on other sites

#2 ·  Posted (edited)

Trolleule, I saw your post (Select Folder/File (_WinAPI_BrowseForFolderDlg()) mit Filter Option: PIDL (IDLIST) auslesen) about this subject in the German forum while the English forum was down.

You generally use an interface pointer to create an interface object to be able to call the methods of the object.

For point 3. in the middle of your German post you create an IUnknown object from the pointer like this:

; IUnknown Interface
Global Const $sIID_IUnknown = "{00000000-0000-0000-C000-000000000046}"
Global Const $tRIID_IUnknown = _WinAPI_GUIDFromString( $sIID_IUnknown )
Global Const $dtag_IUnknown = _
  "QueryInterface hresult(struct*;ptr*);" & _
  "AddRef ulong();" & _
  "Release ulong();"

$oIUnknown = ObjCreateInterface( $pIUnknown, $sIID_IUnknown, $dtag_IUnknown )

Still in point 3. you use QueryInterface to get a pointer for IFolderFilterSite:

Global Const $sIID_IFolderFilterSite = "{C0A651F5-B48B-11d2-B5ED-006097C686F6}"
Global Const $tRIID_IFolderFilterSite = _WinAPI_GUIDFromString( $sIID_IFolderFilterSite )
Global Const $dtag_IFolderFilterSite = "SetFilter hresult(ptr);"

Local $pIFolderFilterSite
$oIUnknown.QueryInterface( $tRIID_IFolderFilterSite, $pIFolderFilterSite )
$oIFolderFilterSite = ObjCreateInterface( $pIFolderFilterSite, $sIID_IFolderFilterSite, $dtag_IFolderFilterSite )

Point 4. It's too late now. I'll be back.

Edited by LarsJ

Share this post


Link to post
Share on other sites

Share this post


Link to post
Share on other sites

I've looked in the documentation. You must specify the pointer to IUnknown in lParam of the BROWSEINFO structure before you call SHBrowseForFolder. This means that you must start to create an interface object. This can probably be done (more or less in the same manner as in Implementing Windows Explorer right pane), but it takes a lot more work. I will not go on with this.

Share this post


Link to post
Share on other sites

#5 ·  Posted (edited)

sorry for late reply. Thank you very much for your help Lars.

Her is the code iam testing with:

If you want to use my code, you have to copy the WinAPIDlg.au3 and delete the _WinAPI_BrowseForFolderDlg there cause i overwrite it in my code or you rename the function in my code.

#include "WinAPIDlg.au3"
;#include "AutoItObject.au3"
#include <APIDlgConstants.au3>
#include <WinAPISys.au3>
#include <MsgBoxConstants.au3>
;#include "_DLLStructDisplay.au3"

Global Const $InitDir = @ProgramFilesDir




;===============================================================================
#interface "IUnknown"
;~ Global Const $sIID_IUnknown = "{00000000-0000-0000-C000-000000000046}"
; Definition
Global $dtagIUnknown = "QueryInterface hresult(ptr;ptr*);" & _
        "AddRef dword();" & _
        "Release dword();"
; List
Global $ltagIUnknown = "QueryInterface;" & _
        "AddRef;" & _
        "Release;"
;===============================================================================
;===============================================================================
#interface "IDispatch"
;~ Global Const $sIID_IDispatch = "{00020400-0000-0000-C000-000000000046}"
; Definition
Global $dtagIDispatch = $dtagIUnknown & _
        "GetTypeInfoCount hresult(dword*);" & _
        "GetTypeInfo hresult(dword;dword;ptr*);" & _
        "GetIDsOfNames hresult(ptr;ptr;dword;dword;ptr);" & _
        "Invoke hresult(dword;ptr;dword;word;ptr;ptr;ptr;ptr);"
; List
Global $ltagIDispatch = $ltagIUnknown & _
        "GetTypeInfoCount;" & _
        "GetTypeInfo;" & _
        "GetIDsOfNames;" & _
        "Invoke;"

;===============================================================================
#interface "IShellFolder"
Global Const $sIID_IShellFolder = "{000214E6-0000-0000-C000-000000000046}"
Global $tagIShellFolder = "ParseDisplayName hresult(hwnd;ptr;wstr;ulong*;ptr*;ulong*);" & _
        "EnumObjects hresult(hwnd;dword;ptr*);" & _
        "BindToObject hresult(struct*;ptr;clsid;ptr*);" & _
        "BindToStorage hresult(struct*;ptr;clsid;ptr*);" & _
        "CompareIDs hresult(lparam;struct*;struct*);" & _
        "CreateViewObject hresult(hwnd;clsid;ptr*);" & _
        "GetAttributesOf hresult(uint:struct*;ulong*);" & _
        "GetUIObjectOf hresult(hwnd;uint;struct*;clsid;uint*;ptr*);" & _
        "GetDisplayNameOf hresult(struct*;dword;struct*);" & _
        "SetNameOf hresult(hwnd;struct*;wstr;dword;struct*);"
;===============================================================================
;===============================================================================
#interface "IShellItem"
Global Const $sIID_IShellItem = "{43826d1e-e718-42ee-bc55-a1e261c37bfe}"
Global $tagIShellItem = "BindToHandler hresult(ptr;clsid;clsid;ptr*);" & _
        "GetParent hresult(ptr*);" & _
        "GetDisplayName hresult(int;ptr*);" & _
        "GetAttributes hresult(int;int*);" & _
        "Compare hresult(ptr;int;int*);"
;===============================================================================
;===============================================================================
#interface "IShellItemArray"
Global Const $sIID_IShellItemArray = "{b63ea76d-1f85-456f-a19c-48159efa858b}"
Global $tagIShellItemArray = "BindToHandler hresult(ptr;clsid;clsid;ptr*);" & _
        "GetPropertyStore hresult(int;clsid;ptr*);" & _
        "GetPropertyDescriptionList hresult(struct*;clsid;ptr*);" & _
        "GetAttributes hresult(int;int;int*);" & _
        "GetCount hresult(dword*);" & _
        "GetItemAt hresult(dword;ptr*);" & _
        "EnumItems hresult(ptr*);"
;===============================================================================
;===============================================================================
#interface "IModalWindow"
Global Const $sIID_IModalWindow = "{b4db1657-70d7-485e-8e3e-6fcb5a5c1802}"
Global $tagIModalWindow = "Show hresult(hwnd);"
;===============================================================================
;===============================================================================
#interface "IFileDialog"
Global Const $sIID_IFileDialog = "{42f85136-db7e-439c-85f1-e4075d135fc8}"
Global $tagIFileDialog = $tagIModalWindow & _
        "SetFileTypes hresult(uint;ptr);" & _
        "SetFileTypeIndex hresult(uint);" & _
        "GetFileTypeIndex hresult(uint*);" & _
        "Advise hresult(ptr;dword*);" & _
        "Unadvise hresult(dword);" & _
        "SetOptions hresult(int);" & _
        "GetOptions hresult(int*);" & _
        "SetDefaultFolder hresult(ptr);" & _
        "SetFolder hresult(ptr);" & _
        "GetFolder hresult(ptr*);" & _
        "GetCurrentSelection hresult(ptr*);" & _
        "SetFileName hresult(wstr);" & _
        "GetFileName hresult(ptr*);" & _
        "SetTitle hresult(wstr);" & _
        "SetOkButtonLabel hresult(wstr);" & _
        "SetFileNameLabel hresult(wstr);" & _
        "GetResult hresult(ptr*);" & _
        "AddPlace hresult(ptr;int);" & _
        "SetDefaultExtension hresult(wstr);" & _
        "Close hresult();" & _
        "SetClientGuid hresult(clsid);" & _
        "ClearClientData hresult();" & _
        "SetFilter hresult(ptr);"
;===============================================================================
;===============================================================================
#interface "IFileOpenDialog"
Global Const $sCLSID_FileOpenDialog = "{DC1C5A9C-E88A-4dde-A5A1-60F82A20AEF7}"
Global Const $sIID_IFileOpenDialog = "{d57c7288-d4ad-4768-be02-9d969532d960}"
Global $tagIFileOpenDialog = $tagIFileDialog & _
        "GetResults hresult(ptr*);" & _
        "GetSelectedItems hresult(ptr*);"
;===============================================================================
;~ #interface "IFolderFilter"
;~ Global Const $sCLSID_FileOpenDialog = "{DC1C5A9C-E88A-4dde-A5A1-60F82A20AEF7}"
Global Const $sIID_IFolderFilter = "{9CC22886-DC8E-11D2-B1D0-00C04F8EEB3E}"
Global $tagIFolderFilter = "ShouldShow hresult(ptr*;ptr;ptr);" & _
        "GetEnumFlags hresult(ptr*;ptr;hwnd*;dword*);"


Local Const $tagITEMIDLIST = 'ptr mkid'
Local Const $tagSHITEMID = 'ushort cb;byte abID'


Global Const $SIGDN_NORMALDISPLAY = 0





;~ Local $poi = _AutoItObject_WrapperCreate($ptr_IShellFolder[1],$tagIShellFolder)
;~ ConsoleWrite("Object: " & $poi & " type: " & VarGetType($poi) & @CRLF)

Local $ptr_IShellFolder = GetDesktop() ; ptr to shellfolder interface
;~ _ArrayDisplay($ptr_IShellFolder)
ConsoleWrite("desktop_pidl: " & $ptr_IShellFolder[1] & " type: " & VarGetType($ptr_IShellFolder[1]) & @CRLF)

Func GetDesktop()
    Local $Ret = DllCall('shell32.dll', 'ptr', 'SHGetDesktopFolder', 'ptr*', 0)
    Return $Ret
EndFunc

Local $structptrs = DllStructCreate("ptr[100]", $ptr_IShellFolder[1])
;~ _DLLStructDisplay($structptrs,"ptr[100]","Randomness")



Local $hBrowseProc = DllCallbackRegister('_BrowseProc', 'int', 'hwnd;uint;lparam;ptr')
Local $pBrowseProc = DllCallbackGetPtr($hBrowseProc)

Local $pText = _WinAPI_CreateString($InitDir)
Local $Path = _WinAPI_BrowseForFolderDlg(_WinAPI_PathStripToRoot($InitDir), 'Select a folder from the list below.', _
                BitOR($BIF_BROWSEINCLUDEFILES, $BIF_NEWDIALOGSTYLE, $BIF_EDITBOX, $BIF_VALIDATE), $pBrowseProc, $pText)
_WinAPI_FreeMemory($pText)

If $Path Then
    ConsoleWrite('--------------------------------------------------' & @CRLF)
    ConsoleWrite($Path & @CRLF)
EndIf

DllCallbackFree($hBrowseProc)

Func _BrowseProc($hWnd, $iMsg, $wParam, $lParam)
    Local $Path

    Switch $iMsg
        Case $BFFM_INITIALIZED
            _WinAPI_SetWindowText($hWnd, 'MyTitle')
            _SendMessage($hWnd, $BFFM_SETSELECTIONW, 1, $lParam)
            ConsoleWrite("Initialize" & @CRLF)
        Case $BFFM_SELCHANGED
;~          $Path = _WinAPI_ShellGetPathFromIDList($wParam)
;~          If Not @error Then
;~              ConsoleWrite($Path & @CRLF)
;~          EndIf
        Case $BFFM_VALIDATEFAILED
            MsgBox(BitOR($MB_ICONERROR, $MB_SYSTEMMODAL), 'Error', _WinAPI_GetString($wParam) & ' is invalid.', 0, $hWnd)
            Return 1
        Case $BFFM_IUNKNOWN
            ConsoleWrite("lparam: " & $lParam & " type: " & VarGetType($lParam) & @CRLF)
;~          Local $test = ObjCreateInterface($lParam, $sIID_IShellFolder, $tagIShellFolder)
            Local $test = ObjCreateInterface($sCLSID_FileOpenDialog, $sIID_IFolderFilter, $tagIFolderFilter)
            ConsoleWrite("ref: " & $test & " type: " & VarGetType($test) & @CRLF)
            Local $ab = $test.AddRef()
            ConsoleWrite("ref: " & $ab & " type: " & VarGetType($ab) & @CRLF)
            Local $Path = _WinAPI_ShellGetPathFromIDList($wParam)
            Local $PIDL = $wParam
            Local $oShellFolder = ObjCreateInterface("{0E5AAE11-A475-4C5B-AB00-C66DE400274E}", $sIID_IShellFolder, $tagIShellFolder)
            ConsoleWrite("reff: " & $oShellFolder & " type: " & VarGetType($oShellFolder) & @CRLF)



            Local $ptrs = DllStructCreate("ptr[100]", $PIDL)
;~          _DLLStructDisplay($ptrs,"ptr[100]","Randomness")


            Local $out_name
            Local $name = $oShellFolder.GetDisplayNameOf($PIDL, $SIGDN_NORMALDISPLAY, $out_name)
            ConsoleWrite("hresult displayname: " & Hex($name) & @CRLF)
    EndSwitch
    Return 0
EndFunc   ;==>_BrowseProc







Func GetFolderLocation()
;~  Local $Ret = DllCall('shell32.dll', 'ptr', 'SHGetFolderLocation', 'ptr*', 0)

EndFunc


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

Func _WinAPI_BrowseForFolderDlg($sRoot = '', $sText = '', $iFlags = 0, $pBrowseProc = 0, $lParam = 0, $hParent = 0)
    Local Const $tagBROWSEINFO = 'hwnd hwndOwner;ptr pidlRoot;ptr pszDisplayName; ptr lpszTitle;uint ulFlags;ptr lpfn;lparam lParam;int iImage'
    Local $tBROWSEINFO = DllStructCreate($tagBROWSEINFO & ';wchar[' & (StringLen($sText) + 1) & '];wchar[260]')
    Local $PIDL = 0, $Result = ''

    If StringStripWS($sRoot, 3) Then
        Local $Path = _WinAPI_PathSearchAndQualify($sRoot, 1)
        If @error Then
            $Path = $sRoot
        EndIf
        $PIDL = _WinAPI_ShellILCreateFromPath($Path) ; get ptr from path
        If @error Then
            ; Nothing
        EndIf
    EndIf
    ConsoleWrite("pIDL from path: " & $PIDL & @CRLF)



    DllStructSetData($tBROWSEINFO, 1, $hParent)
    DllStructSetData($tBROWSEINFO, 2, $PIDL)
    DllStructSetData($tBROWSEINFO, 3, DllStructGetPtr($tBROWSEINFO, 10))
    DllStructSetData($tBROWSEINFO, 4, DllStructGetPtr($tBROWSEINFO, 9))
    DllStructSetData($tBROWSEINFO, 5, $iFlags)
    DllStructSetData($tBROWSEINFO, 6, $pBrowseProc)
    DllStructSetData($tBROWSEINFO, 7, $lParam)
    DllStructSetData($tBROWSEINFO, 8, 0)
    DllStructSetData($tBROWSEINFO, 9, $sText)

    Local $Ret = DllCall('shell32.dll', 'ptr', 'SHBrowseForFolderW', 'struct*', $tBROWSEINFO) ; returns PIDLIST_ABSOLUTE
    If @error Or Not $Ret[0] Then Return SetError(@error, @extended, '')
    ; If Not $Ret[0] Then Return SetError(1000, 0, '')

;~  _ArrayDisplay($Ret)
    ConsoleWrite("out pidl: " & $Ret[0] & @CRLF)

            Local $ptrs = DllStructCreate("ptr[100]", $Ret[0])
;~          _DLLStructDisplay($ptrs,"ptr[100]","Randomness")

;~  Local $stru = DllStructCreate($tagITEMIDLIST)
    Local $pidlLast
    Local $pv
    Local $binder = _SHBindToParent($Ret[0], $sIID_IShellFolder, $pv, $pidlLast)
    _ArrayDisplay($binder)
    ConsoleWrite("out pidl child: " & $pidlLast & @CRLF)
    ConsoleWrite("out interface ptr: " & $pv & @CRLF)
    ConsoleWrite("hresult binder: " & $binder & @CRLF)


    ; $Ret[0] = PIDL:
    ; The address of an item identifier list that specifies a file or directory location relative to the
    ; root of the namespace
    ; Return: The file system path
    $Result = _WinAPI_ShellGetPathFromIDList($Ret[0])
    ConsoleWrite("GetPathFromPIDL: " & $Result & @CRLF)

    _WinAPI_CoTaskMemFree($Ret[0])
    If $PIDL Then
        _WinAPI_CoTaskMemFree($PIDL)
    EndIf
    If Not $Result Then Return SetError(10, 0, '')

    Return $Result
EndFunc   ;==>_WinAPI_BrowseForFolderDlg

Check the code where i cathc the IUnknown event:

There i created a IShellFolder Interface successfully. But now i want to execute the GetDisplayNameOf method:

 

HRESULT GetDisplayNameOf(
[in]   PCUITEMID_CHILD pidl,
[in]   SHGDNF uFlags,
[out]  STRRET *pName
);

 

Check msdn http://msdn.microsoft.com/en-us/library/windows/desktop/bb775071(v=vs.85).aspx

I hope and i think my final question is how i can get an PCUITEMID_CHILD(PIDL that uniquely identifies the file object or subfolder relative to the parent folder.)  of an PIDLIST_ABSOLUTE (Returns a PIDL that specifies the location of the selected folder relative to the root of the namespace. )

If i understand right, a PIDLIST_ABSOLUTE is a list of "itemid" structures and a PCUITEMID_CHILD is a single "itemid" structure?! Anyway, if a pidl is a list, it must be possible to iterate this list and get all the files/folders inside the pidl as ?IShellItem? or get the name of the files/folders with GetDisplayNameOf.

Can you help?

Edited by Trolleule

Share this post


Link to post
Share on other sites

The "Case $BFFM_IUNKNOWN" section of your code:

Note that $lParam is just $pText from line 153. To implement IFolderFilter $lParam must be a pointer to an interface that exposes IFolderFilterSite.

$oShellFolder is not an IShellFolder interface as you can check with this piece of code:

If IsObj( $oShellFolder ) Then
  ConsoleWrite( "$oShellFolder OK" & @CRLF )
Else
  ConsoleWrite( "$oShellFolder ERR" & @CRLF )
EndIf

You should definitely use a COM error handler while you are developing/testing. You can find one in the example for the ObjEvent function in the helpfile.

To walk backwards through a PIDL use the functions ILFindLastID and ILRemoveLastID. To keep the original PIDL unchanged create a copy with ILClone.

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