Why does SHGetKnownFolderPath return E_FAIL for a known folder?


A customer reported having problems with the SH­Get­Known­Folder­Path function. I've left in the red herrings.

On Windows 7, I'm trying to retrieve the Internet folder with the following code:

if (OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken))
{
 HRESULT hr = SHGetKnownFolderPath(FOLDERID_InternetFolder,
                              KF_FLAG_DONT_VERIFY, hToken, &pszPath);
 ...
}

The call always fails with E_FAIL. What am I doing wrong? I tried passing NULL as the token, but that didn't help.

The reason the call fails has nothing to do with Windows 7 or the token. The call fails because FOLDERID_Internet­Folder is a virtual folder—there is no path in the first place!

The reason is that the folder you are requesting is a virtual folder (KF_CATEGORY_VIRTUAL). Virtual folders don't exist in the file system, so they don't have a path. SH­Get­Known­Folder­Item should work.

The customer appears to have misinterpreted this response in a way I wasn't expecting (but which sadly I've seen before):

I added the KF_CATEGORY_VIRTUAL flag, but I still get the same error back.

if (OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken))
{
 HRESULT hr = SHGetKnownFolderPath(FOLDERID_InternetFolder,
                              KF_FLAG_DONT_VERIFY | KF_CATEGORY_VIRTUAL,
                              hToken, &pszPath);
 ...
}

Um, no, that makes no sense at all. KF_CATEGORY_VIRTUAL is a KF_CATEGORY value, but the second parameter to SH­GetKnown­Folder­Path is a KNOWN_FOLDER_FLAG. You can't just combine unrelated values like that. It's like adding 3 grams to 12 meters.

And second, the KF_CATEGORY_VIRTUAL enumeration isn't something that you pass in to "override" anything. The point is that FOLDERID_Internet­Folder is a virtual folder: It has no path, so if you try to ask for its path, you'll just get an error back because the thing you're looking for simply doesn't exist.

I never did figure out what this customer was trying to do. Maybe they figured, since they can't download the Internet, they could at least try to do a Find­First­File on it.

