Shirish11
Shirish11

Reputation: 1617

delphi get folder path

I m working with Delphi 7 and I want to find out the path of my .. /All Users/Documents directory.
I came across the following code

uses shlobj, ...

function GetMyDocuments: string;
 var
  r: Bool;
  path: array[0..Max_Path] of Char;
 begin
  r := ShGetSpecialFolderPath(0, path, CSIDL_Personal, False) ;
  if not r then 
    raise Exception.Create('Could not find MyDocuments folder location.') ;
  Result := Path;
 end;

It works fine but it does not support CSIDL_COMMON_DOCUMENTS which returns the desired path.

Moreover as per MS CSIDL should no longer be used instead use KNOWNFOLDERID .
And I do need to work this app on multiple OS's (only windows).

How can I do this ?
Help is appreciated :)

Upvotes: 10

Views: 16081

Answers (4)

IceCold
IceCold

Reputation: 21231

As recommended by Embarcadero in this doc: VistaUACandDelphi.pdf

Uses SHFolder;

function GetSpecialFolder (CSIDL: Integer; ForceFolder: Boolean = FALSE): string;
CONST SHGFP_TYPE_CURRENT = 0;
VAR i: Integer;
begin
 SetLength(Result, MAX_PATH);
 if ForceFolder
 then ShGetFolderPath(0, CSIDL OR CSIDL_FLAG_CREATE, 0, 0, PChar(Result))= S_ok
 else ShGetFolderPath(0, CSIDL, 0, 0, PChar(Result));
 i:= Pos(#0, Result);
 if i> 0
 then SetLength(Result, pred(i));

 Result:= Trail (Result);
end;

Use it like this:

s:= GetSpecialFolder(CSIDL_LOCAL_APPDATA, true);

Upvotes: 2

whosrdaddy
whosrdaddy

Reputation: 11860

As David already stated, use the SHGetSpecialFolderPath function. Vista and W7 will do the CSIDL/Folder conversion for you. If you want to use the newer API, This should to the trick: Please note that this will only work from vista.

unit Unit1;

interface

uses
  Windows, ActiveX, Forms, SysUtils, OleAuto, Dialogs;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;


type
 TShGetKnownFolderPath = function(const rfid: TGUID; dwFlags: DWord; hToken: THandle; out ppszPath: PWideChar): HResult; stdcall;

var
  Form1: TForm1;

implementation

{$R *.dfm}

function ShGetKnownFolderPath(const rfid: TGUID; dwFlags: DWord; hToken: THandle; out ppszPath: PWideChar): HResult;

var Shell: HModule;
    Fn: TShGetKnownFolderPath;

begin
 Shell := LoadLibrary('shell32.dll');
 Win32Check(Shell <> 0);
 try
  @Fn := GetProcAddress(Shell, 'SHGetKnownFolderPath');
  Win32Check(Assigned(Fn));
  Result := Fn(rfid, dwFlags, hToken, ppszPath);
 finally
  FreeLibrary(Shell);
 end;
end;

function GetPublicDocuments: string;
 var
  ret: HResult;
  Buffer: PWideChar;
begin
  ret := ShGetKnownFolderPath(StringToGuid('{ED4824AF-DCE4-45A8-81E2-FC7965083634}'), 0, 0, Buffer) ;
  OleCheck(ret);
  try
   Result := Buffer;
  finally
    CoTaskMemFree(Buffer);
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
 ShowMessage(GetPublicDocuments);
end;

end.

Upvotes: 3

Anya Shenanigans
Anya Shenanigans

Reputation: 94859

Aren't you supposed to use ShGetFolderPath from shell32.dll? This assumes using windows 2000 with IE5 or newer.

you need to add shlobj to the uses line for the code that makes use of it.

As there is no definition for SHGetFolderPath in the source, you can use the following before the code that uses it:

function SHGetFolderPath(hwnd: HWND; csidl: Integer; hToken: THandle; dwFlags: DWORD; pszPath: PChar): HResult; stdcall; external 'shfolder.dll' name 'SHGetFolderPathA';

Delphi 7 does not make use of the Wide version of the routine, so you can use this code.

Upvotes: 4

David Heffernan
David Heffernan

Reputation: 613572

In my view there's nothing wrong with calling SHGetSpecialFolderPath passing CSIDL_COMMON_DOCUMENTS. If you need to support XP then you can't use known folder IDs. You could write code that used known folder IDs on Vista and up, and fell back to CSIDL on earlier systems. But why bother? MS have done that for you with SHGetSpecialFolderPath.

Upvotes: 8

Related Questions