Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a new replacement for SHGetSpecialFolderLocation?

Tags:

c++

winapi

My app is written in C++Builder for Win32. My code uses the SHGetSpecialFolderLocation() API to get the CSIDL_APPDATA and CSIDL_MYDOCUMENTS paths.

I noticed on Microsoft's website dated 12/04/2018 that it says:

[SHGetSpecialFolderLocation is not supported and may be altered or unavailable in the future. Instead, use SHGetFolderLocation.]

Then for SHGetFolderLocation it says:

Deprecated

What is the current way to get these two paths?

My current code is below.

LPITEMIDLIST List = NULL;
wchar_t  wPath[MAX_PATH + 1];
UnicodeString S01, Fi;

if( !SHGetSpecialFolderLocation(0, CSIDL_APPDATA, &List) ){
  if( SHGetPathFromIDListW(List, wPath ) ){
    S01 = wPath;
    Fi = (S01+"\\my_files\\");
    Form1->MyRoamingPath_Mh = Fi;
  }
}
like image 630
homebase Avatar asked Jan 21 '19 20:01

homebase


1 Answers

SHGetSpecialFolderLocation() was first introduced in Windws 95/NT4. It was deprecated in Windows 2000/XP in favor of SHGetFolderLocation() (which returns a folder location as an IDLIST_ABSOLUTE) and SHGetFolderPath() (which returns a folder location as a path string).

So, in your example, you could have used SHGetFolderPath() instead:

#include <Shlobj.h>
#include <SysUtils.hpp>

wchar_t wPath[MAX_PATH + 1];

if (SHGetFolderPathW(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, wPath) == S_OK)
{
    Form1->MyRoamingPath_Mh = IncludeTrailingPathDelimiter(wPath) + L"my_files\\";
}

In Vista, use of CSIDL was deprecated in favor of KNOWNFOLDERID. The above functions have been deprecated in favor of SHGetKnownFolderIDList()/IKnownFolder::GetIDList() and SHGetKnownFolderPath()/IKnownFolder::GetPath(), respectively.

This is actually stated at the bottom of the SHGetFolderLocation() documentation 1:

1: I guess you did not scroll down far enough to see it.

Note As of Windows Vista, this function is merely a wrapper for SHGetKnownFolderIDList. The CSIDL value is translated to its associated KNOWNFOLDERID and SHGetKnownFolderIDList is called. New applications should use the known folder system rather than the older CSIDL system, which is supported only for backward compatibility.

So, in your example, you can now use SHGetKnownFolderPath() instead:

#include <Shlobj.h>
#include <SysUtils.hpp>

PWSTR pwPath;

if (SHGetKnownFolderPath(FOLDERID_RoamingAppData, KF_FLAG_DEFAULT, NULL, &pwPath) == S_OK)
{
    try
    {
        Form1->MyRoamingPath_Mh = IncludeTrailingPathDelimiter(pwPath) + L"my_files\\";
    }
    __finally
    {
        CoTaskMemFree(pwPath);
    }
}

For the "My Documents" folder, use FOLDERID_Documents.

like image 120
Remy Lebeau Avatar answered Nov 20 '22 12:11

Remy Lebeau