Comments (38)
  1. laonianren says:

    I tried FindFirstFile on the internet and it returned info.cern.ch/…/TheProject.html

  2. Wladimir Palant says:

    Heh, the people who take the time to ask but don't spend any time reading the answer. Don't we all love those?

  3. Joshua Ganes says:

    "It's like adding 3 grams to 12 meters" – Cool, can you show me the function that converts grams to meters, I think I should be able to solve it from there :)

  4. Pierre B. says:

    A lot of times when people seem to not have read an answer, in reality it is that the answer went over their head so they grabbed whatever they could hold on to. Assume that the questioner doesn't know what a virtual folder is and has a mental model where everything has a path. Add to that that the function in the question and the function given in the answer have almost identical names, SHGetKnownFolderPath vs. SH­Get­Known­Folder­Item.

    Reading being sequential, I think that a good practice is to always put the correct answer as the first sentence in the answer. (And, for good measure and security, repeat it as the last sentence of the answer.) So, an answer with a potentially higher rate of success would be:

    "You have to call SH­Get­Known­Folder­Item() for FOLDERID_InternetFolder. Do not call SHGetKnownFolderPath(). The reason is that the folder you are requesting is a virtual folder (KF_CATEGORY_VIRTUAL). Virtual folders don't exist in the file system, so they don't have a path. You have to call SH­Get­Known­Folder­Item() for FOLDERID_InternetFolder."

  5. Skyborne says:

    Huh, it seems the response had a red herring, too: that BIG_NOTICEABLE_CONSTANT that wasn't going to solve their problem when sprinkled liberally on their code.

  6. Dan Bugglin says:

    @Pierre I like how you repeated the important bit twice.  For certain people, such as the example in the OP, I would recommend three or more times.

  7. Danny Moules says:

    @Pierre Unfortunately then you get accused of being patronising, even though you know darn fine well they'd have likely screwed up otherwise.

  8. Kyle says:

    @Joshua Ganes

    Well of course we can convert grams into meters!  Since e = mc^2, all we need to do is convert the mass into energy to accelerate some other mass.  Then, once we know how quickly the mass was converted into energy, then we can determine how far the accelerated mass went and add that value to our 12 meters.

    Simple, right?

  9. rs says:

    At least they didn't try KF_EXTENDED.

  10. dave says:

    Back in the 1990s, many valiant attempts were made to convert grams into metres; the methodology involved linear arrangement of powdered matter.

  11. bzakharin says:

    Forget energy. The answer is 1.06538394 Newtons.

    Assuming the object is 3 meters above sea level, to increase its mass by .003 kg, you must increase its weight by ((6.67300 × 10)^(-11))×(5.9742 × 10^24)(.003)/(12^2) = 1.06538394 Newtons

    Correct me if I'm wrong.

  12. bzakharin says:

    Sorry, I meant 12 meters

  13. Aaron.E says:

    @Boris,

    You seem to have a bit too much precision there.  There's really only significant figure, so I think the answer would be 1 Newton.

  14. Joshua Ganes says:

    Thanks for the help guys. I tried the following:

    if (OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken))

    {

    HRESULT hr = SHGetKnownFolderPath(FOLDERID_InternetFolder,

                                 KF_FLAG_DONT_VERIFY | KF_CATEGORY_VIRTUAL |

                                 1.06538394 * KF_UNIT_NEWTON,

                                 hToken, &pszPath);

    }

    This didn't work and also caused a bunch of compile errors. I think I'll try asking someone with a little more experience with this sort of issue.

  15. Nick says:

    I think the Win32 API needs to add a generic E_WTF error that's returned when you start passing random flags to functions.

  16. WndSks says:

    @Nick: For flag parameters you only have 32 bits to play with, there is going to be some overlapping and a lot of WTF errors =)

  17. AndyC says:

    I'd hazard a guess the FOLDERID_InternetFolder probably wasn't actually what they were after in the first place. It's possible they were after FOLDERID_InternetCache, although even more likely they were trying to figure out where Internet Explorer was installed.

  18. AndyC says:

    I'd hazard a guess the FOLDERID_InternetFolder probably wasn't actually what they were after in the first place. It's possible they were after FOLDERID_InternetCache, although even more likely they were trying to figure out where Internet Explorer was installed.

  19. Cheong says:

    @Bob: How funny… and why A: ? XDDDDDDDD

  20. Nick says:

    @WndSks: Just call it a sanity check local to the function being called.  I did actually make sure that the numeric value of KF_CATEGORY_VIRTUAL was not a valid KNOWN_FOLDER_FLAG :)  Who knows, maybe something like this even exists in checked builds of Windows.

    Besides, now we're rolling with 64 bits now baby… you can have twice as many flags for a parameter!

  21. Dan Bugglin says:

    Unrelated to this article… but related to this blog in general, so it might interest others.  Firefox 4 is going to auto-pin itself to your Windows 7 taskbar (well, if you set it as default browser).

    blog.mozilla.com/…/firefox-auto-pinned-to-the-win7-task-bar

    I immediately thought of Raymond's series of posts about user preferences vs applications forcing those prefs (Quick Launch shortcuts etc) and linked a few of those articles in the Firefox bug.

  22. Jolyon Smith says:

    @Nick – E-WTF sounds like something you'd find in a Yorkshire dialect version of Windows…

    Eee, Wot T' F***

    (like: "Eee-up, trouble at'mill lad").  That Mr 'erriot would be proud so he would.  'e's a raht fahn vet'nerian that one.

  23. Gabe says:

    It's easy to imagine how "SH­Get­Known­Folder­Item should work" got read as "SH­Get­Known­Folder­Path should work", causing the person to believe that you were confirming that they were calling the right function. In this situation it's better to include some error correction bits so that the sentence doesn't make sense if they misread it. For example, "SH­Get­Known­Folder­Item should work instead" or "Use SH­Get­Known­Folder­Item instead of SH­Get­Known­Folder­Path for this" or "Change the function to SH­Get­Known­Folder­Item".

  24. Rangoric says:

    @The Mazzter yeah great, one more reason to uninstall firefox. Now when it breaks later on, it will be Microsoft's fault. But at least now I can point to the creator of it SAYING it's a bad idea.

  25. PhilW says:

    Random thought: Something in (or akin to) the Standard Annotation Language that said "these flags belong in this parameter in these methods" would cause a warning (or worse) if they were used in the wrong way so that "KF_FLAG_DONT_VERIFY | KF_CATEGORY_VIRTUAL" would generate said warning/error (with appropriate compiler work, of course).

  26. Cheong says:

    @The MAZZTer: How does it different than adding the shortcut to "quick start", especially since "quick start" toolbar is not available by default in Win7?

    Consider which is more annoying – 1) create toolbar that did not exist before for me, with just 1 application shortcut being added. 2) pinning it to taskbar if available will relevent feature added to interact with, and can be easily unpinned.

    As long as they don't force it remain pinned on taskbar, I don't really think it does matter.

  27. Danny says:

    Downloading the internet issue.

    This will be very feasible in the next years as new mathematics will be invented (quantum math for example). What we lack currently is a proper compression algorithm, that is all, which is limited to known mathematics. So let's see how big internet currently is by crouching some numbers making some assumptions roughly – 8 billions people each having 10 TB system (there are some farm computer business and there are plenty people living at below poverty level, so let's assume that is the average) – results the internet size is 8 x 10^9 x 10^12 => 8 x 10^21 bytes for the internet size. Now invent a compress algorithm with a ratio of 8 x 10^21 / 1.44 x 10^6 => 1 : 5.56 x 10^15 compression ratio and you can fit the internet on a floppy. For those who will start to laugh may I remind that this is already been done by black holes who hold many more tones then 10^15 in a space smaller then the size of that floppy? Or that the Bing Bang theory is about the entire Universe being compressed to a size smaller then your pin roughly 15 billions years ago? Which makes our mathematics extremely primitive when you see that currently or in the past these compression rates already being implemented.

  28. GregM says:

    There are plenty of ways to compress the internet to fit on a floppy, the hard part is the decompression afterwards, since they're all extremely lossy compression algorithms.

  29. Gechurch says:

    @Cheong

    It's relative annoyance is not the issue (to see why, consider this more extreme example "Which is more painful -1) having your arm cut off. 2) Having your toe cut off. At least you can still walk with a missing toe."). It is taking something that should be a users choice and forcing it upon them. And it is doing it by using an unsupported hack – there is no supported way to programatically add your program to the taskbar.

    If you still think it doesn't matter, ask yourself one of Raymond's favorite questions – what if everyone did this? Would you still be happy if iTunes put itself and Quicktime in the taskbar? What about trial software that inadvertently came along with a flash player update? And what if so many programs did this that there was no longer room for items you pinned to the taskbar yourself? Would you still be happy? What about if the installer crashed under the next service pack of Windows 7, because the implementation detail this hack relies on changes?

  30. 640k says:

    This question is stupid. There's a much smarter way to retrieve the RIGHT answer:

    1. Write a program which calls the api with EVERY combination of every flag.

    2. Compare the result to what you want the api to return.

    3. When program gets the result it wants, that's the flags you should use!

  31. Danny says:

    @Greg

    I meant a compression algorithm with no loss of data at decompression, thought that was obvious with my examples especially since the "decompression" of Universe is still happening. Guess I have to be extremely specific cause kinder-garden kids reads the blog.

  32. Ben says:

    @Danny

    Poor trolling my friend. I'm afraid you will get no bites for your regrettable posts. Still, I implore you to consider bettering yourself. Stay in school, learn a trade, contribute something positive to society. With each comment like the one above, you make the world a little worse.

  33. Danny says:

    @Ben

    What I did is called sarcasm…trolling is what you just did. And speaking of school, go back to it and learn the difference between these 2 words (English teacher for you was the cleaning lady perhaps?)

  34. Ben says:

    Tsk tsk. Such poor manners; does your mother know you talk to people like this? I offer simple advice designed for your betterment, and you respond by insulting my  long suffering english teachers. For shame Danny, for shame!

  35. The customer's point stands.  E_FAIL is a terrible return code.

    If someone's passing a flag that doesn't exist, a more appropriate return code is E_INVALIDARG.

    If someone's looking for something that can't be found, a more appropriate return code is HRESULT_FROM_WIN32(ERROR_NOT_FOUND).  There's at least one API that #define's this as E_NOTFOUND.

  36. Cesar says:

    This flag confusion is why Qt has its QFlags template type, see doc.qt.nokia.com/…/qflags.html for details.

    Of course, this would not help if they were programming in C, but could be used to add a bit more type safety in C++.

    [Windows has it too (DEFINE_ENUM_FLAG_OPERATORS). Unfortunately, SHGetKnownFolderPath's flags parameter is a DWORD instead of a KNOWN_FOLDER_FLAG for backward compatibility. -Raymond]

Comments are closed.

Skip to main content