Thursday morning wrestling: LCID vs. HKL

by Michael S. Kaplan, published on 2004/12/16 12:11 -05:00, original URI: http://blogs.msdn.com/b/michkap/archive/2004/12/16/318271.aspx


Time to take a look at two very important datatypes, the LCID (locale identifier) and the HKL (the handle to an input method). They have several things in common, and more importantly several crucial differences. I'll let you decide which one is better....

First the LCID -- its defined in (among other places) winnt.h, as follows:

typedef DWORD LCID;

Being a DWORD means it is a 32-bit value. There is a great diagram of how the LCID is laid out in the winnt.h header file:

//
//  A locale ID is a 32 bit value which is the combination of a
//  language ID, a sort ID, and a reserved area.  The bits are
//  allocated as follows:
//
//       +-------------+---------+-------------------------+
//       |   Reserved  | Sort ID |      Language ID        |
//       +-------------+---------+-------------------------+
//        31         20 19     16 15                      0   bit
//

(The diagram was never updated to include the sort version information that now takes up some of that reserved space. But there are not yet any different sort versions so its probably not too important.)

Now the Language ID includes all of the information on language, region, and script. And LCIDs are taken as parameters in almost every single NLS function since they all need some locale-specific context, but almost all of them use the LANGID portion only.

Ok, now we'll look at the HKL. It is defined in (among other places) the wtypes.h header file:

typedef void *HKL;

On 32-bit platforms, a void pointer is the same size as a DWORD. But not all platforms are 32-bit (more on this in a moment).

There is no great diagram of how the HKL is laid out, but if there were it would something like this on 32bit platforms:

//
//  An HKL is a pointer which is the combination of a
//  language ID and device-specific information.  The bits are
//  allocated as follows:
//
//       +-----------------------+-------------------------+
//       |  Handle-specific info |      Language ID        |
//       +-----------------------+-------------------------+
//        31                   16 15                      0   bit
//

Obviously this is not a traditional sort of Windows handle value, since it has documented meaning (most handles have some meaning but it is seldom documented and the directions always say to treat them as opaque, unparseable values).

Now what happens when you run on a 64-bit platform? Well, nothing really. The extra 32 bits that the HKL now contains are not used. Seems like a waste, huh?

Well, not entirely. And in the long run I wish that LCIDs had been done the same way since one never knows how that data could have been used. Imagine if we had wanted the NLs functions to take the string "0409" or "0x0409" or maybe even "en-US" rather than the plain old number -- had this been a handle then it would be easy to set up a semantic where it would be a string pointer, but since it was not then it cannot be a string since there are 64-bit platforms.

Of course HKLs do not really have such a need, so for them it is just wasted space. But haven't we all been in the situation where a friend has something that they do not really need but that we probably could have found a use for? Thats definitely the case here -- they do have it and don't need it, we don't have it and do need it!

A little more information about HKLs -- they are not the same as keyboard layout identifiers (KLIDs). Though both contain a LANGID in the bottom WORD of the low DWORD, the top WORD of the low DWORD contains handle-specific info in one case and device-specific info in the other.

Also, there is no rule that the two LANGID values in the KLID and the HKL have to match. Since the "Add a keyboard layout" UI in Windows allows one to add a keyboard under an arbitrary language, the important distinction is that the KLID's LANGID is the intended language of the input method and the HKL's LANGID is the user-selected language of the input method. This feature can be put to use by putting (for example) one of the English (US) keyboards under the UK English language in order to give hints to Word about the language to use for spelling checks. And I'm sure you can imagine it being put to bad use by putting a keyboard under a language that has nothing to do with it and then watching programs like Word act very confused about how to use the language.

If I had to choose which I thought was more useful and scalable, I'd have to pick the HKL. But I guess the grass is always greener on the other side of the SDK....


no comments

referenced by

2008/09/29 What a tangled web we weave when a KLID from an HKL we must receive

go to newer or older post, or back to index or month or day