Jump to content

Convert a special folder to a path


erix
 Share

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

Link to comment
Share on other sites

  • Moderators

@erix can you please post an example of this? Also, what OS, language, and AutoIt version are you using? When I use FileSelectFolder on any of the special folders you mention I receive the path.

"Profanity is the last vestige of the feeble mind. For the man who cannot express himself forcibly through intellect must do so through shock and awe" - Spencer W. Kimball

How to get your question answered on this forum!

Link to comment
Share on other sites

  • Moderators

Not in Windows 10 and AutoIt 3.3.14.5

Nu-uh.PNG.6feb1b97eb80f8b5db3770c5be4b6ca9.PNG

Perhaps someone who has a French OS will wander by to assist.

"Profanity is the last vestige of the feeble mind. For the man who cannot express himself forcibly through intellect must do so through shock and awe" - Spencer W. Kimball

How to get your question answered on this forum!

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

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

 

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

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

 

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