如何在32位平台上pinvoke到GetWindowLongPtr和SetWindowLongPtr?

我想P / Invoke到GetWindowLongPtr和SetWindowLongPtr ,我看到有关它们的相互矛盾的信息。

有些消息称,在32位平台上,GetWindowLongPtr只是一个调用GetWindowLong的预处理器宏,而GetWindowLongPtr不作为user32.dll中的入口点存在。 例如:

  • SetWindowLongPtr的pinvoke.net条目有一个静态方法,它检查IntPtr.Size,然后调用SetWindowLong或SetWindowLongPtr,注释说“遗留操作系统不支持SetWindowLongPtr”。 没有解释“遗留操作系统”的含义。
  • StackOverflow的答案是 “On 32bit系统GetWindowLongPtr只是一个指向GetWindowLong的C宏”。

因此,这些来源似乎表明* Ptr入口点根本不存在于32位Windows 7附带的user32.dll版本中。

但我在MSDN文档中没有看到这一点。 根据MSDN, SetWindowLongPtr取代了SetWindowLong,简单明了。 根据SetWindowLongPtr页面的要求部分,看起来SetWindowLongPtr自Windows 2000(客户端和服务器版本)以来一直在user32.dll中。 同样,没有提到32位操作系统中缺少的入口点。

怀疑事实介于两者之间:当你告诉C ++编译器定位较旧的操作系统(即编译将在Win9x和NT4上运行的东西)时,头文件将SetWindowLongPtr声明为调用SetWindowLong的宏,但是入口点可能确实存在于Windows 2000及更高版本中,如果您告诉编译器定位这些平台,您将直接获取它(而不是宏)。 但这只是猜测; 我真的没有资源或技术可以深入挖掘并validation它。

目标平台也可能扮演一个角色 – 如果您为x86平台编译应用程序,那么就不应该在64位操作系统上调用SetWindowLongPtr。 再一次,我知道这个问题,但我不知道如何找到答案。 MSDN似乎暗示SetWindowLongPtr总是正确的。

有人能告诉我简单的P / Invoke到SetWindowLongPtr是否安全并完成它? (假设Windows 2000及更高版本。)P /调用SetWindowLongPtr会给我正确的入口点:

  • 如果我在32位操作系统上运行针对x86平台的应用程序?
  • 如果我在64位操作系统上运行针对x86平台的应用程序?
  • 如果我在64位操作系统上运行针对x64平台的应用程序?

我建议你按照Windows Forms内部的方式处理这个问题:

public static IntPtr GetWindowLong(HandleRef hWnd, int nIndex) { if (IntPtr.Size == 4) { return GetWindowLong32(hWnd, nIndex); } return GetWindowLongPtr64(hWnd, nIndex); } [DllImport("user32.dll", EntryPoint="GetWindowLong", CharSet=CharSet.Auto)] private static extern IntPtr GetWindowLong32(HandleRef hWnd, int nIndex); [DllImport("user32.dll", EntryPoint="GetWindowLongPtr", CharSet=CharSet.Auto)] private static extern IntPtr GetWindowLongPtr64(HandleRef hWnd, int nIndex); 
  1. 打开头文件(在MSDN页面上,这列为Winuser.h)。 Win32标头通常位于C:\Program Files\Microsoft SDKs\Windows\v7.0A\Include
  2. 搜索SetWindowLongPtr / GetWindowLongPtr所有实例。
  3. 注意,当定义_WIN64时,它们是函数; 如果不是,那么它们就是#defineSetWindowLong / GetWindowLong

这意味着32位操作系统可能没有SetWindowLongPtr / GetWindowLongPtr作为实际函数,因此看起来pinvoke.net上的注释是正确的。

更新(有关_WIN64的更多说明):

_WIN64由C / C ++编译器在编译64位代码时定义(仅在64位操作系统上运行)。 所以这意味着任何使用SetWindowLongPtr / GetWindowLongPtr 64位代码都将使用实际的函数,但使用它们的任何32位代码都将使用SetWindowLong / GetWindowLong 。 这包括在64位操作系统上运行的32位代码。

要在C#中模拟相同的行为,我建议检查IntPtr.SizeIntPtr.Size所做; 它告诉您是否正在运行32位或64位代码。 (请记住,32位代码可能在64位操作系统上运行)。 在托管代码中使用IntPtr.Size可以模拟与_WIN64对本机代码相同的行为。