3
votes

This code:

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

Causes the following Code Analysis problem:

CA1901 P/Invoke declarations should be portable

As it is declared in your code, the return type of P/Invoke 'IconUtil.SHGetFileInfo(string, uint, out IconUtil.SHFILEINFO, uint, uint)' will be 4 bytes wide on 64-bit platforms. This is not correct, as the actual native declaration of this API indicates it should be 8 bytes wide on 64-bit platforms. Consult the MSDN Platform SDK documentation for help determining what data type should be used instead of 'int'.

What am I supposed to do? I tried "consulting MSDN", but I'm not really sure what the problem even means.


I also get this for the same line:

CA1060 Move P/Invokes to NativeMethods class

Because it is a P/Invoke method, 'IconUtil.SHGetFileInfo(string, uint, out IconUtil.SHFILEINFO, uint, uint)' should be defined in a class named NativeMethods, SafeNativeMethods, or UnsafeNativeMethods.

2
You declared SHGetFileInfo as returning int. Does SHGetFileInfo return int? According to MSDN, it does not. On x86, it's close enough. On x64, it isn't. That's what the first message is about. - user743382
When in doubt, check on Pinvoke.Net - they've usually got the signature right - SHGetFileInfo. Of course, if they do get the signature wrong, it's also good to contribute back, but I think they're correct in this case. - Damien_The_Unbeliever
CA1060 is pretty clear: you have placed the method declaration in a class named IconUtil, but it should be placed in a class named NativeMethods, SafeNativeMethods, or UnsafeNativeMethods. Check MSDN to find out which of the three you should use. - dtb

2 Answers

4
votes

The MSDN page that the warning refers to is the documentation of the native function SHGetFileInfo. It gives the signature as:

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

So the first warning is referring to the fact that DWORD_PTR is a pointer sized unsigned integer. That means you should use UIntPtr.

The next thing that jumps out is that the SHFILEINFO struct is indicated as __inout. That means you need to pass it by ref.

So the p/invoke declaration should be:

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

The final warning is simple to resolve. Simply place your p/invoke declaration inside a class named NativeMethods.

0
votes

I solved the first problem by changing return type of int to IntPtr.