Search code examples
vbainternationalizationvista64keyboard-layout

How can I call ActivateKeyboardLayout from 64bit Windows Vista using VBA


Running VBA under XP I was able to call ActivateKeyboardLayout to switch my input language from English to another language. However, this no longer works under Vista64.

Any suggestions or workarounds?

The code that used to work under XP was similar to the following:

Private Declare Function ActivateKeyboardLayout Lib "user32" ( _
    ByVal HKL As Long, ByVal flags As Integer) As Integer
Const aklPUNJABI As Long = &H4460446
ActivateKeyboardLayout aklPUNJABI, 0

There was a suggestion to try

Public Declare Function ActivateKeyboardLayout Lib "user32" ( _
    ByVal nkl As IntPtr, ByVal Flags As uint) As Integer

When I try this I get the error message:

Variable uses an Automation type not supported in Visual Basic


Solution

  • Your declaration for the ActivateKeyboardLayout is actually incorrect. For 32-bit systems your code should be something like this:

    Private Declare Function ActivateKeyboardLayout Lib "user32" (ByVal HKL As Long, _
        ByVal flags As Long) As Long
    
    Const aklPUNJABI As Long = &H4460446
    Dim oldLayout as Long
    oldLayout = ActivateKeyboardLayout(aklPUNJABI, 0)
    If oldLayout = 0 Then
       'Oops an error'
    Else
       'Save old layout for later restore?'
    End If
    

    The 64-bitness of the operating system is a bit of a red herring in this case. Since you are running a VBA app it must be running as a 32-bit app regardless of OS. I suspect your problem may be that on your Vista system the Punjabi keyboard layout that you want is not loaded. ActivateKeyboardLayout will only work to activate a keyboard layout that is already loaded. For some reason the designers of this API felt that failure due to the keyboard layout not existing was not an error so the LastDllError is not set. You may want to look into using LoadKeyboardLayout for this type of situation.

    EDIT: To double check that the keyboard layout you are trying to get is actually loaded you can use this:

    Private Declare Function GetKeyboardLayoutList Lib "user32" (ByVal size As Long, _
        ByRef layouts As Long) As Long
    
    Dim numLayouts As Long
    Dim i As Long
    Dim layouts() As Long
    
    numLayouts = GetKeyboardLayoutList(0, ByVal 0&)
    ReDim layouts(numLayouts - 1)
    GetKeyboardLayoutList numLayouts, layouts(0)
    
    Dim msg As String
    msg = "Loaded keyboard layouts: " & vbCrLf & vbCrLf
    
    For i = 0 To numLayouts - 1
       msg = msg & Hex(layouts(i)) & vbCrLf
    Next
    
    MsgBox msg