Как я могу вызвать ActivateKeyboardLayout из 64-разрядной Windows Vista с помощью VBA
-
19-08-2019 - |
Вопрос
Запустив 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 бита, в зависимости от на платформе.