vba internationalization vista64 keyboard-layout

¿Cómo puedo llamar a ActivateKeyboardLayout desde Windows Vista de 64 bits utilizando VBA?



internationalization vista64 (6)

Al ejecutar VBA bajo XP, pude llamar a ActivateKeyboardLayout para cambiar mi idioma de entrada del inglés a otro idioma. Sin embargo, esto ya no funciona en Vista64.

¿Alguna sugerencia o solución alternativa?

El código que solía funcionar en XP era similar al siguiente:

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

Hubo una sugerencia para probar

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

Cuando intento esto, aparece el mensaje de error:

La variable utiliza un tipo de automatización no compatible con Visual Basic


Esto es solo una suposición ciega, pero ¿ha intentado ejecutar su aplicación como administrador elevado para ver si hace una diferencia? ¿Cuál es el código de error / valor de GetLastError?


¿ Probaste una línea .Net (como en el script VB.Net o esos fragmentos ) como:

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

InputLanguage debe ser compatible con Vista64 con .Net3.5

Código 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


Para la portabilidad de 64 bits puede necesitar usar IntPtr. ¿Puedes dar una oportunidad?

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


Su declaración para ActivateKeyboardLayout es realmente incorrecta. Para sistemas de 32 bits, su código debería ser algo como esto:

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

La 64-bitness del sistema operativo es un poco una arenga roja en este caso. Como está ejecutando una aplicación VBA, debe ejecutarse como una aplicación de 32 bits independientemente del sistema operativo. Sospecho que su problema puede ser que en su sistema Vista el diseño del teclado Punjabi que desea no esté cargado. ActivateKeyboardLayout solo funcionará para activar un diseño de teclado que ya está cargado. Por algún motivo, los diseñadores de esta API consideraron que el error debido a que la distribución del teclado no existía no era un error, por lo que LastDllError no está configurado. Es posible que desee considerar el uso de LoadKeyboardLayout para este tipo de situación.

EDITAR: Para verificar que el diseño del teclado que está tratando de obtener esté realmente cargado, puede usar esto:

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


Lo que todos parecen pasar por alto aquí es que estás trabajando en VBA, no en .NET. IntPtr es un tipo .NET que representa un entero que es nativo de la plataforma. En una plataforma de 32 bits es de 32 bits, en una plataforma de 64 bits, es de 64 bits.

Dado que un HKL es un typedef para un handle, que es un typedef para PVOID que es un typedef para VOID *, es exactamente lo que necesita, si estaba usando .NET.

VBA no tiene nada para los números de 64 bits, por lo que debe tener un enfoque diferente.

En una máquina de 64 bits, tendrás que hacer algo como esto:

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

Esto debería permitirle pasar un valor de 64 bits en la pila a la función API (entre dos variables). Sin embargo, si va a utilizar este código en máquinas de 64 y 32 bits, tendrá que hacer dos declaraciones de la API y luego determinar a cuál llamar.

Además, cualquier otro código en VBA que llame a las API que tratan con punteros o manejadores tendrá que ser cambiado apropiadamente para manejar la entrada de 64 bits (no 32).

En una nota lateral, la declaración original de ActivateKeyboardLayout es incorrecta, ya que tenía un tipo de retorno de Entero, que es un valor de 16 bits, mientras que la API devuelve un tipo de HKL, que es de 32 o 64 bits, dependiendo de la plataforma .


En las ediciones de 64 bits de las aplicaciones de Office, VBA es de hecho de 64 bits. Consulte la documentación de Office 2010 para obtener detalles de los cambios. Para el ejemplo dado en la respuesta de Stephen Martin , deberá cambiar el código de la siguiente manera para agregar el atributo PtrSafe y corregir los parámetros que tienen un tipo HKL en la API de Win32:

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

y

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