2

I'm using SHGetFileInfo to retrieve certain information about a file or directory, i.e. the icon or the description the file extension.

When retrieving the description of the file extension, the string returned from SHGetFileInfo is missing the first four characters.
For example, the description of a .pdf file is Adobe Acrobat Document but I only get e Acrobat Document or the description of a .exe file is Anwendung (as I'm German, in English it's Application i suppose), but I only get ndung.

I'm using

public static string GetFileTypeDescription(this FileInfo file)
{
    SHFILEINFO shFileInfo;
    if (SHGetFileInfo(
          file.Extension, 
          SHGFI_FILE_ATTRIBUTE_NORMAL, 
          out shFileInfo, 
          (uint)Marshal.SizeOf(typeof(SHFILEINFO)), 
          SHGFI_USEFILEATTRIBUTES | SHGFI_TYPENAME)
            != IntPtr.Zero)
    {
        return shFileInfo.szTypeName;
    }

    return null;
}

with the usual implementation of SHGetFileInfo:

[DllImport("shell32.dll")]
internal static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, out SHFILEINFO psfi, uint cbSizeFileInfo, uint uFlags);

[StructLayout(LayoutKind.Sequential)]
internal struct SHFILEINFO
{
    public IntPtr hIcon;
    public IntPtr iIcon;
    public uint dwAttributes;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
    public string szDisplayName;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
    public string szTypeName;
};

//I omitted all flags which are not used above
private const uint SHGFI_FILE_ATTRIBUTE_NORMAL = 0x80,
                   SHGFI_USEFILEATTRIBUTES = 0x10,
                   SHGFI_TYPENAME = 0x400;

What is wrong? Did I miss something? Or how can I retrieve the full description?

KeyNone
  • 8,745
  • 4
  • 34
  • 51

2 Answers2

2

The iIcon field in the C++ struct has type int. On Windows that is a 4 byte signed integer. It corresponds to int in C#.

You have declared the field as IntPtr in your C# code. That is a signed integer, the same size as a pointer. So it is 4 bytes in 32 bit code, and 8 bytes in 64 bit code. It seems likely that you are running 64 bit code.

So, the error is the declaration of this field which simply has the wrong type. The solution is to change the type of iIcon to int.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • Thanks for taking the time to explain! So my struct was 4 bytes too large... but what about `hIcon`? In the C++-typedef it is of type `HICON` which I couldn't find more information about and in C# it is also `IntPtr`. Tested it by compiling for x86 and x64, everything okay - but why? Wouldn't my struct effectively be 4 bytes short on x86? – KeyNone Nov 23 '13 at 12:54
  • HICON is pointer sized. So IntPtr is the correct translation. Starting from the code in the Q, you need to change iIcon to int and then your struct is correctly declared. – David Heffernan Nov 23 '13 at 13:18
  • Accepting your answer because it explains more what's going on. – KeyNone Nov 23 '13 at 13:33
0

Change IntPtr on the iIcon to int. That should work. Or use x86 as the platform target. Either of the two.

Sourav 'Abhi' Mitra
  • 2,390
  • 16
  • 15
  • Change IntPtr on the iIcon to int. That should work. Or use x86 as the platform target. Either of the two. – Sourav 'Abhi' Mitra Nov 22 '13 at 19:38
  • Changing `IntPtr` to `int` on `iIcon` fixed it - thanks! Can you explain why? (Also, edit your answer and delete the whole charset thing, as this won't be useful for other users) – KeyNone Nov 22 '13 at 19:55
  • Please have a look at the following msdn post: http://social.msdn.microsoft.com/Forums/en-US/60610aff-2dfd-4d52-9c4d-638d514100d0/calling-shgetfileinfo-in-c-win-x64. – Sourav 'Abhi' Mitra Nov 22 '13 at 20:21