Как я могу вызвать ActivateKeyboardLayout из 64-разрядной Windows Vista с помощью VBA

StackOverflow https://stackoverflow.com/questions/449207

Вопрос

Запустив VBA под XP, я смог вызвать ActivateKeyboardLayout, чтобы переключить язык ввода с английского на другой язык.Однако это больше не работает под Vista64.

Есть какие-нибудь предложения или обходные пути?

Код, который раньше работал под управлением XP , был похож на следующий:

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

Было предложение попробовать

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

Когда я пытаюсь это сделать, я получаю сообщение об ошибке:

Переменная использует тип автоматизации, не поддерживаемый в Visual Basic

Это было полезно?

Решение

Ваше объявление для ActivateKeyboardLayout действительно неверно. Для 32-битных систем ваш код должен выглядеть примерно так:

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

В этом случае 64-разрядная версия операционной системы является чем-то вроде красной сельди. Поскольку вы используете приложение VBA, оно должно работать как 32-разрядное приложение независимо от ОС. Я подозреваю, что ваша проблема может быть в том, что в вашей системе Vista раскладка клавиатуры Punjabi, которую вы хотите, не загружена. ActivateKeyboardLayout будет работать только для активации раскладки клавиатуры, которая уже загружена. По какой-то причине разработчики этого API чувствовали, что сбой из-за несуществующей раскладки клавиатуры не был ошибкой, поэтому LastDllError не установлен. Возможно, вы захотите использовать LoadKeyboardLayout для такого типа ситуаций.

РЕДАКТИРОВАТЬ: чтобы дважды проверить, что раскладка клавиатуры, которую вы пытаетесь получить, действительно загружена, вы можете использовать это:

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

Другие советы

Это только слепое предположение, но пытались ли вы запустить свое приложение с повышенными правами администратора, чтобы понять, имеет ли это значение? Что такое код ошибки / значение GetLastError?

Вы пробовали .Net line (как в VB.Net скрипт или эти фрагменты ) вроде:

InputLanguage.CurrentInputLanguage = 
    InputLanguage.FromCulture(New System.Globalization.CultureInfo("ar-EG"))

InputLanguage должен быть поддерживается для Vista64 с .Net3.5

Код VB.Net:

Public Sub ChangeInputLanguage(ByVal InputLang As InputLanguage)
   If InputLanguage.InstalledInputLanguages.IndexOf(InputLang) = -1 Then
        Throw New ArgumentOutOfRangeException()
   End If
    InputLanguage.CurrentInputLanguage = InputLang
End Sub

Для 64-битной переносимости вам может потребоваться использовать IntPtr. Можете ли вы дать этому шанс?

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

В 64-разрядных версиях приложений Office VBA действительно 64-разрядный.Видишь Документация Office 2010 для получения подробной информации об изменениях.Для примера , приведенного в Ответ Стивена Мартина, вам нужно будет изменить код следующим образом , чтобы добавить PtrSafe присваивайте и исправляйте параметры, которые имеют HKL введите в Win32 API:

Private Declare PtrSafe Function ActivateKeyboardLayout Lib "user32" (ByVal HKL As LongPtr, _
    ByVal flags As Long) As LongPtr

Const aklPUNJABI As LongPtr = &H4460446
Dim oldLayout as LongPtr
oldLayout = ActivateKeyboardLayout(aklPUNJABI, 0)
If oldLayout = 0 Then
   'Oops an error'
Else
   'Save old layout for later restore?'
End If

и

Private Declare PtrSafe Function GetKeyboardLayoutList Lib "user32" (ByVal size As Long, _
    ByRef layouts As LongPtr) As Long

Dim numLayouts As Long
Dim i As Long
Dim layouts() As LongPtr

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

Кажется, что все упускают из виду то, что вы работаете в VBA, а не в .NET. IntPtr - это тип .NET, представляющий целое число, свойственное платформе. На 32-битной платформе это 32 бита, на 64-битной платформе - 64 бита.

Учитывая, что HKL - это typedef для дескриптора, который является typedef для PVOID, который является typedef для VOID *, это именно то, что вам нужно, если вы использовали .NET.

В VBA нет ничего для 64-битных чисел, поэтому вы должны использовать другой подход.

На 64-битной машине вам нужно будет сделать что-то вроде этого:

Public Type HKL64
    High As Long
    Low As Long
End Type

Private Declare Function ActivateKeyboardLayout Lib "user32" ( _
    Byval HklHigh As Long, Byval HklLow As Long, _
    ByVal flags As Integer) As HKL64

Этот должен позволить вам передать 64-битное значение в стеке функции API (через две переменные). Однако, если вы собираетесь использовать этот код на 64-битных и 32-битных машинах, вам нужно будет сделать две декларации API и затем определить, какой из них вызывать.

Кроме того, любой другой код в VBA, который вызывает API, которые имеют дело с указателями или дескрипторами, должен быть соответствующим образом изменен для обработки 64-битного ввода (не 32).

Кстати, исходное объявление ActivateKeyboardLayout неверно, так как оно имеет тип возвращаемого значения Integer, представляющее собой 16-разрядное значение, в то время как API возвращает тип HKL, который составляет 32 или 64 бита, в зависимости от на платформе.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top