如何使用 VBA 从 64 位 Windows Vista 调用 ActivateKeyboardLayout

发布于 2024-07-11 18:35:39 字数 617 浏览 16 评论 0原文

在 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 中不支持的自动化类型

Running VBA under XP I was able to call ActivateKeyboardLayout to switch my input language from English to another language. However, this no longer works under Vista64.

Any suggestions or workarounds?

The code that used to work under XP was similar to the following:

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

There was a suggestion to try

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

When I try this I get the error message:

Variable uses an Automation type not supported in Visual Basic

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

不语却知心 2024-07-18 18:35:40

您对 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

Your declaration for the ActivateKeyboardLayout is actually incorrect. For 32-bit systems your code should be something like this:

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

The 64-bitness of the operating system is a bit of a red herring in this case. Since you are running a VBA app it must be running as a 32-bit app regardless of OS. I suspect your problem may be that on your Vista system the Punjabi keyboard layout that you want is not loaded. ActivateKeyboardLayout will only work to activate a keyboard layout that is already loaded. For some reason the designers of this API felt that failure due to the keyboard layout not existing was not an error so the LastDllError is not set. You may want to look into using LoadKeyboardLayout for this type of situation.

EDIT: To double check that the keyboard layout you are trying to get is actually loaded you can use this:

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
风透绣罗衣 2024-07-18 18:35:40

这只是一个盲目的猜测,但是您是否尝试过以提升的管理员身份运行您的应用程序,看看是否会有所不同? GetLastError 的错误代码/值是多少?

This is just a blind guess, but have you tried running your app as elevated administrator to see if it makes a difference? What's the error code / value of GetLastError?

庆幸我还是我 2024-07-18 18:35:40

您是否尝试过。网络行(如 VB .Net 脚本那些片段),例如:

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

InputLanguage 应支持具有 .Net3 的 Vista64。 5

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

Did you try a .Net line (as in VB.Net script or those snippets) like:

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

InputLanguage should be supported for Vista64 with a .Net3.5

VB.Net code:

Public Sub ChangeInputLanguage(ByVal InputLang As InputLanguage)
   If InputLanguage.InstalledInputLanguages.IndexOf(InputLang) = -1 Then
        Throw New ArgumentOutOfRangeException()
   End If
    InputLanguage.CurrentInputLanguage = InputLang
End Sub
泅人 2024-07-18 18:35:40

对于 64 位可移植性,您可能需要使用 IntPtr。 你能尝试一下吗?

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

For 64-bit portability you may need to use IntPtr. Can you give this a shot?

Public Declare Function ActivateKeyboardLayout Lib "user32" (ByVal nkl As IntPtr, ByVal Flags As uint) As Integer
萌面超妹 2024-07-18 18:35:40

在 64 位版本的 Office 应用程序中,VBA 确实是 64 位的。 请参阅 Office 2010 文档了解更改的详细信息。 对于 Stephen Martin 的回答<中给出的示例/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

In 64-bit editions of Office apps, VBA is indeed 64-bit. See Office 2010 documentation for details of the changes. For the example given in Stephen Martin's answer, you will need to change the code as follows to add the PtrSafe attribute and fixup the parameters that have a HKL type in the Win32 API:

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

and

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
因为看清所以看轻 2024-07-18 18:35:40

每个人似乎都忽略了一点,那就是您是在 VBA 中工作,而不是在 .NET 中工作。 IntPtr 是一种 .NET 类型,表示平台本机的整数。 在32位平台上它是32位,在64位平台上它是64位。

鉴于 HKL 是句柄的 typedef,它是 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

应该允许您将堆栈上的 64 位值传递给 API 函数(跨两个变量)。 但是,如果您要在 64 位和 32 位计算机上使用此代码,则必须对 API 进行两个声明,然后确定调用哪一个。

此外,VBA 中调用处理指针或句柄的 API 的任何其他代码都必须进行适当更改才能处理 64 位输入(而不是 32 位)。

附带说明一下,ActivateKeyboardLayout 的原始声明是错误的,因为它的返回类型为 Integer,这是一个 16 位值,而 API 返回的是 HKL 类型,这是 32 位或 64 位,具体取决于平台。

The thing that everyone seems to overlook here is that you are working in VBA, not in .NET. IntPtr is a .NET type which represents an integer which is native to the platform. On a 32-bit platform it is 32 bits, on a 64 bit platform, it is 64 bits.

Given that an HKL is a typedef for a handle, which is a typedef for PVOID which is a typedef for VOID *, it's exactly what you need, if you were using .NET.

VBA doesn't have anything for 64-bit numbers, so you have to take a different approach.

On a 64-bit machine, you will have to do something like this:

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

This should allow you to pass a 64 bit value on the stack to the API function (across two variables). However, if you are going to use this code on 64 bit and 32 bit machines, you are going to have to make two declarations of the API and then determine which one to call.

Also, any other code in VBA that calls APIs that deal with pointers or handles will have to be changed appropriately to handle 64 bit input (not 32).

On a side note, the original declaration of ActivateKeyboardLayout is wrong, as it had a return type of Integer, which is a 16-bit value, while the API returns a type of HKL, which is 32 or 64 bits, depending on the platform.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文