Reputation: 1617
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
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
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
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
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