Abstract:
Hexadecimal locale IDs, saving user data on shutdown, and other bugs.

Created by Peter Kankowski
Last changed
Filed under Win32 programming

Share on social sitesReddit Digg Delicious Buzz Facebook Twitter

Dark corners in Microsoft's documentation

Microsoft Platform SDK was greatly improved since the times of Windows 95. Many errors in documentation were corrected; examples were added for common functions, etc. But descriptions for some functions still remain vague or incomplete.

Locale IDs are hexadecimal

The reference for EnumLocalesProc says lpLocaleString "points to a buffer containing a null-terminated locale identifier string", but it doesn't mention that locale ID is written in hexadecimal notation.

The description for GetLocaleInfo shares the same mistake: it says "If the information is a numeric value, the function converts the number to text using decimal notation". While this is true for LOCALE_IDEFAULTCODEPAGE or LOCALE_ICALENDARTYPE, it's simply wrong for LOCALE_ILANGUAGE. Locale ID is returned in hexadecimal if you use LOCALE_ILANGUAGE. Try this code:

LCID lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
                     SORT_DEFAULT);
GetLocaleInfo(lcid, LOCALE_ILANGUAGE, buff, NUM_OF(buff));
// Now lcid == 0x0409, buff == "0409"

Hexadecimal notation is non-obvious here because commonly used locale IDs contain only hexadecimal figures from 0 to 9 (for example, US English is 0409 hexadecimal, and German is 0407), so one may erroneously believe they are decimal. (BTW, decimal locale IDs are also used: English version of Visual Studio contains a folder "1033", which stands for English locale ID in decimal notation.)

Saving files on Windows shutdown

When Windows shuts down, it doesn't send WM_CLOSE and WM_DESTROY messages to your application. Many programmers are unaware of this because Platform SDK never states it explicitly. As a result, programs fail to save configuration files or user's data when you press power button. For example, old versions of 1by1 did not save the last played song (the author have corrected the bug already).

You should handle WM_QUERYENDSESSION or WM_ENDSESSION to avoid this problem in your programs. In the simplest case, use the same handler for WM_ENDSESSION and WM_DESTROY:

LRESULT CALLBACK WndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam) {
    switch(msg) {
        case WM_DESTROY:
        case WM_ENDSESSION;
            SaveConfig();
            FreeMemory();
            PostQuitMessage(0);
            return 0;
        ...
    }
}

Platform SDK says you need not call PostQuitMessage if the session is ending (wParam == TRUE for WM_ENDSESSION), but, for simplicity, you may wish to call PostQuitMessage always. Also, don't presume that you need not to free your memory because nobody will use it when the computer will be turned off :). WM_ENDSESSION may be sent to your application even if some other program has interrupted the shutdown process by returning FALSE in respond to WM_QUERYENDSESSION, so it's safer and easier to perform all termination steps.

Raymond Chen answered about this problem.

CDIS_SHOWKEYBOARDCUES meaning is reversed

CDIS_SHOWKEYBOARDCUES actually means "Hide keyboard cues". When the flag is set, a cue should be hidden; when it's cleared, the cue should be shown. The flag is named incorrectly and MSDN documentation does not explain this.

More dark corners

Raymond Chen sometimes fills up documentation weaknesses in his blog:

  • WM_GETDLGCODE is poorly documented, and that's why people keep asking how to catch Enter key or to prevent the text from being selected when switching focus to edit controls. You can find the answers in the KB article and in the Raymond Chen's blog.
  • If you pass "*.htm" to FindFirstFile, it will return not only *.htm files, but also *.html files. The latest version of Platform SDK briefly mentions this: it says that "the search includes the long and short file names" (previous versions were silent about this). Raymond Chen explains the reason for this strange behavior. To avoid the problem, you should filter out short names returned by FindFirstFile/FindNextFile (for example, using your own wildcard-matching function).

There is at least one shareware program that finds *.html files when you enter *.htm file mask. Beware of documentation errors, and if you know some of them, please add them here.

Peter Kankowski
Peter Kankowski

About the author

Peter is the developer of Aba Search and Replace, a tool for replacing text in multiple files. He likes to program in C with a bit of C++, also in x86 assembly language, Python, and PHP. He can be reached at kankowski@gmail.com.

Created by Peter Kankowski
Last changed

Leave your comment

Your name:


Comment:


Please ignore this field: