32 bit vs. 64 bit HKLs?

by Michael S. Kaplan, published on 2006/08/01 03:05 -04:00, original URI: http://blogs.msdn.com/b/michkap/archive/2006/08/01/684909.aspx

The question from Josh went something like this:

The 64 bit version of ToUnicodeEx is apparently sensitive to the high-order DWORD of the HKL parameter. I noticed this with the Turkish F keyboard which has an HKL of 0xfffffffff014041f in a 64-bit process. Attempting to send 0x00000000f014041f into ToUnicodeEx results in an empty string returned.

My problem is that I have HKLs coming to me from both 32 and 64 bit applications, and I need to know what I should be doing to turn the 32-bit HKL into the equivalent 64-bit HKL. It looks like the high order DWORD on a 64-bit HKL is only ever 0 or MAXDWORD, but it isn’t clear to me when it should be one vs. the other.

We ended up with a theory (though I was initially thinking of it more like a bug, to be honest), but the theory was one that Hiro confirmed a couple of days later.

Does anyone reading this know what is going on here? Or why I was thinking of it more as a bug? Or what other KLID values like the MSKLC-generated ones like "A0000409" might produce in the way of the HKLs on 64-bit in this case?


This post brought to you by (U+0f47, a.k.a. TIBETAN LETTER JA)

# SDiZ on 1 Aug 2006 4:08 AM:

I would treat that as a bug.

# Igor Tandetnik on 1 Aug 2006 7:46 AM:

I believe it's by design. See


"USER and GDI handles are sign extended 32b values" section.

# Michael S. Kaplan on 1 Aug 2006 10:24 AM:

Hi Igor,

Heh, you stole my thunder on the explanatory text. :-)

It is indeed by design. Though speaking personally, I would have done it a bit differently had it been up to me (obviously it wasn't!).

# Michael S. Kaplan on 1 Aug 2006 10:29 AM:

From the link:

USER and GDI handles are sign extended 32b values
To facilitate the porting, a decision has been made that these system handles should stay as 32b values, sign extended to 64b on the 64b platform. That is, the individual handle types are still based on the HANDLE type, which maps to void *, and so the size of the handle is the size of the pointer, i.e. 4 bytes on 32b and 8 bytes on 64b. However, the actual value of the handle on the 64b platform, (i.e. the meaningful bits), fits within the lower 32b, while the upper bits just carry the sign.

This should make it easy to port the majority of the application code. Handling of the special values, like –1, should be fairly transparent. It also should agree nicely with all the cases where the handles had been remoted with the help of the IDL definitions from the public file wtypes.idl. However, care needs to be taken when remoting the handles was done via a DWORD, as the upper long should be properly sign extended on the 64b side. The app should use HandleToLong() and LongToHandle() macros (inline functions) to do the casting right.

So, in general we can have the following situations:

A handle like HWND, HMENU, HPALETTE, HBITMAP etc was sent as its own type (that is specified with HMENU, etc. as the type of the argument) – do nothing, ole32.dll code handles situation as appropriate
A handle was sent as a DWORD – you can:
leave it as such and cast the wire value to handle using LongToHandle()
change the argument to long or LONG_PTR; this is possible in some cases only,
When designing a new interface, in order of preference: use the types themselves, use context handles or use a LONG64 argument to hack through.
Going back to specifics of porting the legacy code, the following system handles fall into the nice 32b compatible category.



# Mihai on 1 Aug 2006 12:19 PM:

Ok, is clear this is cause by signed extension.
But I think is a bug, because the doc sais:
"The low word contains a Language Identifier for the input language and the high word contains a device handle to the physical layout of the keyboard"

Another theory is that the ffff is not because of the sign, but because is Turkish F keyboard.
For the Turkish Q keyboard it will be 0xqqqqqqqqf014041f :-)

# Michael S. Kaplan on 1 Aug 2006 1:38 PM:

Well, that part is a doc bug, at least. :-)

It is clear that you have to convert it from a signed 64bit pointer to a signed 32bit pointer prior to doing the operations on the HKL if you need to do any....

referenced by

2010/05/04 The wacky world of WOW64 keyoards, un-leashed, un-locked, un-something-or-other

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

2006/08/07 Fixing a bug in the documentation

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