如何使用 VBA 从 64 位 Windows Vista 调用 ActivateKeyboardLayout
-
19-08-2019 - |
题
在 XP 下运行 VBA 我能够调用 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 不支持的自动化类型
解决方案
您的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系统,你想没有加载旁遮普键盘布局上。 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
其他提示
这仅仅是一个盲目的猜测,但你尝试过运行你的应用作为提升的管理员,看它是否有差别?什么是GetLastError函数的错误代码/值?
你有没有尝试过 .Net线路 (如 VB.Net 脚本 或者 那些片段) 喜欢:
InputLanguage.CurrentInputLanguage =
InputLanguage.FromCulture(New System.Globalization.CultureInfo("ar-EG"))
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
有关的64位的可移植性您可能需要使用的IntPtr。你可以给这个一杆?
Public Declare Function ActivateKeyboardLayout Lib "user32" (ByVal nkl As IntPtr, ByVal Flags As uint) As Integer
在Office应用程序的64位版本,VBA确实64位。请参阅的Office 2010文档细节上的变化。对于斯蒂芬·马丁的答案<给出的例子/ A>,则需要改变代码,如下所示来添加PtrSafe
属性和修正内容具有Win32 API中一个HKL
类型的参数:
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
这是每个人似乎都在这里忽略的事情是,你是在VBA工作,而不是在.NET。 IntPtr的是代表一个整数,其是天然的平台.NET类型。在32位的平台它是32位,64位的平台上,它是64位。
假设一个HKL是一个把手,这是PVOID一个typedef这是VOID *的类型定义一个typedef,这正是你需要的,如果你使用.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
此应允许传递堆栈到API函数(跨越两个变量)上的64位值。但是,如果你要在64位和32台机器使用此代码,你将不得不使API的两个声明,然后确定要调用哪一个。
此外,在VBA任何其他代码调用与指针或句柄处理的API将必须被适当地改变,可处理64位输入端(未32)。
在一个方面说明,ActivateKeyboardLayout的原始声明是错误的,因为它有整数,它是一个16位值返回类型,而API返回一个类型HKL,它是32或64位,这取决于的在平台。