Jump to content

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


Recommended Posts

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?

Signature - my forum contributions:

Spoiler

UDF:

LFN - support for long file names (over 260 characters)

InputImpose - impose valid characters in an input control

TimeConvert - convert UTC to/from local time and/or reformat the string representation

AMF - accept multiple files from Windows Explorer context menu

DateDuration -  literal description of the difference between given dates

Apps:

Touch - set the "modified" timestamp of a file to current time

Show For Files - tray menu to show/hide files extensions, hidden & system files, and selection checkboxes

SPDiff - Single-Pane Text Diff

 

Link to comment
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.

 

Link to comment
Share on other sites

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

Signature - my forum contributions:

Spoiler

UDF:

LFN - support for long file names (over 260 characters)

InputImpose - impose valid characters in an input control

TimeConvert - convert UTC to/from local time and/or reformat the string representation

AMF - accept multiple files from Windows Explorer context menu

DateDuration -  literal description of the difference between given dates

Apps:

Touch - set the "modified" timestamp of a file to current time

Show For Files - tray menu to show/hide files extensions, hidden & system files, and selection checkboxes

SPDiff - Single-Pane Text Diff

 

Link to comment
Share on other sites

Link to comment
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).

Signature - my forum contributions:

Spoiler

UDF:

LFN - support for long file names (over 260 characters)

InputImpose - impose valid characters in an input control

TimeConvert - convert UTC to/from local time and/or reformat the string representation

AMF - accept multiple files from Windows Explorer context menu

DateDuration -  literal description of the difference between given dates

Apps:

Touch - set the "modified" timestamp of a file to current time

Show For Files - tray menu to show/hide files extensions, hidden & system files, and selection checkboxes

SPDiff - Single-Pane Text Diff

 

Link to comment
Share on other sites

Create an account or sign in to comment

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

Create an account

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

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

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