【问题标题】:"P/Invoke entry points should exist" with what should be correct entry points stated“应该存在 P/Invoke 入口点”,并说明正确的入口点
【发布时间】:2012-10-20 07:12:33
【问题描述】:

我从 Visual Studio 2012 中的代码分析工具收到此警告。代码如下所示:

using System;
using System.Runtime.InteropServices;

namespace MyProgramNamespace
{
    class NativeMethods
    {
        [DllImport("user32.dll", EntryPoint = "GetWindowLongPtr")]
        public static extern IntPtr GetWindowLongPtr(IntPtr handle, int flag);

        [DllImport("user32.dll", EntryPoint = "SetWindowLongPtr")]
        public static extern IntPtr SetWindowLongPtr(IntPtr handle, int flag, IntPtr ownerHandle);
    }
}

我只为 x64 编译,所以我不关心使用旧的 GetWindowLong 和 SetWindowLong。据我所知,这些入口点名称是正确的。

编辑:已解决。 原来问题在于 Visual Studio 本身(以及代码分析工具)是 32 位的。当代码分析工具检查 user32.dll 以查看这些函数是否存在时,它会检查 user32.dll 的 32 位版本(在 C:/Windows/SysWOW64/ 中),而不是程序实际使用的那个(64 位版本)在C:/Windows/System32),并且这些函数只存在于64位版本(32位版本使用GetWindowLong/SetWindowLong而不是GetWindowLongPtr/SetWindowLongPtr(注意PTR部分))。

【问题讨论】:

  • 这是推测,但可能代码分析工具只检查 32 位版本的 user32.dll。 32 位版本的 user32.dll 中不存在 Get/SetWindowLongPtr。如果代码分析工具本身是 32 位的,这可能就是原因。
  • 另外,如果我注释掉底部的 2 行(对于 SetWindowLongPtr),所有警告都会消失。然而,由于这些行未注释,Get 和 Set 方法都会发出警告。如果我只注释掉前 2 行(Get),Set 仍然会发出警告
  • @Jargon 我会将解决方案作为答案发布并标记它,因为给出的答案都不正确(包括我的)。

标签: c# interop pinvoke analysis


【解决方案1】:

它们不起作用的原因是,通过在 DllImport 属性中指定 EntryPoint =,您是在告诉 Marshaller,“这正是我希望您调用的函数”。

user32.dll 中没有名为GetWindowLongPtr 的函数。有GetWindowLongPtrAGetWindowLongPtrW

当您省略 EntryPoint= 时,Marshaller 将根据正在运行的操作系统调用其中一个。

因此,要么将其省略,要么指定 A 或 W 版本。如果您指定 A 或 W,您还需要为 A 版本指定 CharSet=CharSet.Ansi 或为 W 版本指定 CharSet=CharSet.Unicode

【讨论】:

  • 尝试删除 EntryPoint,但没有修复,还尝试添加 CharSet(尝试 A 与 Ansi 和 W 与 Unicode),没有一个使警告消失
  • @行话警告?这个警告来自哪里?当然不是编译器。你在使用某种代码检查工具吗?
  • @Jargon 然后我用谷歌搜索了它(msdn.microsoft.com/en-us/library/ms182208.aspx)。它来自 FxCop。只需禁用警告并测试调用在运行时是否成功。
  • 是的,我在帖子的第一行中提到它是 Visual Studio 2012 中的代码分析工具(在旧版本中曾经是 FxCop)。我可以抑制警告,但我宁愿知道是什么导致它确保我正确地执行互操作。
  • 一定是这样。我从 System32 文件夹中复制了 user32.dll,警告消失了。如果我从 SysWOW64(32 位版本)复制 user32.dll,警告仍然存在。我想这就是我在 x86 IDE 中编写 x64 代码所得到的结果
【解决方案2】:

(此答案也发布在原始问题底部的编辑中,以帮助人们快速轻松地找到它)

原来问题在于 Visual Studio 本身(以及代码分析工具)是 32 位的。当代码分析工具检查 user32.dll 以查看这些函数是否存在时,它会检查 user32.dll 的 32 位版本(在 C:/Windows/SysWOW64/ 中),而不是程序实际使用的那个(64 位版本)在C:/Windows/System32),并且这些函数只存在于64位版本(32位版本使用GetWindowLong/SetWindowLong而不是GetWindowLongPtr/SetWindowLongPtr(注意PTR部分))。

【讨论】:

    【解决方案3】:

    尝试以下方法:

        [DllImport("user32.dll", EntryPoint = "GetWindowLongPtrW")]
        public static extern IntPtr GetWindowLongPtr(IntPtr handle, int flag);
    
        [DllImport("user32.dll", EntryPoint = "SetWindowLongPtrW")]
        public static extern IntPtr SetWindowLongPtr(IntPtr handle, int flag, IntPtr ownerHandle);
    

    【讨论】:

    • 用 W 和 A 都试过了(在某处看到)。两者都不起作用:S
    • 是的,ExactSpelling 似乎没有区别
    • 我的错,ExactSpelling如果指定了EntryPoint就没有必要了……我觉得这个warning是正常的,因为我编译x64程序集的时候会出现类似的警告(它会警告 Reference Assemblies)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-20
    • 2019-07-02
    • 1970-01-01
    • 2019-09-28
    相关资源
    最近更新 更多