Sign in to follow this  
Followers 0
orbs

FileSelectFolder old style by DllCall - how does the root dir work?

5 posts in this topic

in this topic:

there is a reference to this function, using the "old style" by DLL call:

Func _FileSelectFolder ($title, $root = 0, $flags = 0, $hwnd = 0)
    Local $ret, $pidl, $res = ''   
    Local $ubi = DllStructCreate ("hwnd;ptr;ptr;ptr;int;ptr;ptr;int") 
    Local $utl = DllStructCreate ("char[512]") 
    Local $urs = DllStructCreate ("char[260]") 
    Local $ulf = BitOR (BitShift(BitAnd ($flags,1),-9), _ 
        BitShift(BitAnd ($flags,2),-5), _
        BitShift(BitAnd ($flags,4),-2))    
    DllStructSetData ($utl, 1, $title)
    DllStructSetData ($ubi, 1, $hwnd)
    DllStructSetData ($ubi, 3, DllStructGetPtr($urs))
    DllStructSetData ($ubi, 4, DllStructGetPtr($utl))
    DllStructSetData ($ubi, 5, $ulf)
    $ret = DllCall ("shell32.dll", "ptr", "SHGetSpecialFolderLocation", _
        "int", 0 , _
        "int", $root , _
        "ptr", DllStructGetPtr($ubi, 2))
    If $ret[0] Then Return $res
    $pidl = DllCall ("shell32.dll", "ptr", "SHBrowseForFolder", "ptr", DllStructGetPtr ($ubi))
    If $pidl[0] Then
        $ret = DllCall ("shell32.dll", "int", "SHGetPathFromIDList", _
            "ptr", $pidl[0], _
            "ptr", DllStructGetPtr ($urs))
        If $ret[0] Then $res = DllStructGetData ($urs, 1)
        DllCall ("ole32.dll", "int", "CoTaskMemFree", "ptr", $pidl[0]) 
    EndIf
    DllCall ("ole32.dll", "int", "CoTaskMemFree", "ptr", DllStructGetData ($ubi, 2))
    Return $res
EndFunc

this function accepts the "root" dir as an integer, not a string (it calls the SHBrowseForFolder function, which accepts the BROWSEINFO struct, which holds the folder as an integer). this is a complete mystery to me; however, for Windows, that apparently makes perfect sense. :huh2:

i can't understand how this function can accept any root dir other than the default. can anyone shed some light on that?

Share this post


Link to post
Share on other sites



I never did much with the Shell Namespace because I didn't have to and it is a pita. :)

 

This site may shed some light on it:

https://msdn.microsoft.com/en-us/library/windows/desktop/cc144090(v=vs.85).aspx#unknown_13653

 

The confusion may be that the PIDL is like an integer type that is used as a pointer.  You might try to find examples in a different programming language.  Maybe something in C# or C++ on the Code Project site.

 

Share this post


Link to post
Share on other sites

#3 ·  Posted (edited)

following MSDN links i came across this: SHParseDisplayName

Translates a Shell namespace object's display name into an item identifier list and returns the attributes of the object. This function is the preferred method to convert a string to a pointer to an item identifier list (PIDL). 

i tried to implement it, and failed miserably. this is my attempt:

Func _FileSelectFolder($title, $sRoot = '', $flags = 0, $hwnd = 0)
    Local $ret, $pidl, $res = ''
    Local $ubi = DllStructCreate("hwnd;ptr;ptr;ptr;int;ptr;ptr;int")
    Local $utl = DllStructCreate("char[512]")
    Local $urs = DllStructCreate("char[260]")
    Local $ulf = BitOR(BitShift(BitAND($flags, 1), -9), _
            BitShift(BitAND($flags, 2), -5), _
            BitShift(BitAND($flags, 4), -2))
    DllStructSetData($utl, 1, $title)
    DllStructSetData($ubi, 1, $hwnd)
    DllStructSetData($ubi, 3, DllStructGetPtr($urs))
    DllStructSetData($ubi, 4, DllStructGetPtr($utl))
    DllStructSetData($ubi, 5, $ulf)


    If $sRoot = '' Then
        $ret = DllCall("shell32.dll", "ptr", "SHGetSpecialFolderLocation", _
                "int", 0, _
                "int", 0, _
                "ptr", DllStructGetPtr($ubi, 2))
        If $ret[0] Then Return $res
    Else

        ; >>>>> how to call SHParseDisplayName so that the $ubi struct will contain the PIDL in element #3 ?
        $ret = DllCall("shell32.dll", "long", "SHParseDisplayName", _
                'ptr', Ptr($sRoot), _
                'ptr', Null, _
                'ptr', DllStructGetPtr($ubi, 2), _
                'ptr', Null, _
                'ptr', Null)
        DllStructSetData($ubi, 2, $ret[3])
        ; >>>>>

        If $ret[0] Then Return $res
    EndIf


    $pidl = DllCall("shell32.dll", "ptr", "SHBrowseForFolder", "ptr", DllStructGetPtr($ubi))
    If $pidl[0] Then
        $ret = DllCall("shell32.dll", "int", "SHGetPathFromIDList", _
                "ptr", $pidl[0], _
                "ptr", DllStructGetPtr($urs))
        If $ret[0] Then $res = DllStructGetData($urs, 1)
        DllCall("ole32.dll", "int", "CoTaskMemFree", "ptr", $pidl[0])
    EndIf
    DllCall("ole32.dll", "int", "CoTaskMemFree", "ptr", DllStructGetData($ubi, 2))
    Return $res
EndFunc   ;==>_FileSelectFolder

i redefined the parameter to accept a string (empty string by default). if the string is empty, it follows the original logic to calculate the PIDL of the "desktop". this still works. but if it's not empty, i try to call SHParseDisplayName to calculate the PIDL. as i understand, that PIDL should be placed into the DLL struct that is later passed to SHBrowseForFolder (named $ubi here), as the 3rd field of the struct. i can't get that to work - see the section marked by  ; >>>>>  in the code above. what am i doing wrong?

Edited by orbs

Share this post


Link to post
Share on other sites

thank you LarsJ, i'll look into that (and i'll keep in mind to look in the WinAPI UDF if i ever bump into a DLL call).

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