Comment appeler ActivateKeyboardLayout à partir de Windows Vista 64 bits avec VBA
-
19-08-2019 - |
Question
Exécution de VBA sous XP, j’ai pu appeler ActivateKeyboardLayout pour faire passer ma langue de saisie de l’anglais à une autre langue. Toutefois, cela ne fonctionne plus sous Vista64.
Avez-vous des suggestions ou des solutions de contournement?
Le code qui fonctionnait sous XP était semblable au suivant:
Private Declare Function ActivateKeyboardLayout Lib "user32" ( _
ByVal HKL As Long, ByVal flags As Integer) As Integer
Const aklPUNJABI As Long = &H4460446
ActivateKeyboardLayout aklPUNJABI, 0
Il a été suggéré d'essayer
Public Declare Function ActivateKeyboardLayout Lib "user32" ( _
ByVal nkl As IntPtr, ByVal Flags As uint) As Integer
Lorsque j'essaie, le message d'erreur suivant s'affiche:
La variable utilise un type Automation non pris en charge dans Visual Basic
La solution
Votre déclaration pour ActivateKeyboardLayout est en réalité incorrecte. Pour les systèmes 32 bits, votre code devrait ressembler à ceci:
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
Les 64 bits du système d’exploitation sont un peu un fil rouge dans ce cas. Étant donné que vous exécutez une application VBA, celle-ci doit être exécutée en tant qu'application 32 bits, quel que soit le système d'exploitation. Je soupçonne que votre problème peut provenir du fait que la configuration de clavier Punjabi que vous souhaitez n'est pas chargée sur votre système Vista. ActivateKeyboardLayout fonctionnera uniquement pour activer une disposition de clavier déjà chargée. Pour une raison quelconque, les concepteurs de cette API ont estimé qu'une défaillance due à une disposition de clavier inexistante n'étant pas une erreur, la LastDllError n'est pas définie. Vous voudrez peut-être envisager d’utiliser LoadKeyboardLayout pour ce type de situation.
EDIT: Pour vérifier que la configuration de clavier que vous essayez d’obtenir est bien chargée, vous pouvez utiliser ceci:
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
Autres conseils
Ceci est juste une hypothèse aveugle, mais avez-vous essayé d'exécuter votre application en tant qu'administrateur élevé pour voir si cela fait une différence? Quel est le code / valeur d'erreur de GetLastError?
Avez-vous essayé un Ligne .Net (comme dans Script VB.Net ou ces extraits ) comme:
InputLanguage.CurrentInputLanguage =
InputLanguage.FromCulture(New System.Globalization.CultureInfo("ar-EG"))
InputLanguage devrait être prise en charge pour Vista64 avec un .Net3.5
Code 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
Pour une portabilité 64 bits, vous devrez peut-être utiliser IntPtr. Pouvez-vous donner un coup de feu?
Public Declare Function ActivateKeyboardLayout Lib "user32" (ByVal nkl As IntPtr, ByVal Flags As uint) As Integer
Dans les éditions 64 bits des applications Office, VBA est bien 64 bits. Consultez la documentation Office 2010 pour plus d'informations. détails des changements. Pour l'exemple cité dans réponse de Stephen Martin , vous devez modifier le code comme suit pour ajouter l'attribut PtrSafe
et corriger les paramètres associés à un type HKL
dans l'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
et
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
Ce que tout le monde semble oublier, c’est que vous travaillez en VBA, pas en .NET. IntPtr est un type .NET qui représente un entier natif de la plate-forme. Sur une plate-forme 32 bits, c'est 32 bits, sur une plate-forme 64 bits, c'est 64 bits.
Etant donné qu'un HKL est un typedef pour un handle, qui est un typedef pour PVOID qui est un typedef pour VOID *, c'est exactement ce dont vous avez besoin si vous utilisiez .NET.
VBA n’a rien pour les nombres 64 bits, vous devez donc adopter une approche différente.
Sur une machine 64 bits, vous devrez faire quelque chose comme ceci:
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
Ceci devrait vous permettre de transmettre une valeur 64 bits de la pile à la fonction API (à travers deux variables). Cependant, si vous envisagez d’utiliser ce code sur des machines 64 bits et 32 ??bits, vous devrez faire deux déclarations de l’API, puis déterminer laquelle appeler.
De même, tout autre code de VBA appelant des API traitant des pointeurs ou des descripteurs devra être modifié de manière appropriée pour gérer une entrée 64 bits (et non 32).
Sur une note de côté, la déclaration d'origine de ActivateKeyboardLayout est fausse, car elle avait un type de retour Integer, qui est une valeur de 16 bits, tandis que l'API renvoie un type de HKL, 32 ou 64 bits, en fonction sur la plate-forme.