如何解决“P/Invoke声明应该可移植”的问题?

3

这段代码:

[DllImport("shell32", CharSet=CharSet.Unicode)]
private static extern int SHGetFileInfo(string pszPath, uint dwFileAttributes, out SHFILEINFO psfi, uint cbFileInfo, uint flags);

导致以下代码分析问题:
CA1901 P/Invoke声明应该是可移植的
由于在您的代码中声明为P/Invoke的返回类型'IconUtil.SHGetFileInfo(string, uint, out IconUtil.SHFILEINFO, uint, uint)'将在64位平台上宽4个字节。这是不正确的,因为此API的实际本地声明表明在64位平台上应该宽8个字节。请参阅MSDN Platform SDK文档以获取帮助,确定应使用哪种数据类型代替'int'。
我应该怎么做?我尝试过"查阅MSDN",但我甚至不确定问题是什么意思。
我也在同一行收到以下内容:
CA1060 将P/Invoke移动到NativeMethods类
由于它是一个P/Invoke方法,'IconUtil.SHGetFileInfo(string, uint, out IconUtil.SHFILEINFO, uint, uint)'应该在名为NativeMethods、SafeNativeMethods或UnsafeNativeMethods的类中定义。

3
你将 SHGetFileInfo 声明为返回 intSHGetFileInfo 的返回值是 int 吗?根据 MSDN,它不是。在 x86 上,这足够接近。但在 x64 上,不是这样的。这就是第一条消息的意思。 - user743382
如果不确定,可以参考Pinvoke.Net——他们通常会有正确的签名——SHGetFileInfo。当然,如果他们的签名错误,也可以贡献自己的经验,但我认为在这种情况下他们是正确的。 - Damien_The_Unbeliever
CA1060非常清楚:您已将方法声明放置在名为IconUtil的类中,但应将其放置在名为NativeMethodsSafeNativeMethodsUnsafeNativeMethods的类中。请查看MSDN以找出应使用哪个类。 - dtb
2个回答

4

这个警告所指的MSDN页面是本地函数SHGetFileInfo的文档。它的签名为:

DWORD_PTR SHGetFileInfo(
  __in     LPCTSTR pszPath,
  DWORD dwFileAttributes,
  __inout  SHFILEINFO *psfi,
  UINT cbFileInfo,
  UINT uFlags
);

第一个警告是指 DWORD_PTR 是一个指针大小的无符号整数,这意味着你应该使用 UIntPtr

接下来需要注意的是,SHFILEINFO 结构体被标识为 __inout,这意味着你需要通过 ref 传递它。

因此,p/invoke 声明应该是:

[DllImport("shell32", CharSet=CharSet.Unicode)]
private static extern UIntPtr SHGetFileInfo(
    string pszPath, 
    uint dwFileAttributes, 
    ref SHFILEINFO psfi, 
    uint cbFileInfo, 
    uint flags
);

最后的警告很容易解决。只需将您的p/invoke声明放在名为NativeMethods的类内即可。

0

我通过将返回类型从 int 更改为 IntPtr 来解决了第一个问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接