IExtractImage インターフェイスをインポートする次のコードがあります。
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("BB2E617C-0920-11d1-9A0B-00C04FC2D6C1")]
public interface IExtractImage
{
[PreserveSig]
Int32 GetLocation([MarshalAs(UnmanagedType.LPWStr)] out StringBuilder pszPathBuffer,
int cch,
ref int pdwPriority,
SIZE prgSize,
int dwRecClrDepth,
ref int pdwFlags);
[PreserveSig]
Int32 Extract(out IntPtr phBmpThumbnail);
}
IShellFolder もインポートしましたが、簡潔にするためにここでは言及しません。私の意図は、シェルフォルダーを使用してファイルのサムネイルにアクセスすることです。サムネイルを取得するコードは次のとおりです。しかし、IExtractImage.GetLocation() への呼び出しが NullReference 例外で失敗し、
「タイプ 'System.NullReferenceException' の例外が CCDash.exe で発生しましたが、ユーザー コードで処理されませんでした。
追加情報: オブジェクト参照がオブジェクトのインスタンスに設定されていません。」
誰かが私が見逃しているものを特定するのを手伝ってもらえますか?
public Bitmap GetThumbNail(string mediaFileName)
{
IShellFolder shellDesktop;
SHGetDesktopFolder(out shellDesktop);
IntPtr pidlRoot;
uint attribute = 0;
string mediaPath = "C:\\Users\\<user>\\Videos"; // I have hard-coded the path for now
uint pchEaten = 0;
// Get the pidl of the media folder
shellDesktop.ParseDisplayName(IntPtr.Zero, IntPtr.Zero, mediaPath, ref pchEaten, out pidlRoot, ref attribute);
Guid mediaFolderGuid = new Guid("000214E6-0000-0000-C000-000000000046");
shellDesktop.BindToObject(pidlRoot, IntPtr.Zero, mediaFolderGuid, out shellMediaFolder);
IntPtr pidlMediaFolder;
// Get the pidl of the media file
shellMediaFolder.ParseDisplayName(IntPtr.Zero, IntPtr.Zero, mediaFileName, ref pchEaten, out pidlMediaFolder, ref attribute);
Guid mediaFileImgGuid = new Guid("BB2E617C-0920-11d1-9A0B-00C04FC2D6C1");
uint rfgRes = 0;
IExtractImage extractImage;
shellMediaFolder.GetUIObjectOf(IntPtr.Zero, 1, out pidlMediaFolder, mediaFileImgGuid, ref rfgRes, out extractImage);
SIZE size = new SIZE
{
cx = 40,
cy = 40
};
int flags = 0x40 | 0x40;
StringBuilder location = new StringBuilder(260, 260);
int priority = 0;
int requestedColourDepth = 0x20;
IntPtr hBmp = IntPtr.Zero;
// Now get the image
extractImage.GetLocation(out location, location.Capacity, ref priority, size, requestedColourDepth, ref flags);
extractImage.Extract(out hBmp);
Bitmap thumbnail = Image.FromHbitmap(hBmp);
return thumbnail;
}
編集:
以下のようにコードを修正しました。最初のバージョンと大差ありませんが、エラー処理が少し増え、ドキュメントと変数名が改善され、コードをよりよく理解できるようになりました。変更されたコードは次のとおりです。
public Bitmap GetThumbNail(string mediaFileName)
{
Bitmap thumbnail = null;
//Step 1: Use SHGetDesktopFolder to get the desktop folder.
IShellFolder shellDesktop;
SHGetDesktopFolder(out shellDesktop);
if (shellDesktop != null)
{
IntPtr pidlMediaFolder;
try
{
uint attribute = 0;
string mediaPath = Path.GetDirectoryName(mediaFileName);
uint pchEaten = 0;
// Step 2: Using the desktop's IShellFolder, pass the file's parent folder path name into ParseDisplayName to get its PIDL.
shellDesktop.ParseDisplayName(IntPtr.Zero, IntPtr.Zero, mediaPath, ref pchEaten, out pidlMediaFolder, ref attribute);
}
catch (Exception)
{
Marshal.ReleaseComObject(shellDesktop);
return null;
}
if (pidlMediaFolder != IntPtr.Zero)
{
Guid mediaFolderGuid = new Guid("000214E6-0000-0000-C000-000000000046");
IShellFolder shellMediaFolder;
// Step 3: Using the desktop's IShellFolder, pass the PIDL into the BindToObject method
// and get the IShellFolder interface of the file's parent folder.
try
{
shellDesktop.BindToObject(pidlMediaFolder, IntPtr.Zero, mediaFolderGuid, out shellMediaFolder);
}
catch (Exception)
{
Marshal.ReleaseComObject(shellDesktop);
return null;
}
if (shellMediaFolder != null)
{
IntPtr pidlMediaFile;
uint attribute = 0;
uint pchEaten = 0;
// Step 4: Using the parent folder's IShellFolder, pass the file name into ParseDisplayName to get its PIDL.
int ret = shellMediaFolder.ParseDisplayName(IntPtr.Zero, IntPtr.Zero, mediaFileName, ref pchEaten, out pidlMediaFile, ref attribute);
Guid mediaFileImgGuid = new Guid("BB2E617C-0920-11d1-9A0B-00C04FC2D6C1");
uint rfgRes = 0;
IExtractImage extractImage;
// Step 5: Using the parent folder's IShellFolder, pass the file's PIDL
// into the GetUIObjectOf. method to get the IExtractImage interface.
ret = shellMediaFolder.GetUIObjectOf(IntPtr.Zero, 1, out pidlMediaFile, mediaFileImgGuid, ref rfgRes, out extractImage);
SIZE size = new SIZE
{
cx = 40,
cy = 40
};
uint flags = 0x0200;
StringBuilder location = new StringBuilder(260, 260);
int priority = 0;
int requestedColourDepth = 0x20;
IntPtr hBmp = IntPtr.Zero;
// Now get the image
extractImage.GetLocation(out location, location.Capacity, ref priority, size, requestedColourDepth, ref flags);
extractImage.Extract(out hBmp);
thumbnail = Image.FromHbitmap(hBmp);
}
}
}
return thumbnail;
}
ステップ 4 で、pidlMediaFile が正しく取得されず、その値が ParseDisplayName() 呼び出し後も 0 のままであることがわかります。ここから問題が始まります。ファイルの親フォルダーでは正常に取得されるのに、ファイル名の pidl が取得されない理由がわかりません。