如何使用Win32 API或Windows API代码包在C#中检索显示为小号且在Windows 10上打开的C#通用文件夹图标?

问题描述 投票:1回答:1

[使用Win32 API检索C#中的文件/文件夹图标是一个琐碎的过程,已经记录了无数次,一直追溯到.Net的开头。

每个记录在案的解决方案只是相同方法的一种变体:P /调用SHGetFileInfo(),并传递适当的属性/标志。

我正在Windows 10上进行开发,我假设使用Shell32.dll v6.1-Windows 7附带的相同版本,并且根据Microsoft's documentation发布了最后一个版本。在我的开发系统上,对于C:\ Windows \ system32 \ shell32.dll,资源管理器中“属性”窗口的“详细信息”选项卡中显示的版本是“ 10.0.18362.719”。

我的目标是使用这种方法来生成“通用”文件夹图标。我需要它小(相对于大)并且处于打开(相对于关闭)状态。

我注意到,如果有人从SHGetFileInfo()请求一个小的通用文件夹图标,则结果始终显示为“关闭”状态。

相反,如果从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);
    }
}

使用Interop方法声明如下:

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);
}

是否需要某种黑魔法来获得通用的文件夹图标,该图标既小又开,或者又大又闭?

我还可以在项目中使用Windows API代码包,因此,如果可以仅使用此库就可以绕过Win32 API并达到我想要的结果,这将令人满意。

更新:根据Ian H的建议,我尝试使用SHGetStockIconInfo API,但不幸的是结果是相同的:

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);
}
c# .net winapi pinvoke windows-api-code-pack
1个回答
0
投票

系统打开图标的大小是32 * 32,您可以使用GetObject获得。

我的要求是带有“打开”外观的小(16x16)图标。

以下是在C ++中使用IShellItemImageFactory根据系统打开图标外观创建尺寸16 * 16 BITMAP的示例,您可以将其称为解决方法。

IShellItemImageFactory

小的打开图标将显示为:

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); }

© www.soinside.com 2019 - 2024. All rights reserved.