Jump to content
erix

Convert a special folder to a path

Recommended Posts

Hello, 

When using the "FileSelectFolder" command and the user chooses a special folder (Documents, Pictures, Vidéos) the result obtained is not the folder path but a CLSID of type :
"::{450D8FBA-AD25-11D0-98A8-0800361B1103}"

I would like to be able to recover the path of the folder even if the user uses a special folder, but I have not yet found a method to convert a CLSID to a path.

I have tested commands like _WinAPI_ShellGetSpecialFolderPath but this one doesn't seem to take into account CLSID but CSIDL.
So I tried to find a method to convert CLSIDs into CSIDL, but I didn't find anything either.

Would you have a method to retrieve the path when a user selects a special folder or command that converts CLSIDs to a path?

Thank you.

Eric

Share this post


Link to post
Share on other sites

@JLogan3o13 

Thank you for your answer.
Please test with this simple code:

$folder = FileSelectFolder("", "")
MsgBox(4096,"",$folder)

And select one of the special folders

special_folders.jpg.48d0413ae44b5608195d4a1b2ef09622.jpg

I use Windows 7 French and Autoit 3.3.14.5

The result obtained is :

result.jpg.43671b5e98c82cf148170edab759159f.jpg

 

Share this post


Link to post
Share on other sites

A Library is a logical representation of one or more folders.  A library does not resolve to a specific folder.  Therefore, what folder are you thinking you can get when a user selects a Library?

 

Edited by TheXman

Share this post


Link to post
Share on other sites

erix,

when you run "explorer shell:libraries"

This  opens the root libraries folder. if I'm guessing  right ..

TheXman,

I guess that is all what erix is after ..

Deye

Edited by Deye

Share this post


Link to post
Share on other sites

Without designating an initial path (by leaving it the null value) for FileSelectFolder, my guess is that it would open in the default opening folder for Windows Explorer. You can set that, or you can manually set it to be whatever folder you'd like in the second parameter.


Who lied and told you life would EVER be fair?

Share this post


Link to post
Share on other sites

This is also a problem on an English Windows 7.

Here SHCreateItemFromParsingName is used to get a pointer to an IShellItem interface. Then the name can be displayed with $oIShellItem.GetDisplayName:

#include <WinAPI.au3>

Global Const $sIID_IShellItem = "{43826D1E-E718-42EE-BC55-A1E261C37BFE}"
Global Const $tIID_IShellItem = _WinAPI_GUIDFromString( $sIID_IShellItem )
Global Const $dtag_IShellItem = _
  "BindToHandler hresult(ptr;clsid;clsid;ptr*);" & _
  "GetParent hresult(ptr*);" & _
  "GetDisplayName hresult(int;ptr*);" & _
  "GetAttributes hresult(int;int*);" & _
  "Compare hresult(ptr;int;int*);"

Func SHCreateItemFromParsingName( $sPath, $pbc, $riid, ByRef $ppv )
  Local $aRet = DllCall( "Shell32.dll", "long", "SHCreateItemFromParsingName", "wstr", $sPath, "struct*", $pbc, "struct*", $riid, "ptr*", 0 )
  If @error Then Return SetError(1, 0, 0)
  $ppv = $aRet[4]
  Return $aRet[0]
EndFunc


Example()

Func Example()
  Local $pIShellItem
  SHCreateItemFromParsingName( "::{450D8FBA-AD25-11D0-98A8-0800361B1103}", 0, $tIID_IShellItem, $pIShellItem )

  Local $oIShellItem = ObjCreateInterface( $pIShellItem, $sIID_IShellItem, $dtag_IShellItem )

  Local $pName, $sName
  $oIShellItem.GetDisplayName( 0, $pName )
  $sName = DllStructGetData( DllStructCreate( "wchar[512]", $pName ), 1 )
  ConsoleWrite( $sName & @CRLF )
EndFunc

 

Share this post


Link to post
Share on other sites

@TheXman If in the Libraries folder I click on Document, I would like to have the Document path.

@LarsJ Sorry, but my level is not high enough to understand how to get the path with this code.

I thought it was going to be something simple, but I feel like I came across something more complicated than I thought.

Thank you for your help anyway

Share this post


Link to post
Share on other sites

Perhaps this will make it clearer...

;@LarsJ
#include <WinAPI.au3>

Global Const $sIID_IShellItem = "{43826D1E-E718-42EE-BC55-A1E261C37BFE}"
Global Const $tIID_IShellItem = _WinAPI_GUIDFromString($sIID_IShellItem)
Global Const $dtag_IShellItem = _
        "BindToHandler hresult(ptr;clsid;clsid;ptr*);" & _
        "GetParent hresult(ptr*);" & _
        "GetDisplayName hresult(int;ptr*);" & _
        "GetAttributes hresult(int;int*);" & _
        "Compare hresult(ptr;int;int*);"
Global Const $SIGDN_FILESYSPATH = 0x80058000
Global Const $SIGDN_DESKTOPABSOLUTEEDITING = 0x8004c000


Func SHCreateItemFromParsingName($sPath, $pbc, $riid, ByRef $ppv)
    Local $aRet = DllCall("Shell32.dll", "long", "SHCreateItemFromParsingName", "wstr", $sPath, "struct*", $pbc, "struct*", $riid, "ptr*", 0)
    If @error Then Return SetError(1, 0, 0)
    $ppv = $aRet[4]
    Return $aRet[0]
EndFunc   ;==>SHCreateItemFromParsingName

