delphipathspecial-folderstopendialog

Getting Special Folder Path from OpenDialog selection in Delphi


I let my users select a folder via the OpenDialog component.

However, when they select a folder such as Documents or My Videos or something like that, the path is just the name of the folder.

I can get the path of such folder via the API, but how do I get the path based on what they've selected in the OpenDialog?


Solution

  • I believe that you are actually talking about a user selecting a Windows 7 library. In which case you need to use special code to find the default save location for that library.

    You need to use the IFileDialog interface to do this. If you use TOpenDialog then you don't have access to the IFileDialog interface. So you need to use the Vista dialog, TFileOpenDialog which does expose the IFileDialog interface.

    Once you have this interface you can obtain IShellItem interfaces for each selected shell item by calling GetResults for multi-select dialogs, and GetResult for single-select dialogs. You can then pass these IShellItem interfaces to a function like this:

    function ShellItemFileSystemPath(const si: IShellItem): string;
    var
      attribs: DWORD;
      pszPath: PChar;
      lib: IShellLibrary;
      defSaveFolder: IShellItem;
    begin
      OleCheck(si.GetAttributes(SFGAO_FILESYSTEM, attribs));
      if attribs=0 then begin
        // This could be a library, in which case we shall return the default save location
        if  Succeeded(CoCreateInstance(CLSID_ShellLibrary, nil, CLSCTX_INPROC_SERVER, IID_IShellLibrary, lib))
        and Succeeded(lib.LoadLibraryFromItem(si, STGM_READ))
        and Succeeded(lib.GetDefaultSaveFolder(DSFT_DETECT, IShellItem, defSaveFolder)) then begin
          Result := ShellItemFileSystemPath(defSaveFolder);
          exit;
        end;
        raise EValidityError.CreateFmt(
          'Cannot operate on ''%s'' because it is not part of the file system.',
          [ShellItemDisplayName(si)]
        );
      end;
      OleCheck(si.GetDisplayName(SIGDN_FILESYSPATH, pszPath));
      Try
        Result := pszPath;
      Finally
        CoTaskMemFree(pszPath);
      End;
    end;
    

    The code in the Embarcadero libraries should be doing this, but sadly that library code is deficient. It should be supporting Windows 7 libraries by now.

    Personally, I don't use the Embarcadero provided file dialogs because of this issue and others.