在C#中使用Win32应用程序接口检索文件/文件夹图标是一个微不足道的过程,这一过程已经被无数次地记录下来,一直追溯到.Net的开始。
每个有文档记录的解决方案都只是相同方法的变体:p/调用SHGetFileInfo(),传递适当的属性/标志。
我是在Windows10上开发的,我假设它使用的是Shell32.dll v6.1 --与Windows7附带的版本相同,最后一个版本是根据Microsoft's documentation发布的。在我的开发系统上,C:\Windows\system32\shell32.dll的资源管理器的Properties窗口的Details选项卡中显示的版本是"10.0.18362.719“。
我的目标是使用这种方法来生成一个“通用的”文件夹图标。我需要它是小(vs大)和在开放(vs关闭)状态。
我注意到,如果有人从SHGetFileInfo()请求一个小的通用文件夹图标,结果总是以"closed“状态出现。
相反,如果从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 Code Pack,所以如果可以绕过Win32 API,仅使用这个库就可以达到我想要的结果,这就足够了。
更新:在Ian H的建议下,我尝试使用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);
}
发布于 2020-04-17 17:50:04
系统打开图标大小为32*32,您可以使用GetObject
获取。
我的要求是一个带有“打开”外观的小图标(16x16)。
以下是在C++中使用IShellItemImageFactory
根据系统打开图标外观创建大小为16*16的位图的示例,您可以将其作为解决办法。
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);
}
打开的小图标将如下所示:
https://stackoverflow.com/questions/61162922
复制相似问题