Watch, Follow, &
Connect with Us

For forums, blogs and more please visit our
Developer Tools Community.


Welcome, Guest
Guest Settings
Help

Thread: CSIDL vs FOLDERID in XE5 - Advice Sought


This question is answered.


Permlink Replies: 6 - Last Post: Sep 21, 2015 12:03 PM Last Post By: Remy Lebeau (Te... Threads: [ Previous | Next ]
Dominic Mahon

Posts: 14
Registered: 7/20/02
CSIDL vs FOLDERID in XE5 - Advice Sought  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Sep 20, 2015 10:16 AM
I am using XE5 and have been using CSIDL to get the paths for data storage etc.

I have have been using the following code:
{CODE}
dir_programdata:= GetSpecialFolderPath(CSIDL_APPDATA);
{/CODE}

and the function is:

{CODE}
function GetSpecialFolderPath(folder : integer) : string;
// REMEMBER: add Winapi.SHFolder to USES
const
SHGFP_TYPE_CURRENT = 0;
var
path: array [0..MAX_PATH] of char;
begin
if SUCCEEDED(SHGetFolderPath(0,folder,0,SHGFP_TYPE_CURRENT,@path[0])) then
Result := path else Result := '';
end;
{/CODE}

I read on MSDN CSIDL has been replaced by FOLDERID: ( https://msdn.microsoft.com/en-gb/library/windows/desktop/bb762494(v=vs.85).aspx )
"As of Windows Vista, these values have been replaced by KNOWNFOLDERID values. See that topic for a list of the new constants and their corresponding CSIDL values. For convenience, corresponding KNOWNFOLDERID values are also noted here for each CSIDL value. The CSIDL system is supported under Windows Vista for compatibility reasons. However, new development should use KNOWNFOLDERID values rather than CSIDL values."

However, my XE5 doesnt appear to know what these FOLDERID's are, and I cant seem to find out how to use them in Delphi via Google.

As I understand it, I should now be using FOLDERID_RoamingAppData, instead of CSIDL_APPDATA but:
Q1: does anyone have any idea how to implement it?
Q2: do I need to write a new function?

I was looking at TPath as an alternative but the folder list appears woefully incomplete.

Advice would be most welcome on the best way (excluding buying latest) of futureproofing/standardising my code

Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: CSIDL vs FOLDERID in XE5 - Advice Sought  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Sep 20, 2015 11:18 AM   in response to: Dominic Mahon in response to: Dominic Mahon
Dominic wrote:

I read on MSDN CSIDL has been replaced by FOLDERID

Yes, and has been since Vista.

However, my XE5 doesnt appear to know what these FOLDERID's are

Yes, it does, actually. You just need to include the relevent units in your
'uses' clause. See below.

I cant seem to find out how to use them in Delphi via Google.

These are the very first search results I see when searching on Google:

How to get folder path from Known folder GUID in Delphi
http://stackoverflow.com/questions/14802473/

Getting Vista Folder Paths
http://stackoverflow.com/questions/976509/

In particular, this comment is important:

In Delphi 2010, all the SHGetKnownFile functions are defined in the unit
"shlobj" The FOLDERID constants are in KnownFolders

So, try this code:

uses
  ..., Winapi.ShlObj, Winapi.KnownFolders;
 
function GetKnownFolderPath(const folder : KNOWNFOLDERID ) : string;
// REMEMBER: add Winapi.ShlObj to USES
var
  path: LPWSTR;
begin
  if SUCCEEDED(SHGetKnownFolderPath(folder, 0, 0, path)) then
  begin
    try
      Result := path;
    finally
      CoTaskMemFree(path);
    end;
  end else
    Result := '';
end;
 
dir_programdata:= GetKnownFolderPath(FOLDERID_RoamingAppData);


--
Remy Lebeau (TeamB)
Dominic Mahon

Posts: 14
Registered: 7/20/02
Re: CSIDL vs FOLDERID in XE5 - Advice Sought  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Sep 20, 2015 1:19 PM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Remy Lebeau (TeamB) wrote:
Thanks Remy, For some reason this site is blocked for me, .. odd.. will have to ask my SYSADMIN why

Remy Lebeau (TeamB) wrote:
finally
CoTaskMemFree(path);
end;
is this not redundant/overkill, or have I missed the blindingly obvious??

Sorry for asking dumb questions :-P
Carl-Henrik Nil...

Posts: 53
Registered: 3/26/02
Re: CSIDL vs FOLDERID in XE5 - Advice Sought  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Sep 20, 2015 2:14 PM   in response to: Dominic Mahon in response to: Dominic Mahon
Dominic Mahon wrote:
is this not redundant/overkill, or have I missed the blindingly obvious??

No, the documentation says:
'The calling process is responsible for freeing this resource once it is no longer needed by calling CoTaskMemFree.'
( https://msdn.microsoft.com/en-us/library/windows/desktop/bb762188%28v=vs.85%29.aspx )

Not all current FOLDERIDs are declared in XE5. Check this link:
( https://msdn.microsoft.com/en-us/library/dd378457%28v=VS.85%29.aspx )
--
C-H
Dominic Mahon

Posts: 14
Registered: 7/20/02
Re: CSIDL vs FOLDERID in XE5 - Advice Sought  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Sep 21, 2015 2:51 AM   in response to: Carl-Henrik Nil... in response to: Carl-Henrik Nil...
Carl-Henrik Nilsson wrote:
Dominic Mahon wrote:
is this not redundant/overkill, or have I missed the blindingly obvious??

No, the documentation says:
'The calling process is responsible for freeing this resource once it is no longer needed by calling CoTaskMemFree.'
( https://msdn.microsoft.com/en-us/library/windows/desktop/bb762188%28v=vs.85%29.aspx )

Not all current FOLDERIDs are declared in XE5. Check this link:
( https://msdn.microsoft.com/en-us/library/dd378457%28v=VS.85%29.aspx )
--
C-H

Thanks for this C-H

So it just good housekeeping,??
Leaving CoTaskMemFree(path) out of code was not reporting any leaks using "REPORTMEMORYLEAKSONSHUTDOWN=true" which prompted the question..

I only use a tiny set of FOLDERID's and most likely a weird logic, so wasn't planning on using KnownFolders.pas, thanks for heads up about inadequacies

my revised code - may help someone in future
{code}
procedure TForm1.SetMyDataDirectory(Sender:TObject);

function GetKnownFolderPath(const folder: KNOWNFOLDERID): string;
// REMEMBER: add Winapi.ShlObj to USES
var
path: LPWSTR;
begin
if SUCCEEDED(SHGetKnownFolderPath(folder, 0, 0, path)) then
begin
try
Result := path;
finally
CoTaskMemFree(path); //see note
end;
end
else
Result := '';
end;

const
//MATURE/FORMER CSIDL in KnownFolders.pas
FOLDERID_RoamingAppData : TGUID = '{3EB685DB-65F9-4CF6-A03A-E3EF65729F3D}';
FOLDERID_LocalAppData : TGUID = '{F1B32785-6FBA-4FCF-9D55-7B8E7F157091}';
FOLDERID_ProgramData : TGUID = '{62AB5D82-FDC1-4DC3-A9DD-070D1D495D97}';
//ADDED FOR WIN8.1+ not in in KnownFolders.pas for xe5
FOLDERID_SkyDrive : TGUID = '{A52BBA46-E9E1-435f-B3D9-28DAA648C0F6}';

var
oup:string;

begin
if global_multiuserlicence = true then
dir_programdata := GetKnownFolderPath(FOLDERID_ProgramData)
else
if global_keepdata_on_this_pc = true then
begin
if global_keepdata_same_dir = true then
dir_programdata := ExtractFilePath(Application.ExeName)+'\data'
else
dir_programdata := GetKnownFolderPath(FOLDERID_LocalAppData)
end else
begin
dir_programdata := GetKnownFolderPath(FOLDERID_RoamingAppData);
if global_use_localskydrive = true then
begin
oup:=GetKnownFolderPath(FOLDERID_SkyDrive);
if oup>'' then dir_programdata:= oup
else
ShowMessage('Cannot find your Onedrive Folder - Defaulting to Roaming: '+dir_programdata);
end;
end;
//create subdirectories (unixify);
dir_programdata := dir_programdata + '\' + ReplaceStr(global_sw_developer,
' ', '_') + '\' + ReplaceStr(global_sw_appname, ' ', '_');
ForceDirectories(dir_programdata);

end;

{/code}
Carl-Henrik Nil...

Posts: 53
Registered: 3/26/02
Re: CSIDL vs FOLDERID in XE5 - Advice Sought
Helpful
Click to report abuse...   Click to reply to this thread Reply
  Posted: Sep 21, 2015 3:40 AM   in response to: Dominic Mahon in response to: Dominic Mahon
Dominic Mahon wrote:
So it just good housekeeping,??

Well, we don't want resource leaks, do we?!

Leaving CoTaskMemFree(path) out of code was not reporting any leaks using "REPORTMEMORYLEAKSONSHUTDOWN=true"
which prompted the question..

Yes, the memory manager only reports leaks of memory it self has allocated.
--
C-H
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: CSIDL vs FOLDERID in XE5 - Advice Sought
Correct
Click to report abuse...   Click to reply to this thread Reply
  Posted: Sep 21, 2015 12:03 PM   in response to: Dominic Mahon in response to: Dominic Mahon
Dominic wrote:

So it just good housekeeping,??

No, the call to CoTaskMemFree() is required, per the documentation.

Leaving CoTaskMemFree(path) out of code was not reporting any leaks using
"REPORTMEMORYLEAKSONSHUTDOWN=true" which prompted the question..

ReportMemoryLeaksOnShutdown can only report leaks for memory that is allocated
by the RTL's memory manager. SHGetKnownFolderPath() is not using the RTL's
memory manager to allocate memory for the returned path. It is using the
Shell's memory manager instead. ReportMemoryLeaksOnShutdown cannot report
leaks for that.

--
Remy Lebeau (TeamB)
Legend
Helpful Answer (5 pts)
Correct Answer (10 pts)

Server Response from: ETNAJIVE02