¿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