13

我想 P/Invoke 到GetWindowLongPtrSetWindowLongPtr,我看到关于它们的信息相互矛盾。

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

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

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

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

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

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

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

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

2 回答 2

18

我建议您以 Windows 窗体内部的方式处理此问题:

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);
于 2010-07-27T13:46:03.020 回答
4
  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/的 64 位代码GetWindowLongPtr都将使用实际函数,但任何使用它们的 32 位代码都将使用SetWindowLong/GetWindowLong代替。这包括在 64 位操作系统上运行的 32 位代码。

为了在 C# 中模拟相同的行为,我建议IntPtr.Size按照 pinvoke.net 进行检查;它会告诉您运行的是 32 位还是 64 位代码。(请记住,32 位代码可以在 64 位操作系统上运行)。在托管代码中使用IntPtr.Size模拟与本机代码相同的行为_WIN64

于 2010-07-27T13:01:18.447 回答