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
1 Response
[…] Load and init keyboard-dlls in a 64-bit enviroment (KbdLayerDescriptor) […]