This is working for me...
std::string GetProgramDataPath() {
CHAR path[MAX_PATH];
HRESULT hr = SHGetFolderPathA(nullptr, CSIDL_COMMON_APPDATA, nullptr, 0, path); // path accepted as LPSTR parameter?
if (SUCCEEDED(hr)) {
return std::string(path); // then automatically cast to const char*?
}
else {
return std::string();
}
}
...but I don't know why. I try to pass LPSTR, but I get:
Error C4700 "uninitialized local variable 'path' used"
I look up how to initialize LPSTR and come up with this:
std::string GetProgramDataPath() {
LPSTR path = new CHAR[MAX_PATH];
HRESULT hr = SHGetFolderPathA(nullptr, CSIDL_COMMON_APPDATA, nullptr, 0, path);
if (SUCCEEDED(hr)) {
std::string strPath(path);
delete[] path;
return std::string(strPath);
}
else {
delete[] path;
return std::string();
}
}
Is this the 'correct' code? With new and delete it seems wrong. Am I doing something unsafe by just using CHAR[]? How come it works instead of LPSTR? I believe it has something to do with the "equivalence of pointers and arrays" in C, but it seems there are some automatic conversions from CHAR[] to LPSTR to const char * in this code I don't understand.
CodePudding user response:
Instead of managing the memory your self with new and delete I'd use a std::string instead and let it manage the memory.
static std::string GetProgramDataPath()
{
std::string buffer(MAX_PATH, '\0');
const HRESULT result = SHGetFolderPathA
(
nullptr,
CSIDL_COMMON_APPDATA,
nullptr,
0,
buffer.data()
);
if (SUCCEEDED(result))
{
// Cut off the trailing null terminating characters.
// Doing this will allow you to append to the string
// in the position that you'd expect.
if (const auto pos{ buffer.find_first_of('\0') }; pos != std::string::npos)
buffer.resize(pos);
// Here is how you can append to the string further.
buffer.append(R"(\Some\Other\Directory)");
return buffer;
}
buffer.clear();
return buffer;
}
CodePudding user response:
This is working for me...but I don't know why.
LPSTR is just an alias for CHAR* (aka char*):
typedef CHAR *LPSTR;
In certain contexts, a fixed-sized CHAR[] (aka char[]) array will decay into a CHAR* (aka char*) pointer to its 1st element, such as when passing the array by value in a function parameter, as you are doing.
I try to pass
LPSTR, but I getError C4700 "uninitialized local variable 'path' used".
Because LPSTR is just a pointer, and you likely did not point it at anything meaningful.
Is this the 'correct' code?
Technically yes, that will work (though return std::string(strPath) should be return strPath instead). However, you should consider using std::string or std::vector<char> instead to manage memory for you, don't use new[]/delete[] directly, eg:
std::string GetProgramDataPath() {
std::vector<char> path(MAX_PATH);
HRESULT hr = SHGetFolderPathA(nullptr, CSIDL_COMMON_APPDATA, nullptr, 0, path.data());
if (SUCCEEDED(hr)) {
return std::string(path.data());
}
return std::string();
}
Am I doing something unsafe by just using
CHAR[]?
No.
How come it works instead of
LPSTR?
Because CHAR[] decays into the same type that LPSTR is an alias of.
it seems there are some automatic conversions from
CHAR[]toLPSTRtoconst char *in this code.
Correct.
