在C#中,我们经常会使用P/Invoke调用系统API,比如下面这段代码:

[DllImport("user32.dll", EntryPoint = "GetForegroundWindow", SetLastError = true)]
public static extern int GetForegroundWindow();

在这段代码中,我们使用int类型作为GetForegroundWindow函数的返回值类型,这其实是有风险的。实际上,这个API返回一个句柄(HWND,参考资料:GetForegroundWindow function (winuser.h)),而句柄其实是一个指针(POINTER,参考资料:Windows Data Types),使用int类型来代替指针,在某些情况下会有问题。

在C#中,int类型是32位有符号整数,而指针在不同的平台上有不同的大小。在32位系统,int类型确实与指针等价,但是在64位系统,指针最大可以占用64位,这显然超出了int类型的范围。而IntPtr解决了这个问题,它会根据不同的情况,使自己能够储存一个指针,或者在这种情况下,储存一个句柄。

但在实际编程中,使用int类型却不一定会导致问题,这是因为目前所运行的程序大部分都是32位的,即便是64位,所产生的句柄也不一定超出32位大小,这些情况下不会有句柄数据丢失的问题。但无论如何,这个写法都是错误的,特别是现在64位越来越流行的趋势下。

正确的代码如下:

[DllImport("user32.dll", EntryPoint = "GetForegroundWindow", SetLastError = true)]
public static extern IntPtr GetForegroundWindow();