Как я могу вызвать ActivateKeyboardLayout из 64-битной Windows Vista, используя VBA - PullRequest
5 голосов
/ 16 января 2009

Запустив 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

Ответы [ 6 ]

5 голосов
/ 16 февраля 2009

Ваше объявление для 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
0 голосов
/ 03 декабря 2016

В 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
0 голосов
/ 19 февраля 2009

Здесь, кажется, все упускают из виду то, что вы работаете в 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 бита, в зависимости на платформе.

0 голосов
/ 14 февраля 2009

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

Public Declare Function ActivateKeyboardLayout Lib "user32" (ByVal nkl As IntPtr, ByVal Flags As uint) As Integer
0 голосов
/ 13 февраля 2009

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

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
0 голосов
/ 16 января 2009

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

...