Как я могу получить общий значок папки c в C#, который выглядит маленьким и открытым в Windows 10, используя либо Win32 API, либо Windows API Code Pack? - PullRequest
1 голос
/ 11 апреля 2020

Использование Win32 API для получения значков файлов / папок в C# - это тривиальный процесс, который был задокументирован бесчисленное количество раз, начиная с самого начала. Net.

Каждый документированный Решение - это всего лишь вариант того же подхода: P / Invoking SHGetFileInfo (), передавая соответствующие атрибуты / флаги.

Я занимаюсь Windows 10, который, я полагаю, использует Shell32.dll v6.1 - - та же версия, которая поставлялась с Windows 7, и последняя, ​​выпущенная в соответствии с документацией Microsoft . Версия, отображаемая на вкладке «Сведения» окна «Свойства» в проводнике моей системы разработки для C: \ Windows \ system32 \ shell32.dll, - «10.0.18362.719».

Моя цель - использовать этот подход сгенерировать иконку «generi c» FOLDER. Мне нужно, чтобы он был МАЛЫЙ (против большого) и находился в состоянии ОТКРЫТО (против закрытого).

Что я заметил, так это то, что если кто-то запрашивает небольшой общий значок папки c из SHGetFileInfo (), результат всегда появляется в закрытом состоянии.

И наоборот, если кто-то запрашивает большой общий значок папки c из SHGetFileInfo (), результат всегда появляется в открытом состоянии.

Следующий код представляет собой простейшую возможную демонстрацию этого. Для большого значка измените флаг SmallIcon на LargeIcon. Для закрытого значка удалите флаг OpenIcon.

public static Icon GetMyIcon()
{
    var flags = (uint)(ShellAttribute.Icon | ShellAttribute.SmallIcon | ShellAttribute.OpenIcon);

    var fileInfo = new ShellFileInfo();
    var size = (uint)Marshal.SizeOf(fileInfo);
    var result = Interop.SHGetFileInfo(string.Empty, (uint)FileAttribute.Directory, out fileInfo, size, flags);

    if (result == IntPtr.Zero)
        throw Marshal.GetExceptionForHR(Marshal.GetHRForLastWin32Error());

    try
    {
        return (Icon)Icon.FromHandle(fileInfo.hIcon).Clone();
    }
    finally
    {
        Interop.DestroyIcon(fileInfo.hIcon);
    }
}

С методами взаимодействия, объявленными следующим образом:

public static class Interop
{
    [DllImport("shell32.dll", CharSet = CharSet.Auto)]
    public static extern IntPtr SHGetFileInfo(string path,
        uint attributes,
        out ShellFileInfo fileInfo,
        uint size,
        uint flags);

    [DllImport("user32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool DestroyIcon(IntPtr pointer);
}

Существует ли какая-то черная магия c, необходимая для получения обобщенного c значок папки, который является либо маленьким и открытым, либо большим и закрытым?

Я также могу использовать Windows API Code Pack в моем проекте, поэтому, если есть возможность обойти Win32 API и достичь желаемого результата, используя только эту библиотеку, это удовлетворит.

ОБНОВЛЕНИЕ: По предложению Иана Х я попытался использовать API SHGetStockIconInfo, но результат, к сожалению, был таким же:

private static Icon GetStockIcon()
{
    SHSTOCKICONINFO sii = new SHSTOCKICONINFO();
    sii.cbSize = (UInt32)Marshal.SizeOf(typeof(SHSTOCKICONINFO));

    Marshal.ThrowExceptionForHR(SHGetStockIconInfo(SHSTOCKICONID.SIID_FOLDEROPEN,
            SHGSI.SHGSI_ICON | SHGSI.SHGSI_SMALLICON,
            ref sii));
    return Icon.FromHandle(sii.hIcon);
}

1 Ответ

0 голосов
/ 17 апреля 2020

Размер значка открытой системы составляет 32 * 32, который вы можете получить, используя GetObject.

. Моё требование - маленький (16x16) значок с «открытым» видом.

Ниже приведен пример на C ++, использующий IShellItemImageFactory для создания размера 16 * 16 BITMAP на основе внешнего вида значка открытой системы, который можно использовать как обходной путь.

        SHFILEINFOW sfi = { 0 };
        ICONINFO iconinfo;
        HBITMAP hBitmap;
        IShellItemImageFactory *pImageFactory;
        SIZE size = { 16, 16 };

        CoInitialize(NULL);

        hr = SHGetFileInfo(L"D:\\Test",
            -1,
            &sfi,
            sizeof(sfi),
            SHGFI_SYSICONINDEX | SHGFI_OPENICON | SHGFI_ICON);

        if (FAILED(hr))
        {
            OutputDebugString(L"SHGetFileInfo fails.\n");
        }

        GetIconInfo(sfi.hIcon, &iconinfo);
        hBitmap = iconinfo.hbmColor;

        BITMAP bmp;
        ZeroMemory(&bmp, sizeof(bmp));

        if (iconinfo.hbmColor)
        {
            // Get initial size is 32*32
            int nWrittenBytes = GetObject(iconinfo.hbmColor, sizeof(bmp), &bmp);

            hr = SHCreateItemFromParsingName(L"D:\\Test", NULL, IID_PPV_ARGS(&pImageFactory));
            if (SUCCEEDED(hr))
            {
                // Get expected size 16*16
                hr = pImageFactory->GetImage(size, SIIGBF_BIGGERSIZEOK, &hBitmap);
                if (FAILED(hr))
                {
                    OutputDebugString(L"IShellItemImageFactory::GetImage failed with error code %x");
                }
                pImageFactory->Release();
            }

            // Confirm if the size is 16*16
            nWrittenBytes = GetObject(hBitmap, sizeof(bmp), &bmp);
        }

Небольшой значок открытия будет выглядеть так:

enter image description here

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