Доступ к миниатюрам, которые не существуют

Я сделал приложение, которое представляет вам список файлов на вашем компьютере. Всякий раз, когда вы щелкаете по любому элементу в списке, рядом с ним в небольшом PictureBox должен отображаться эскиз соответствующего файла. Я использую C# на Windows 7.

Чтобы получить миниатюру, я обратился к методу, опубликованному в другом вопросе. Сначала я ссылаюсь на пакет Windows API Code. Затем я использую следующий код:

ShellFile shellFile = ShellFile.FromFilePath(fullPathToFile);
myPictureBox.Image = shellFile.Thumbnail.LargeBitmap;

Это не всегда работает. Иногда отображаемая миниатюра является просто значком приложения по умолчанию. Я обнаружил, что настоящий эскиз отображается только в том случае, если Windows ранее сгенерировала эскиз для этого файла и сохранила его в кэше миниатюр. Это означает, что мне нужно вручную открыть папку, подождать, пока Windows сгенерирует миниатюры для каждого файла, и тогда мое приложение сможет увидеть эти большие пальцы.

Как моя программа может заставить Windows 7 создавать реальные миниатюры перед их использованием?

Обновление (от Li0liQ)

Можно принудительно получить эскиз, добавив FormatOption:

ShellFile shellFile = ShellFile.FromFilePath(fullPathToFile);
shellFile.Thumbnail.FormatOption = ShellThumbnailFormatOption.ThumbnailOnly;
myPictureBox.Image = shellFile.Thumbnail.LargeBitmap;

Тем не менее, я получаю исключение в случае, если миниатюра еще не там:

Текущий ShellObject не имеет допустимого обработчика миниатюр или возникла проблема при извлечении миниатюры для этого конкретного объекта оболочки. ---> System.Runtime.InteropServices.COMException: класс не зарегистрирован (исключение из HRESULT: 0x80040154 (REGDB_E_CLASSNOTREG))

См. Как обновить эскиз файла в проводнике Windows? вопрос и фрагмент кода для потенциальных подсказок.

4 ответа

Вот фрагмент кода, который извлекает эскизы растровых изображений (только с использованием Windows Vista или выше). Он основан на классном интерфейсе IShellItemImageFactory:

    static void Main(string[] args)
    {
        // you can use any type of file supported by your windows installation.
        string path = @"c:\temp\whatever.pdf";
        using (Bitmap bmp = ExtractThumbnail(path, new Size(1024, 1024), SIIGBF.SIIGBF_RESIZETOFIT))
        {
            bmp.Save("whatever.png", ImageFormat.Png);
        }
    }

    public static Bitmap ExtractThumbnail(string filePath, Size size, SIIGBF flags)
    {
        if (filePath == null)
            throw new ArgumentNullException("filePath");

        // TODO: you might want to cache the factory for different types of files
        // as this simple call may trigger some heavy-load underground operations
        IShellItemImageFactory factory;
        int hr = SHCreateItemFromParsingName(filePath, IntPtr.Zero, typeof(IShellItemImageFactory).GUID, out factory);
        if (hr != 0)
            throw new Win32Exception(hr);

        IntPtr bmp;
        hr = factory.GetImage(size, flags, out bmp);
        if (hr != 0)
            throw new Win32Exception(hr);

        return Bitmap.FromHbitmap(bmp);
    }

    [Flags]
    public enum SIIGBF
    {
        SIIGBF_RESIZETOFIT = 0x00000000,
        SIIGBF_BIGGERSIZEOK = 0x00000001,
        SIIGBF_MEMORYONLY = 0x00000002,
        SIIGBF_ICONONLY = 0x00000004,
        SIIGBF_THUMBNAILONLY = 0x00000008,
        SIIGBF_INCACHEONLY = 0x00000010,
        SIIGBF_CROPTOSQUARE = 0x00000020,
        SIIGBF_WIDETHUMBNAILS = 0x00000040,
        SIIGBF_ICONBACKGROUND = 0x00000080,
        SIIGBF_SCALEUP = 0x00000100,
    }

    [DllImport("shell32.dll", CharSet = CharSet.Unicode)]
    private static extern int SHCreateItemFromParsingName(string path, IntPtr pbc, [MarshalAs(UnmanagedType.LPStruct)] Guid riid, out IShellItemImageFactory factory);

    [ComImport]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    [Guid("bcc18b79-ba16-442f-80c4-8a59c30c463b")]
    private interface IShellItemImageFactory
    {
        [PreserveSig]
        int GetImage(Size size, SIIGBF flags, out IntPtr phbm);
    }

