2

The following code gets different results on different machines. One machine just gives the desktop folder (not desired) the other gives the desktop folder and Computer, mapped drives (desired).

procedure TForm1.Button1Click(Sender: TObject);
var
  Directory : String;
begin
  FileCtrl.SelectDirectory('Caption', 'Desktop', Directory, [sdNewUI, sdShowEdit]);
end;

One one machine it gives:

Bad Browse

On another it gives:

Good Browse

This feels like a windows setting, but I am not sure where to start. Using Delphi XE, Windows 10.

Any thoughts are appreciated. Thanks for your time.

user1627960
  • 421
  • 1
  • 3
  • 10
  • 1
    If it were me I'd use the new common file item dialog introduced in Vista which is the native folder picker – David Heffernan May 11 '16 at 15:03
  • To show the root Desktop namespace, you should be setting the `Root` parameter to an empty string (`''`) instead of `'Desktop'`. – Remy Lebeau May 11 '16 at 17:20
  • Thanks @RemyLebeau! Using `''` instead of `'Desktop'` solved my issue. – user1627960 May 11 '16 at 19:37
  • That is because the real name is `''` but the display name is `'Desktop'`. Some folders (actually, on e.g. a German Windows, quite a few folders) have different display and real names. – Rudy Velthuis May 12 '16 at 06:33

1 Answers1

4

Workaround
Use a TFileOpenDialog instead*.
Set FileOpenDialog1.Options:= [fdoPickFolders,fdoPathMustExist]

enter image description here

Now you have a dialog that:

  • Always works.
  • Allows copy paste

*) Not to be confused with the TOpenDialog, which does not allow you to only select folders.

Solution for Windows XP
Note that the new TFileOpenDialog only works for Vista and above.
Your program will not work on XP if you include this control.
If you start the dialog on XP it will generate an EPlatformVersionException.

You may want to use the following code instead if you want to be backward compatible:

uses JclSysInfo; //because you have XE use JCL.

...
var
  WinMajorVer: Integer;
  Directory: string;
  FileDialog: TFileOpenDialog;
begin
  WinMajorVer:= GetWindowsMajorVersionNumber;
  if WinMajorVer < 6 then begin //pre-vista
    //To show the root Desktop namespace, you should be setting the Root parameter to an empty string ('') instead of 'Desktop'
    FileCtrl.SelectDirectory('Caption', '', Directory, [sdNewUI, sdShowEdit]);
  end else begin
    FileDialog:= TFileOpenDialog.Create(self);
    try
      FileDialog.Options:= [fdoPickFolders,fdoPathMustExist];
      if FileDialog.Execute then Directory:= FileOpenDialog1.FileName;
    finally
      FileDialog.Free;
    end;
  end;
  Result:= Directory;
end;

Recommended reading:
detect windows version

EDIT

FileCtrl.SelectDirectory('Caption', 'Desktop', Directory, [sdNewUI, sdShowEdit]);

The 'Desktop' goes into the Root parameter, which is handled like so:

...
    SHGetDesktopFolder(IDesktopFolder);
    IDesktopFolder.ParseDisplayName(Application.Handle, nil,
      Root, Eaten, RootItemIDList, Flags);
...

Here's what MSDN for IDesktopFolder.ParseDisplayName has to say:

pszDisplayName [in]
Type: LPWSTR
A null-terminated Unicode string with the display name. Because each Shell folder defines its own parsing syntax, the form this string can take may vary. The desktop folder, for instance, accepts paths such as "C:\My Docs\My File.txt". It also will accept references to items in the namespace that have a GUID associated with them using the "::{GUID}" syntax.

Note that the documentation states that the desktop folder will accept paths and guids. It does not accept 'Desktop'. Because that's neither.

The fact that 'Desktop' as a root works on one system but not another is some undocumented fix made in an older/newer version of the IDesktopFolder interface.

Technical solution
Use '' as a 'root' as shown in my code above.

Obviously SelectDirectory is a really bad design by Microsoft that should never be used. It just sucks in so many ways. I recommend it not be used whenever possible.

Community
  • 1
  • 1
Johan
  • 74,508
  • 24
  • 191
  • 319
  • The *app* will still work on XP, but the *dialog* will not (`EPlatformVersionException` is raised when the dialog is invoked at runtime). – Remy Lebeau May 11 '16 at 17:23
  • @RemyLebeau, Thanks for clearing that up. I don't have XP to test, so I was not sure what would happen. Given that it does start on XP I've added some workaround code. – Johan May 11 '16 at 17:44
  • `if WinVer in ...` - OUCH! It would be much easier to use `if Win32MajorVersion < 6 then ...` instead. And use a `try/finally` to free the `TFileOpenDialog`. – Remy Lebeau May 11 '16 at 18:29