Подтвердить что ты не робот

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

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

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

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? Вопрос и код фрагмент для потенциальных подсказок.

4b9b3361

Ответ 1

Вот фрагмент кода, который извлекает миниатюрные растровые изображения (только с использованием 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) вы хотите убедиться, что ваш процесс работает с тем же уровнем уровня UAC, что и в противном случае, по соображениям безопасности некоторые операции не удаются. Например, если вы запускаете свой процесс из F5 или CTRL + F5 в Visual Studio, а ваша Visual Studio запускается как администратор, ваш процесс может не получить эскизы, в то время как он будет работать при двойном щелчке по файлу .exe от исследователя. REGDB_E_CLASSNOTREG - типичная ошибка, которую вы можете получить в этих случаях.

Ответ 2

После некоторого поиска я нашел Thumbnails Microsoft Office в Sharepoint. Он может работать только на офисных документах, но может быть, что вы хотите. Будет требоваться некоторый перевод, поскольку примеры находятся в С++ и VB.Net.

Ответ 3

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

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

API кэширования эскизов предназначен для предоставления приложениям унифицированный метод для извлечения и кеширования эскизов. В 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:

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

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

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

Ответ 4

Насколько я знаю, вы не можете заставить 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