;;https://www.tenforums.com/tutorials/3123-clsid-key-guid-shortcuts-list-windows-10-a.html
Local Const $sMyDocs = "::{450D8FBA-AD25-11D0-98A8-0800361B1103}"
Local Const $sControlPanel = "::{5399E694-6CE5-4D6C-8FCE-1D8870FDCBA0}" ; (not actually a valid path...)
Local Const $sUserFiles = "::{59031a47-3f72-44a7-89c5-5595fe6b30ee}"
Local Const $sGames = "::{ED228FDF-9EA8-4870-83b1-96b02CFE0D52}"
Local Const $sThisPc = "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}"

Example($sMyDocs)
Example($sControlPanel)
Example($sUserFiles)
Example($sGames)
Example($sThisPc)
Example("C:\Windows")



Func Example($spath_clsid)
    Local $pIShellItem
    SHCreateItemFromParsingName($spath_clsid, 0, $tIID_IShellItem, $pIShellItem)

    Local $oIShellItem = ObjCreateInterface($pIShellItem, $sIID_IShellItem, $dtag_IShellItem)
    If Not IsObj($oIShellItem) Then
        ConsoleWrite("!Error no object" & @CRLF)
        Return ;
    EndIf

    Local $pName, $sName, $pAttribs
    $oIShellItem.GetAttributes($SFGAO_FILESYSTEM, $pAttribs)
    If BitAND($pAttribs, $SFGAO_FILESYSTEM) = $SFGAO_FILESYSTEM Then
        $oIShellItem.GetDisplayName($SIGDN_FILESYSPATH, $pName)
        $sName = DllStructGetData(DllStructCreate("wchar[512]", $pName), 1)
        ConsoleWrite($sName & @CRLF)
    Else ;; In relation to Desktop
        $oIShellItem.GetDisplayName($SIGDN_DESKTOPABSOLUTEEDITING, $pName)
        $sName = DllStructGetData(DllStructCreate("wchar[512]", $pName), 1)
        ConsoleWrite(@DesktopDir & "\" & $sName & @CRLF)
    EndIf
EndFunc   ;==>Example

 

Edited by Bilgus

Share this post


Link to post
Share on other sites

I am beginning to understand how it works and also that it is not that simple. :D

Thank you for all this information.

Share this post


Link to post
Share on other sites
16 hours ago, vincend said:

the result is mediocre, the best way is _WinAPI_ShellGetKnownFolderPath ()

AFAICT folderIDs <> Folder CLSIDs

 

#include <WinAPIShellEx.au3>
ConsoleWrite('"' & _WinAPI_ShellGetKnownFolderPath('{031E4825-7B94-4dc3-B131-E946B44C8DD5}') & '" @error = ' & @error & ' @extended = 0x' & Hex(@extended) & @CRLF)

;Results:
;"" @error = 10 @extended = 0x80070002

 

Share this post


Link to post
Share on other sites

Here is the same example but using WinAPI instead of COM

 

#include <WinAPI.au3>

Func GetShellPath($sPath_Clsid)
    ;@Bilgus
    Local Const $SIGDN_FILESYSPATH = 0x80058000
    Local Const $SIGDN_DESKTOPABSOLUTEEDITING = 0x8004c000
    Local $iError = 0, $iErrExt = 0, $sReturn = ""
    Local $aRet = DllCall("shell32.dll", "LONG", "SHParseDisplayName", _
                                         "WSTR", $sPath_Clsid, _
                                         "PTR", 0, _
                                         "PTR*", 0, _
                                         "ULONG", $SFGAO_FILESYSTEM, _
                                         "ULONG*", 0)
    If @error Or $aRet[0] Then
        $iError = 1
        $iErrExt = $aRet[0]
    Else
        Local $pPIDL = $aRet[3]
        Local $bFileSystem = ($aRet[5] = $SFGAO_FILESYSTEM)
        Local $iSIGDN = $SIGDN_FILESYSPATH
        If Not $bFileSystem Then $iSIGDN = $SIGDN_DESKTOPABSOLUTEEDITING

        ; Retrieve the path from PIDL
        $aRet = DllCall("shell32.dll", "INT", "SHGetNameFromIDList", _
                                       "PTR", $pPIDL, "LONG", $iSIGDN, "PTR*", 0)
        If Not (@error And $aRet[0]) Then
            $sReturn = _WinAPI_GetString($aRet[3])
            _WinAPI_CoTaskMemFree($aRet[3])
        Else
            $iError = 2
            $iErrExt = $aRet[0]
        EndIf

        DllCall("shell32.dll", "NONE", "ILFree", "PTR", $pPIDL) ; Free PIDL
    EndIf
    Return SetError($iError, $iErrExt, $sReturn)
EndFunc   ;==>GetPath

;;https://www.tenforums.com/tutorials/3123-clsid-key-guid-shortcuts-list-windows-10-a.html
Local Const $sMyDocs = "::{450D8FBA-AD25-11D0-98A8-0800361B1103}"
Local Const $sControlPanel = "::{5399E694-6CE5-4D6C-8FCE-1D8870FDCBA0}" ; (not actually a valid path...)
Local Const $sUserFiles = "::{59031a47-3f72-44a7-89c5-5595fe6b30ee}"
Local Const $sGames = "::{ED228FDF-9EA8-4870-83b1-96b02CFE0D52}"
Local Const $sThisPc = "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}"
Local Const $sLibraries = "::{031E4825-7B94-4dc3-B131-E946B44C8DD5}"

Example($sMyDocs)
Example($sControlPanel)
Example($sUserFiles)
Example($sGames)
Example($sThisPc)
Example($sLibraries)
Example("C:\Windows")



Func Example($spath_clsid)
    ConsoleWrite(GetShellPath($spath_clsid) & @CRLF)
EndFunc   ;==>Example

 

Edited by Bilgus

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

×
×
  • Create New...