Pregunta

Ejecutando 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?

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 recibo el mensaje de error:

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

¿Fue útil?

Solución

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 bits del sistema operativo es un poco falsa 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 alguna razón, los diseñadores de esta API consideraron que la falla debido a que el diseño 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 la distribución del teclado que está intentando cargar esté cargada, 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

Otros consejos

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

¿Intentó con un .Net line (como en Script VB.Net o esos fragmentos ) como:

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

InputLanguage debería ser compatible con Vista64 con un .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, es posible que deba usar IntPtr. ¿Puedes darle una oportunidad a esto?

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

En las ediciones de 64 bits de las aplicaciones de Office, VBA es de hecho de 64 bits. Consulte documentación de Office 2010 para Detalles de los cambios. Para el ejemplo dado en 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 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

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 número entero nativo de la plataforma. En una plataforma de 32 bits, tiene 32 bits, en una plataforma de 64 bits, tiene 64 bits.

Dado que un HKL es un typedef para un identificador, 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 números de 64 bits, por lo que debe adoptar un enfoque diferente.

En una máquina de 64 bits, tendrá 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

Este debería permitirle pasar un valor de 64 bits en la pila a la función API (a través de dos variables). Sin embargo, si va a usar este código en máquinas de 64 bits 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 se ocupan de punteros o controladores tendrá que cambiarse adecuadamente para manejar la entrada de 64 bits (no 32).

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

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top