Delphi Handbooks Collection


Delphi XE Handbook


Delphi 2010 Handbook


December 1, 2009

SHGetFolderPath and Default User

I've had a few issues with the SHGetFolderPath API, which are now solved.

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.

 





 

5 Comments

SHGetFolderPath and Default User 

Yes, the Ansi version calls the Unicode version with a
NULL token handle. So this call succeeds. Also the
Flags parameter is reset to 0 (There are two push $00
instructions).

However, I wonder why you are using $FFFF which is
65535 or Word(-1). So it was correct in the 16bit days
when -1 resolved to $FFFF. In a 32bit handle it just
becomes 65535 and that is unlikely a correct handle.

Always use THandle(-1) to get the correct result,
since 64bit Delphi will maybe get a THandle value with
64bit size. 
Comment by Christian Wimmer [http://blog.delphi-jedi.net] on December 1, 19:20

SHGetFolderPath and Default User 

Just forgot to mention.
The parameters are ignored only by the function
implemented in the SHFolder.dll library.

Shell32.dll does it right.
Comment by Christian Wimmer [http://blog.delphi-jedi.net] on December 1, 19:30

SHGetFolderPath and Default User 

Why do you pass CSIDL_PERSONAL in the Ansi-version, and CSIDL_MYDOCUMENTS in the two other snippets? Is that a 
copy-paste error perhaps?
Comment by Patrick van Logchem [http://www.everyangle.com] on December 2, 09:55

SHGetFolderPath and Default User 

Christian,

  good point, the wrong "-1" might caused extra trouble, 
but with the actual -1 value casted I got exactly the 
same error. Interesting you found the differences 
between SHFolder and the Shell library.

Patrick,

  CLSID_Personal and CLSID_MYDOCUMENT are defined as 
aliases one of the other. 
Comment by Marco Cantu [http://www.marcocantu.com] on December 2, 10:27

SHGetFolderPath and Default User 

"...with the actual -1 value casted I got exactly the 
same error. "
I don't understand. How does the source look like then?
It works for me with THandle(-1). 
Comment by Christian Wimmer [http://blog.delphi-jedi.net] on December 2, 23:51


Post Your Comment

Click here for posting your feedback to this blog.

There are currently 0 pending (unapproved) messages.