Our website is made possible by displaying online advertisements to our visitors. Please consider supporting us by whitelisting our website.

Load and init keyboard-dlls in a 64-bit enviroment (KbdLayerDescriptor)

This article is also published in codeproject.com and codeguru.com

When running a 32-bit application on a 64-bit system, the keyboard-dll-files does not work as expected, this class fixes that problem!

Demo and class is coded with Visual Studio 2010 using C++ and MFC-framework.

Download demo (193 KB) as shown below
Download source (42 KB) with kbd.h/kbd64.h and CKLL-class

Introduction

Windows uses kbd**.dll files to load keyboards. When loading a keyboard on a 32-bit application on a 64-bit system you’ll get a corrupted array.
This little hack will handle keyboard-dll loads for a 32-bit application, running on a 64-bit system.

Background

The problem was found during my creation of a onscreen keyboard that I wanted to be multilingual.
After searching several forums I didn’t find any good solution for the problem.
The DLL-import is the same on either systems, but after running init using KbdLayerDescriptor(), the array is actual corrupted. An element called pVkToWcharTable is always NULL. This array shows the connection between Virtual Keys (VK) and characters, pretty essential for presenting a keyboard 🙂

In the kbd.h header-file, from Microsoft DDK, this pointer is defined:

#if defined(BUILD_WOW6432)
    #define KBD_LONG_POINTER __ptr64
#else
     #define KBD_LONG_POINTER
#endif

This works great on a 32-bit application running a 32-bit system, but not on a 64-bit system.
If you define BUILD_WOW6432 and compile the application as 64-bit, the program works as expected.

What caused this strange behavior?

After doing a little research of the topic I found the probably cause in MSDN.
A pointer defined as __ptr32 is coerced on a 64-bit system. If the KbdLayerDescriptor() actually uses sizeof() and other functions to get the length, it probably goes out of range, in the array.

My solution is to create “my own” 64-bit variables using this define

#define KBD_LONG_POINTER64 __ptr64

Checkout the kbd64.h for all variables/functions renamed around this 64-bit define.
Kbd64.h is just a renamed kbd.h to ensure own defines for the 64-bit pointer.

The demo

The included demonstration shows how to get the dll inited and array filled correctly.
It does not show how to handle modifiers and dead-keys, that is not essential part of the subject.
If you are looking into handling dead-keys or wondering anything about these “strange” kbd**.dll files, check out Michael Kaplan Sorting it all Out and search for the KbdLayerDescriptor.

Using the code

The CKLL class has four public functions + one helper

//Loads the DLL into the handler
BOOL	LoadDLL(CString sKeyboardDll);
	
//Get the counts of virtual keys (VK)
USHORT	GetVKCount();

//Get the char(s) linked to that VK
CString	GetChar(USHORT iVK);

//Get the scan code(s) linked to that VK
CString GetSC(USHORT iVK);

//Helper: Return TRUE if 64-bit, false if 32-bit
BOOL	Is64BitWindows();

If you have already have written you’re own functions based on the kbd.h header from Microsoft, then you can use the kbd64.h header and replace the variables and add 64 in the end; for example PKBDTABLES -> PKBDTABLES64. Then you use the Is64BitWindows() to check what type of system the application is running on.

Check out the Fill32() and Fill64() function in the CKLL class to get an idea on how it works.

Points of Interest

The keyboard-dlls are created using the Microsoft Keyboard Layout Creator and by using the built-in functions you can easily create custom dlls without any hassle.

The connection between Scan Codes (SC) and physical layout is pretty interesting

Source

That makes it so much easier if you’re creating an onscreen keyboard, and using a keyboard language you never used.
The qwerty-range seems match every time, and you can also match it to Microsoft’s own Keyboard Layouts to ensure that it is right.

Feedback

If you have solved this problem differently, I would like to hear from you in the comment field!

History

v1.0 Init release to the public