【问题标题】:GetAsyncKeyState DLLImport statementGetAsyncKeyState DLLImport 语句
【发布时间】:2017-08-11 13:34:24
【问题描述】:

我遇到了需要根据操作系统更改我正在使用的 DLL 导入语句的情况。我想知道是否有其他人观察到这一点,知道原因,或者是否有更好的方法来处理这个问题。

这是显示问题的最小代码 sn-p。这是一个简单的命令行应用,只输出 shift 键的状态。

using System;
using System.Runtime.InteropServices;

namespace Shift
{
    class Program
    {
        [DllImport("user32.dll", SetLastError = true)]
        public static extern short GetAsyncKeyState(ushort virtualKeyCode);

        static void Main(string[] args)
        {
            Console.WriteLine("Shift is: " + GetAsyncKeyState(0x10));
        }
    }
}

在 Windows 8.1 x64 上运行或构建为 32 位并在 Windows 7 x64 上运行时,上述内容对我来说很好。但是,当为 x64 编译时,它不适用于 Windows 7 系统。在这种情况下,GetAsyncKeyState 总是返回 0。

如果我将 DLLImport 更改为以下内容,则在为 x64 编译时它可以在 Windows 7 系统上运行。

[DllImport("user32.dll", SetLastError = true)]
public static extern short GetAsyncKeyState(int virtualKeyCode);

【问题讨论】:

  • 最初的声明有一个错误。 (ushort 是 16 位,int 是 32 位 - 在 32 位和 64 位操作系统上所有版本的 Windows)。任何事情都可能发生在一个错误上,包括它工作正常的错觉。那么你的问题是什么?
  • x64 有一个非常不同的调用约定,因为它有更多的寄存器。快速调用风格约定,前 4 个参数通过寄存器而不是堆栈传递。 x86 不允许将 16 位值压入堆栈,因此存在隐式整数提升。这隐藏了声明中的错误。声明此函数的最佳方式是使用 Keys 作为参数类型。所以你可以通过 Keys.ShiftKey,枚举很好。与 pinvoke.net 网站进行比较永远不会有什么坏处。
  • @SimonMourier 感谢您指出问题。
  • @HansPassant 感谢您对正在发生的事情的非常具体的描述。这就是我希望得到的答案。

标签: c# winapi interop pinvoke


【解决方案1】:

原来的声明是错误的。文档在这里:https://msdn.microsoft.com/en-us/library/windows/desktop/ms646293.aspx

这给出了如下声明:

SHORT WINAPI GetAsyncKeyState(
  _In_ int vKey
);

正确的 p/invoke 是:

[DllImport("user32.dll")]
public static extern short GetAsyncKeyState(int vKey);

请注意,我已经删除了SetLastError 的设置。文档没有提到 SetLastError 被调用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-20
    • 2016-05-16
    • 1970-01-01
    • 1970-01-01
    • 2018-05-14
    • 2011-02-03
    相关资源
    最近更新 更多