最低限DllImportの使い方を理解している方を対象にしています。この記事をコピペで利用した際の責任は一切負いません
あの、C# で Windowsのファイルアイコンやら色々な情報を獲得する SHGetFileInfo
の宣言を、DllImport
からLibraryImport
に書き換えて、憎きSYSLIB1054
を一つ撲滅する方法をお伝えします。
まず、C# での DllImport
のパターンは、よく見るのはこういう宣言ですね。
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct SHFILEINFO
{
public IntPtr hIcon;
public int iIcon;
public uint dwAttributes;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string szDisplayName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
public string szTypeName;
};
[DllImport("shell32.dll", CharSet = CharSet.Unicode)]
private static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttribs, ref SHFILEINFO psfi, uint cbFileInfo, SHGFI uFlags);
そして SHGETFILEINFO
の使い方はこんな感じですよね?
SHFILEINFO shinfo = new();
IntPtr shFileInfoResult;
// ここ
shFileInfoResult = SHGetFileInfo(path, 0, ref shinfo, (uint)Marshal.SizeOf(shinfo), SHGFI.SHGFI_ICON | SHGFI.SHGFI_SMALLICON | SHGFI.SHGFI_TYPENAME);
if (shFileInfoResult == IntPtr.Zero || shinfo.hIcon == IntPtr.Zero)
{
int lastError = Marshal.GetLastWin32Error();
throw new Exception($"SHGetFileInfo Failed with error code {lastError}");
}
BitmapSource icon = Imaging.CreateBitmapSourceFromHIcon(shinfo.hIcon, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
DestroyIcon(shinfo.hIcon);
// あとはiconとshinfo.szTypeNameでアイコンとファイル種類が手に入る
で、今となっては C# の DllImport
を使った SHGetFileInfo
に警告 SYSLIB1054
が出てくる、という状況です。
そしてVisual Studioの提案のままに、DllImport
からLibraryImport
に書き換えるとこうなります。
/*
// これが
[DllImport("shell32.dll", CharSet = CharSet.Unicode)]
private static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttribs, ref SHFILEINFO psfi, uint cbFileInfo, SHGFI uFlags);
*/
// ↓こう
[LibraryImport("shell32.dll", EntryPoint = "SHGetFileInfoW", StringMarshalling = StringMarshalling.Utf16)]
private static partial IntPtr SHGetFileInfo(string pszPath, uint dwFileAttribs, ref SHFILEINFO psfi, uint cbFileInfo, SHGFI uFlags);
そして、悲惨なことに第三引数psfi
でエラーになってしまうんです。
その psfi
のエラー回避方法となりますが、エラーになった SHFILEINFO
の書き換えが必要になります。できあがりがこちら。
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public unsafe struct SHFILEINFO
{
public IntPtr hIcon;
public int iIcon;
public uint dwAttributes;
public fixed ushort szDisplayName[260];
public fixed ushort szTypeName[80];
};
これで、エラー自体は抑制できますが、今度は別の場所が問題になります。szDisplayName
やszTypeName
がstring
型からushort
配列になったのですから当然の話ですね。
szDisplayName
やszTypeName
をstring
型に変換する必要があります。
ここではszTypeName
を対象にしますが、szDisplayName
も同様の処理となります。
string typeName = String.Empty;
unsafe
{
typeName = Utf16StringMarshaller.ConvertToManaged(shinfo.szTypeName) ?? String.Empty;
}
unsafe
で括ってUtf16StringMarshaller.ConvertToManaged
を使えばいいです。
以上。