Как правильно сохранить HICON из IMAGELIST в виде файла изображения - PullRequest
0 голосов
/ 05 января 2020

Моя цель:

Сохранение всех Window Icon Handle (HICON) из HIMAGELIST в виде нескольких файлов изображений (.png или *) 1011 *).


Моя проблема:

После моей процедуры сохранения некоторые изображения имеют низкое качество, а некоторые нет.

Я заметил эту проблему только на изображениях папок с подпапками / подпапками.

Saved HICON (.tiff)


Моя попытка:

Фон кода:

  • Я использую Vanara, чтобы помочь мне с вызовами PInvoke и многое другое .
  • * * * * * * * * * * * * * * * * * * * * * * * * *
  • * * * * * *1050* * * * * * * *1050* * * * * * * * *1050* * * * * * * * * *1050* * Этот метод является частью расширения Shell (я знаю, я не должен был делать что).
private void Saving()
{
    var hWnd = GetListViewHWnd(); // This is the Desktop SysListView32 HWND

    IntPtr lParam = IntPtr.Zero;
    IntPtr pHil = SendMessage(hWnd, ListViewMessage.LVM_GETIMAGELIST, 0, ref lParam);

    var sHil = new SafeHIMAGELIST(pHil); // This is the IMAGELIST of the ListView

    var imageCount = sHil.Interface.GetImageCount(); // sHil.Interface == IImageList Interface

    for (int i = 0; i < imageCount; i++)
    {
        using (var fs = File.OpenWrite(@"C:\Users\Julien\Desktop\Icons\" + i + ".tiff"))
        {
            using (SafeHICON sHIcon = sHil.Interface.GetIcon(i, IMAGELISTDRAWFLAGS.ILD_NORMAL))
            {
                var bmpS = Imaging.CreateBitmapSourceFromHIcon(
                        sHIcon.DangerousGetHandle(),
                        Int32Rect.Empty,
                        BitmapSizeOptions.FromEmptyOptions());

                BitmapEncoder enc = new TiffBitmapEncoder();
                enc.Frames.Add(BitmapFrame.Create(bmpS));
                enc.Save(fs);
            }
        }
    }

    sHil.Dispose();
}

Также:

var bmp = Bitmap.FromHicon(sHIcon.DangerousGetHandle());
bmp.Save(fs);

FAQ:

Почему я использую список изображений listview, а не SHGetFileInfo?

Поскольку SHGetFileInfo даст мне HICON вот так:

bad * 107 7 *

для папки, которая на самом деле выглядит следующим образом:

good

Как насчет передачи SHGFI_SYSICONINDEX в SHGetFileInfo ?

То же самое, значки непустых папок не хранятся в списке образов системы.

Поскольку я могу написать свое расширение на C ++, я открыт для любого написанного решения в C ++ тоже.

Редактировать: Я попытался нарисовать эти сбитые изображения, используя IImageList.Draw(), и это, кажется, работает. Ясно, что проблема возникает из-за того, как я создаю изображение из HICON.

enter image description here

var hdc = GetDC(notepadHWnd);
var dp = new IMAGELISTDRAWPARAMS(
    hdc,
    new RECT(73, 73, 73, 73), 12,
    COLORREF.None,
    IMAGELISTDRAWFLAGS.ILD_NORMAL);

sHil.Interface.Draw(dp);

1 Ответ

0 голосов
/ 07 января 2020

Поскольку я упрямый, я настаивал на IMAGELIST списка рабочего стола.

Мне удалось получить значки / эскизы из него. Рисуя их в контексте устройства в памяти.

Больше никаких сбитых изображений.

private void Saving()
{
    var hWnd = GetListViewHWnd(); // Desktop SysListView32 HWND

    IntPtr lParam = IntPtr.Zero;
    IntPtr pHil = SendMessage(hWnd, ListViewMessage.LVM_GETIMAGELIST, 0, ref lParam);

    var sHil = new SafeHIMAGELIST(pHil); // IMAGELIST of the ListView
    sHil.Interface.GetIconSize(out var cx, out var cy);

    var imageCount = sHil.Interface.GetImageCount(); // IImageList Interface
    var desktopHdc = new SafeHDC(GetDC(GetListViewHWnd()).DangerousGetHandle());
    var inMemoryHdc = CreateCompatibleDC(desktopHdc);

    for (int i = 0; i < imageCount; i++)
    {
        var inMemoryBmp = CreateCompatibleBitmap(desktopHdc, cx, cy);

        SelectObject(inMemoryHdc, inMemoryBmp);

        var ilDp = new IMAGELISTDRAWPARAMS(
            inMemoryHdc, 
            new RECT(0, 0, 0, 0), 
            i, 
            COLORREF.None,
            IMAGELISTDRAWFLAGS.ILD_NORMAL);

        sHil.Interface.Draw(ilDp);

        var bmpS = Imaging.CreateBitmapSourceFromHBitmap(
                inMemoryBmp.DangerousGetHandle(), 
                IntPtr.Zero,
                Int32Rect.Empty, 
                BitmapSizeOptions.FromEmptyOptions());

        using (var fs = File.OpenWrite(@"C:\Users\Julien\Desktop\Icons\" + i + ".png"))
        {
            BitmapEncoder enc = new PngBitmapEncoder();
            enc.Frames.Add(BitmapFrame.Create(bmpS));
            enc.Save(fs);
        }

        inMemoryBmp.Dispose();
    }

    sHil.Dispose();
    desktopHdc.Dispose();
    inMemoryHdc.Dispose();
}

Но, как сказал Джонатан Поттер, это не хорошая идея:

Например, комбинация IShellItemImageFactory и SHCreateItemFromIDList выглядит лучше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...