Why doesn’t SHGetKnownFolderPath return the customized path?

A customer reported that the SHGet­Known­Folder­Path function was not working correctly. They moved their Videos folder to a new location, but when they called SHGet­Known­Folder­Path, they got the old path rather than the new one.

A quick check of the code they provided showed why:

                      KF_FLAG_DONT_VERIFY |

Um, you're passing the KF_FLAG_DEFAULT_PATH flag. That flag means "Tell me where this folder would have been if its location had never been customized." Therefore, if you pass this flag, you have no right to complain that it's returning a path different from the customized path. Because passing that flag means "I don't want the customized path."

Comments (23)
  1. Michael says:

    The amp-shy-semicolon in the function name in the first paragraph lacks a semicolon toward the end of the function name. A real web browser handles this nicely, but my RSS reader balked at it.

    Thanks for an otherwise great blog.

    [Fixed, thanks. -Raymond]
  2. BC_Programming says:

    "Pray, Mr. Babbage, if you put into the machine wrong figures, will the right answers come out?"

  3. Rick C says:

    @BC_Programming: I am not able rightly to apprehend the kind of confusion of ideas that could provoke such a question.

    Isn't it nice that 150 years later we still have the same problem?

  4. Peter says:

    I actually feel sorry for this customer.  MS support cases are too valuable commodity to waste just because no one can be bothered to read MSDN.

  5. Ben says:

    @Peter – And Stack Overflow is going the same way.

  6. David Ching says:

    The customer should have known better before filing an incident report.  Still, it illustrates the all-too-familiar trait of Win32 API's to use bitfields like KE_FLAG_DEFAULT_PATH instead of modern, readable constructs like enum FolderPath { DefaultLocation, CustomizedLocation }.  You don't have these problems with .NET, which is a much more readable API.  Of course, it helps that bitfields are no longer needed to achieve adequate performance (in most cases).

  7. Killer{R} says:

    I suspect next question of cusomer was 'how to customize default-not-custimized path returned due to KF_FLAG_DEFAULT_PATH"

  8. Clovis says:

    I suspect the next question of customer was 'Can I haz teh codez'?

  9. Anonymous Coward says:

    David Ching, your bitfield thing is bullshit. Compare this:

    SHGetKnownFolderPath(FOLDERID_Videos,                      KF_FLAG_DONT_VERIFY | KF_FLAG_DEFAULT_PATH, NULL, ppszPath);



    I agree that .Net's names look cleaner, but that's mostly because I hate ALL CAPS; it looks like shouting to me.

  10. Killer{R} says:

    shouting or not, but all macro defines in Windows SDK were definitely written by a blonde.

  11. SimonRev says:

    I suspect that the reason that the Windows SDKS are filled with macros instead of enums is because C and C++ (pre C++11) left the size of an enumerated item to be implementation defined.  This effectively means no enums because if my compiler decides to treat a particular enum as 1 byte and the one the SDK authors used used 4 byte enums, then all sorts of hilarity will ensue (the shrapnel of which Raymond would have had to pick up and write an entertaing blog entry about).

    [It's much simpler than that. The coding conventions for the Windows SDK were established six years before enums were added to the C language. You're asking why they didn't use the Space Shuttle to rescue the Apollo 13 astronauts. -Raymond]
  12. @SimonRev:  I have run into exactly this hilarity because the Windows SDK developers forgot this concept a long time ago.  A simple grep shows the header files are chock full of enums.

    Older versions of a competing non-Microsoft C++ compiler (and possibly still true today) have a checkbox for treating enum types as ints.  Guess what the default is?  Hint: I spent a good bit of time debugging an issue before I realized that sizeof(some enum) == 1, and the enum was passed to the Win32 API as some function parameter or structure member.

    For all I know, checking this box breaks compatibility with another programming language provided by the same company, but the projects I work with don't use that language apart from 3rd-party components.

    Either the developers of this compiler were short-sighted and never thought of this compatibility issue with existing Windows headers when they picked sizeof(enum) != sizeof(int), or Microsoft started adding enums to their headers after this compiler started doing that and MS didn't care about the breakage.

  13. David Ching says:

    @AC:  Your second example shows it is indeed easier to have one parameter for each option instead of jamming all the options into one dwFlags parameter as is done in the API!  Then it forces the caller to specify each option instead of (perhaps accidentally) omitting it.  For example, either the KF_FLAG_DEFAULT_PATH or 0 must be the 7th parameter.  Even this is not great because it is not obvious that '0' means customized path.  Better to add #define KF_FLAG_CUSTOMIZED_PATH 0.  The enum replaces #defines with something typesafe and even more readable (since the KF_FLAG_ prefix can be omitted, so there is less crud to read).  Using bitfield instead, not specifying KF_FLAG_DEFAULT_PATH is the same as specifying "Customized Path", but it is not clear from reading the caller code, since bitfields are entirely optional.

  14. David Ching says:

    @JamesJohnston:  I believe, but am not certain, the reason for Turbo/Borland C++ treating enums as bytes (and not ints) by default was to save memory.  Back then, Windows programming had a lot of performance issues, such as DS != SS in a DLL, thus the overhead of thunks, so the "enum as int" non-optimization was considered part of the Windows penalty.  I also believe that if you created a new Windows project, that it would default the option to treat enum as int (for Windows compatibility). Back then, it was more important to create highly performant DOS programs, and it was understood that if you wanted to program in Windows, you would pay a performance penalty.

  15. Anonymous Coward says:

    Oh, that's a disappointment. David was just trolling.

  16. Drak says:

    @Peter: I didn't need to read MSDN to see what was wrong here. It's kind of obvious to me from the name of the bit.

  17. asdbsd says:

    @JamesJohnston: Delphi has this flag too ("Minimum enum size"). You can also mark certain enums to use specific size (like with field alignment), and I believe Builder has that too.

  18. Matt says:

    @SimonRev: That problem isn't a real problem anyway, because Microsoft just puts in a MS_EXPAND_ENUM_TO_FOUR_BYTES = 0x7fffffff at the end of the enum whenever they use enums to force the size.

  19. Anonymous Coward says:

    Matt, that was funny. You made me grep.

  20. Not a Win32 programmer says:

    What's the use case for wanting to know where a folder was before the user customized its location? If I (as a user) move my Videos folder to the D: drive or whatever, I don't want random programs trying to access the ghost of the folder at its old location.

  21. Timothy Byrd says:

    @Not a Win32 Programmer: How about resetting things back to stock after some 3rd party program co-opts the video folder because it's so special?

  22. Drak says:

    @Not a Win32 programmer: you could use it to check if the current path is the default path, I suppose.

  23. couch says:

    @Not a Win32 programmer : use case IMHO is internal APIs not differing from public APIs, internally you need to know this so why not expose it. (e.g. reset to default button)

Comments are closed.