Дополнительные примечания:

  • GetImage метод имеет различные интересные флаги (SIIGBFВы можете играть с.
  • По соображениям производительности вы можете кэшировать фабрики. Например, для файлов.PDF требуется загрузка всего Adobe Reader .exe в фоновом режиме.
  • При обращении к оболочке (Windows Explorer) вы хотите убедиться, что ваш процесс работает на том же уровне UAC, что и оболочка, иначе по соображениям безопасности некоторые операции завершатся неудачно. Так, например, если вы запускаете ваш процесс из F5 или CTRL+F5 в Visual Studio, а ваша Visual Studio запускается от имени администратора, ваш процесс может быть не в состоянии получить эскизы, хотя он будет работать при двойном щелчке по файлу.exe. от исследователя. REGDB_E_CLASSNOTREG Это типичная ошибка, которую вы можете получить в этих случаях.

Как моя программа может заставить Windows 7 создавать реальные миниатюры перед их использованием?

Из интерфейсов оболочки: интерфейс IThumbnailCache (выделено мое)

API Thumbnail Cache разработан для предоставления приложениям унифицированного метода для извлечения и кэширования миниатюр. В Windows XP кэширование миниатюр выполняется для каждой папки, а кэш хранится в файле Thumbs.db в каждой папке. Хотя этот подход обеспечивает пространственную локальность, он не поддерживает предварительный просмотр и запросы к папкам. Кэш миниатюр в Windows Vista устраняет этот недостаток, предоставляя глобальный кэш.

Чтобы кэшировать миниатюру, приложение должно сначала получить IShellItem, представляющий элемент, для которого будет получена миниатюра, а затем передать IShellItem вызову IThumbnailCache::GetThumbnail. Если параметр flags для IThumbnailCache:: GetThumbnail включает флаг WTS_EXTRACT, а миниатюра еще не кэширована, миниатюра будет извлечена и помещена в кэш. Если установлен флаг WTS_FORCEEXTRACTION, кеш игнорируется и всегда извлекается новый эскиз. См. Раздел IThumbnailCache:: GetThumbnail для получения дополнительной информации о флагах, передаваемых в IThumbnailCache::GetThumbnail.

Если миниатюра еще не находится в кэше, она будет автоматически извлечена из исходного файла с использованием существующих реализаций IExtractImage или IThumbnailProvider, которые зарегистрированы в операционной системе. Ваше приложение не должно предоставлять реализацию экстрактора миниатюр.

Итак, предположим, что в вашей системе есть реализация поставщика IThumbnail, который работает с PDF:

  1. Получить элемент оболочки для вашего PDF.
  2. Получить ссылку на кэш миниатюр оболочки. Давайте назовем это thumbNailCache,
  3. Вызов thumbNailCache.GetThumbnail(shellItem, thumbNailpx,wtxFlagSet, out thumbNailBitmap);, В документации сказано, что это создаст миниатюру для вас и вернет ее в выходной параметр thumbNailBitmap.

Предостережения: я не знаю, предоставляет ли ваш Code Pack полностью IThumbnailCache, но если это так, это выглядит довольно просто. Если этого не произойдет, вам придется импортировать его из shell32.dll.

Также есть интерфейс IThumbnailProvider, который может работать для вас, но читайте комментарии сообщества. Это кажется хрупким и хитрым в использовании.

После некоторых поисков я нашел эскизы Microsoft Office в Sharepoint. Это может работать только на офисных документах, но может быть тем, что вы хотите. Потребуется некоторый перевод, так как примеры на C++ и VB.Net.

Насколько я знаю, вы не можете заставить Windows 7 создавать эскизы. Однако вы можете создать его самостоятельно с помощью кода:

Image image = Image.FromFile(fileName);
Image thumbNail = image.GetThumbnailImage(120, 120, ()=>false, IntPtr.Zero);
thumbNail.Save(Path.ChangeExtension(fileName, "thumb"));

http://msdn.microsoft.com/en-us/library/system.drawing.image.getthumbnailimage.aspx

Другие вопросы по тегам