Проводник Windows может отображать миниатюры всех гидратированных файлов в моей папке. Проблема в том, что мой код не всегда может получить одни и те же миниатюры.
Некоторые подробности:
Мое приложение написано на C#, поэтому я использую P/Invoke для взаимодействия с оболочкой и получения миниатюр. Вот пример кода, в котором для простоты удалена обработка ошибок:
Код: Выделить всё
[ComImportAttribute()]
[GuidAttribute("bcc18b79-ba16-442f-80c4-8a59c30c463b")]
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
public interface IShellItemImageFactory
{
HResult GetImage(
[In, MarshalAs(UnmanagedType.Struct)] SIZE size,
[In] SIIGBF flags,
[Out] out IntPtr phbm);
}
[DllImport("shell32.dll", CharSet = CharSet.Unicode, PreserveSig = false)]
[return: MarshalAs(UnmanagedType.Interface, IidParameterIndex = 2)]
public static extern IShellItemImageFactory SHCreateItemFromParsingName(
[In][MarshalAs(UnmanagedType.LPWStr)] string pszPath,
[In] IntPtr pbc,
[In][MarshalAs(UnmanagedType.LPStruct)] Guid riid);
[DllImport("gdi32.dll", EntryPoint = "DeleteObject")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool DeleteObject(
[In] IntPtr hObject);
[Flags]
public enum SIIGBF
{
SIIGBF_RESIZETOFIT = 00,
SIIGBF_BIGGERSIZEOK = 01,
SIIGBF_MEMORYONLY = 02,
SIIGBF_ICONONLY = 04,
SIIGBF_THUMBNAILONLY = 08,
SIIGBF_INCACHEONLY = 10
}
public Bitmap GetThumbnail(string parsingName)
{
// obtain the IShellItemImageFactory interface
IShellItemImageFactory isiif = null;
Guid iid = typeof(IShellItemImageFactory).GUID;
isiif = SHCreateItemFromParsingName(parsingName, IntPtr.Zero, iid);
if (isiif == null) return null;
// extract memory bitmap
SIIGBF flags = SIIGBF.SIIGBF_BIGGERSIZEOK | SIIGBF.SIIGBF_THUMBNAILONLY;
IntPtr hBitmap = IntPtr.Zero;
HResult result = isiif.GetImage(new SIZE(256, 256), flags, out hBitmap);
Marshal.FinalReleaseComObject(isiif);
if (hBitmap == IntPtr.Zero) return null;
Bitmap bmp = Image.FromHbitmap(hBitmap);
DeleteObject(hBitmap);
return bmp;
}
Внутри корня синхронизации CFAPI он не всегда работает. Я пока не смог найти закономерности, когда это работает, а когда нет. Я наблюдаю такое же непоследовательное поведение при попытке использовать разные типы файлов (расширения), поэтому кажется, что оно не ограничено конкретными типами. Когда это не работает, я получаю HRESULT от вызова GetImage 0x8004B207, который, очевидно, преобразуется в WTS_E_NOSTORAGEPROVIDERTHUMBNAILHANDLER. Я бы не ожидал получить эту ошибку (или любую другую ошибку), поскольку миниатюры файлов уже отображаются в Проводнике.
Еще одна вещь, которую я пробовал, — это обойти командную консоль и создать миниатюры самостоятельно. Это выглядит примерно так:
- Возьмите расширение файла, найдите его в HKEY_CLASSES_ROOT, найдите IThumbnailProvider CLSID
- Найдите реализацию IThumbnailProvider по CLSID
- Создать экземпляр IThumbnailProvider, передавая либо поток, либо файл в зависимости от того, что он поддерживает.
- Вызов GetThumbnail для результирующего экземпляра IThumbnailProvider
Итак, вкратце у меня есть следующие вопросы:
- Как мне программно получить миниатюру, которую Explorer уже показывает мне в графическом интерфейсе, чтобы я мог показать ее в своем собственном пользовательском интерфейсе?
- Безопасно ли создавать мои миниатюры? собственные миниатюры непосредственно с помощью IThumbnailProvider типа файла?
- Как заставить командную консоль кэшировать сгенерированные миниатюры, чтобы генерация происходила только один раз?