【问题标题】:Does P/Invoke on 64-bit windows require different signatures than on 32-bit?64 位窗口上的 P/Invoke 需要与 32 位不同的签名吗?
【发布时间】:2012-11-16 08:17:57
【问题描述】:

例如,当我创建引用 user32.dll 的签名时,如果目标是 64 位计算机,我应该使用 user64.dll 构建它吗?

[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern bool ChangeClipboardChain(
    IntPtr hWndRemove,
    IntPtr hWndNewNext);

目前这不是问题,因为我只针对 32 位,因为供应商 (Progress OpenEdge) 提供的库仅提供 32 位库来访问他们的数据库。

我目前没有 64 位 windows 电脑,看看是不是这样。

【问题讨论】:

    标签: c# 64-bit pinvoke


    【解决方案1】:

    尽管有命名约定,但 user32.dll(和其他 32...dll)在 64 位机器上实际上是 64 位的。这些是 dll 的历史名称,无论底层架构发生什么变化,都一直保持这种名称。阅读this 页面以获取更多详细信息。

    【讨论】:

    • 天哪,我的天哪,该页面描述文件系统视图如何在 64/32 位应用程序之间变化的方式看起来相当可怕。非常感谢您的回答皮特。
    【解决方案2】:

    您应该不需要在调用 USER32.DLL 函数时需要更改链接到的 DLL 的签名/名称。

    尽管有命名约定,但在 64 位 Windows 机器上,位于 [Windows]\System32 中的 USER32.DLL 文件实际上是一个 64 位 DLL。 real 32 位版本的 USER32.DLL 实际上位于名为 [Windows]\SysWow64 的文件夹中。

    请参阅this question 了解更多信息。

    您可能需要最小心的一件事是您作为参数传递给各种 Windows API 函数的数据类型。例如,USER32.DLL 中的“SendMessage”函数有一个特定的要求,至少有一个参数(根据page on P/Invoke)。

    它的签名是:

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
    

    并且下面的注释 2 和 3 明确指出:

    2) 切勿使用“int”或“integer”作为 l 参数。您的代码将在 64 位上崩溃 视窗。只使用 IntPtr,一个“ref” 结构,或“out”结构。

    3) 切勿使用“bool”、“int”或 “整数”作为返回值。您的 核心将在 64 位 Windows 上崩溃。 仅使用 IntPtr。使用起来不安全 bool - pInvoke 不能编组 IntPtr 为布尔值。

    这个“警告”似乎是特定于这个特定函数 (SendMessage),尽管在调用 任何 Windows API 函数时我会特别注意这一点。

    【讨论】:

    • 感谢克雷格,太好了。我有一个问题,为什么System.Windows.Forms.Message.Msg 的类型是int。只问因为那将在Msg 中用于SendMsg,以前在我一直使用int 的同一个签名中。
    • @Brett - 这是个好问题,我不知道确切的答案,但是,这可能与 SendMessage 签名将 Msg 参数作为 UInt32 和 .NET 的事实有关Int 始终是 32 位(与底层 windows 平台无关),而 IntPtr 结构旨在反映底层 windows 平台(即它在 32 位 Windows 上是 32 位结构,但在 64 位 Windows 上是 64 位结构)。必须承认,这只是代表我的猜测。我很想知道自己的确切答案。
    • 是的,我想到了;然而,有趣的是,它是int 而不是uint,因为UInt32Int32 具有不同的上限/下限,但是,任何发送超出0-Int32.MaxValue 的东西都会出错反正。真的只是一个观察:)
    • @Brett @Craig 不同的是 uint 不是 CLR 类型,而 int 是。
    • 这是有用的信息。不过,它确实影响了对该方法的调用的类型转换。例如,以前是“SendMessage(parent.Handle, WM_SETREDRAW, false, 0);”现在是 'SendMessage(parent.Handle, WM_SETREDRAW, (IntPtr)0, (IntPtr)0);'等
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-12-17
    • 2013-08-19
    • 1970-01-01
    • 2015-05-30
    • 2013-05-19
    相关资源
    最近更新 更多