Over the last few days, I've had a few issues with the SHGetFolderPath API, which are now solved. It all started when I grabbed some Delphi existing code (pre-Unicode), with a call to:
OleCheck (SHGetFolderPath (Handle, CSIDL_MYDOCUMENTS, $FFFF, 0, PChar(szBuffer)));
By simply leaving the code as it was I got a Windows runtime error, "The Handle is Invalid". Might be the handle passed as first parameter, but it didn't help. Curious, I went back to the Ansi version of the function:
OleCheck (SHGetFolderPathA (Handle, CSIDL_PERSONAL, $FFFF, 0, PAnsiChar(szBuffer)));
This indeed worked and returned the path to my documents folder. Odd. Some more experiments and I realized I was binding the SHFolder unit, and not the ShlObj unit. The former hooks the SHGetFolderPath functions of the SHFolder.dll, provided by Windows for backwards compatibility. So I decided to link in the version in ShlObj. Now both calls raised the error! Not a progress, but as least it made some more sense.
Back to the function documentation, I notice by chance something I misread a few times:
"Assigning the hToken parameter a value of -1 indicates the Default User."
Yikes! The Default User, not the current user. The default user is the default configuration for any future user, and that folder simply doesn't exist, which is the reason for the error (Microsoft could use a slightly less generic error message, but that's another story). The older compatibility function probably ignored the parameter, while the newer version uses it. So all I had to do to fix my code was change it to:
OleCheck (SHGetFolderPath (Handle, CSIDL_MYDOCUMENTS, 0, 0, PChar(szBuffer)));
to get the correct result, "C:\Users\Marco\Documents". So it took me over an hour to write a number instead of another one. My productivity in terms of Lines of Code (LOC) was terrible, but I did fix the issue. This falls into the common case of code that works by chance (due to the system ignoring a parameter) and is very easy to break accidentally.