Flag behavior for the NLS APIs

by Michael S. Kaplan, published on 2005/03/29 02:18 -05:00, original URI: http://blogs.msdn.com/b/michkap/archive/2005/03/29/403216.aspx

Flags for APIs are an interesting thing, especially when you have APIs that you improve between versions. And the NLS APIs are no exception to this.

There are two ways one could handle flag values that are undefined in the current version of an API:

  1. You can disallow any unknown flag value.
  2. You can allow but ignore any unknown flag value.

Just in case people were not sure, by and large the NLS API use #1, something that I think most APIs do. While the ability to call the code just one way is nice, never being sure what the behavior is really not so nice. And when you look at APIs from the point of view of not knowing what will come next, you never want to add that kind of uncertainty to the mix for the future.

(Note that the one glaring exception to this is the LOCALE_NOUSEROVERRIDE flag, which actually gets pretty controversial when you get down to it (cf: When is it a backcompat break and when is it fulfilling not-yet-fulfilled technology?)

It was interesting working on the Microsoft Layer for Unicode, which tries to let people write Unicode applications. What to do with the flags that are NT-specific becomes an even more interesting set of debates with people who start each meeting claiming they have no strong feelings about the issue and end each meeting ready to kill the ignorant wingnuts who want Microsoft to go down in flames via their own bad decisions. Hopefully you'll see the counterpoint there....

On the whole I am happy with the behavior of the rest of the APIs (and with most of the behavior of GetLocaleInfo, et. al., ignoring the LOCALE_NOUSEROVERRIDE stuff). And that is speaking as a former external developer who had to write all of that version-specific code. Because I would rather see the API fail up front than appear to succeed while actually ignoring what I told it to do. An API that accepts but ignores random crap (and if you think about, all it is random crap when it is not yet defined) is not a very robust API....

Though I must admit as that same former external developer who had to write code against up to ten versions of Windows that the flags only working in some version and not others can be quite a pain to keep straight.

A smattering of flags that were added later:

And so on. All flags added for new functionality that on prior versions would cause the API to fail with an ERROR_INVALID_FLAGS return from GetLastError()...



# AC on 29 Mar 2005 11:42 AM:

Why aren't the new flags wrapped in proper #IFDEF values for Windows version? This would make passing the wrong flag a compile time error and then you could allow any flag without fear of breaking clients.

# Michael Kaplan on 29 Mar 2005 12:06 PM:

That is an excellent question! I'll cover this in a future posting....

# Dean Harding on 29 Mar 2005 3:45 PM:

Well, most people would just stick a #define _WINNT_WIN32 0x501 before they include windows.h anyway, so a #ifdef isn't going to help them. Besides, that would then mean if you want to use the new flag on newer Windows, but fallback to old behaviour on old windows, you don't have a choice but to test for the windows version...

Bartosz Wójcik on 5 Jan 2010 10:51 AM:

Hi, I have a question, what to use instead of LOCALE_SISO3166CTRYNAME on Windows 95???

Michael S. Kaplan on 5 Jan 2010 11:07 AM:

A system upgrade to a supported OS?

Bartosz Wójcik on 5 Jan 2010 2:05 PM:

Hi Michael :), I can't. Well I think I will stick to LOCALE_SENGCOUNTRY (I just hope those english country names   from WinNls.h [comments Country/Region Codes.] are correct :P), this looks like a most compatible solution...

