【发布时间】: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 感谢您对正在发生的事情的非常具体的描述。这就是我希望得到的答案。