给定一个文件类型(例如.txt
)我怎样才能得到:
文件类型的关联图标路径和索引,例如:
我想转换.txt
into:
-
Path: %SystemRoot%\system32\imageres.dll
-
Index: -102
有了这些信息,我就可以提取图标(例如使用SHDefExtractIcon
).
背景
Windows 中的每种类型的文件都在注册表中注册。当图标与文件关联时,它被指定为Path包含图标的文件以及图标资源的索引(如果索引为负,则作为资源 ID)。
Using .txt
以文件为例,关联的默认图标 is:
%SystemRoot%\system32\imageres.dll,-102
提取关联图标
首先是Win API函数提取关联图标 https://msdn.microsoft.com/en-us/library/windows/desktop/ms648067(v=vs.85).aspx:
检索文件中找到的索引图标或关联的可执行文件中找到的图标的句柄。
这个想法是,你将路径和索引传递给它,它就会为你获取图标:
String iconPath = "%SystemRoot%\system32\imageres.dll";
Word iIcon = -102;
HICON ico = ExtractAssociatedIcon(0, iconPath, iIcon);
只有当你已经know您想要的图标的路径和索引。
幸运的是,提取关联图标也能够tell图标文件的路径和索引:
如果该函数无法从该文件获取图标句柄,并且该文件具有关联的可执行文件,它将在该可执行文件中查找图标。
在这种情况下正确调用该函数有点棘手,因为它会修改您提供的缓冲区(如果您没有将缓冲区填充得足够长,则会导致缓冲区溢出):
String iconPath = "C:\Example.txt" + StringOfChar(\0, 32767); //pad the InOut buffer
Word iIcon = 0;
HICON ico = ExtractAssociatedIcon(0, iconPath, iIcon);
DestroyIcon(ico);
当函数返回时:
-
iconPath:
%SystemRoot%\system32\imageres.dll
-
iIcon: -102
为什么我不直接使用HICON
由 ExtractAssociatedIcon 返回?因为 ExtratAssociatedIcon 不允许我指定我想要的图标的大小。它返回“Shell 大图标”,仅此而已。
此外,ExtractAssociatedIcon 可以执行按文件类型查找的英勇努力的唯一方法是如果文件actually存在。如果指定的文件不存在(它不存在 - 因为没有foo.txt
),函数失败。
SHDef提取图标
Enter SHDef提取图标 https://msdn.microsoft.com/en-us/library/windows/desktop/bb762149(v=vs.85).aspx. It 能够提取我想要的任何大小的图标 https://blogs.msdn.microsoft.com/oldnewthing/20140501-00/?p=1103,你只需要把它传递给path and index图标资源:
String iconFile = "%SystemRoot%\system32\imageres.dll";
Int32 iIndex = -102;
HICON hLargeIcon;
if (SHDefExtractIcon(iconFile, iIndex, 0, out hLargeIcon, null, 256) == S_OK)
return hLargeIcon
唯一的问题是我必须获得关联的path and index已经有文件类型了。和SHDef提取图标,不像提取关联图标,不会为您执行英勇的查找。
为此,我必须自己执行查找;这是我的问题。
越野车注册表洞穴探险
我的第一次尝试是读取对方的文件关联契约 https://blogs.msdn.microsoft.com/oldnewthing/20031226-00/?p=41343。我知道默认图标是如何注册的,我可以反向操作。
-
转换.ext
至相关的ProgID
:
HKEY_CLASSES_ROOT/.ext
(default) = [ProgID]
-
查找DefaultIcon
在下面[ProgID]
HKEY_CLASSES_ROOT/[progID]/DefaultIcon
(default) = [path],[index]
就我而言:
HKEY_CLASSES_ROOT/.txt
(default) = txtfile
HEKY_CLASSES_ROOT/txtfile/DefaultIcon
(default) = "%SystemRoot%\system32\imageres.dll,-102"
这是后面代码使用的方法这接受了 https://stackoverflow.com/a/272044/12597Stackoverflow 对同一个问题的回答:
- 将 ext 转换为 progID
- 查找 progID 的 DefaultIcon 键
Assuming the ext exists, and the progID exists, and the DefaultIcon exists, and the path exists, and i can parse the path, it's an incorrect unsupported answer. There are edge cases that the accepted code does not handle1.
我想要 Windows API支持的执行映射的方法.ext
to
SH获取文件信息
有一个方便的功能SH获取文件信息 https://msdn.microsoft.com/en-us/library/windows/desktop/bb762179(v=vs.85).aspx。它很方便,因为文件名不需要actually exist https://blogs.msdn.microsoft.com/oldnewthing/20040601-00/?p=39073。如果你通过了SHGFI_USEFILEATTRIBUTES
标志,它的意思是:
不要访问磁盘。假设文件/目录存在,并且其文件属性是我作为 dwFileAttributes 参数传递的内容。无论它是否实际存在,都执行此操作。
这很好:
SHELLFILEINFO sfi;
DWORD res = SHGetFileInfo("foo.txt",
FILE_ATTRIBUTE_NORMAL,
ref shellFileInfo,
sizeof(shellFileInfo),
SHGFI_ICON | SHGFI_LARGEICON | SHGFI_SHELLICONSIZE | SHGFI_USEFILEATTRIBUTES);
if (res <> 0)
return shellFileInfo.hIcon;
唯一的问题是我无法指定我想要的图标大小。我受限于图标的大小shell决定it想要使用。
提取图像
提取图像 https://msdn.microsoft.com/en-us/library/windows/desktop/bb761848(v=vs.85).aspx很好:
- 它可以返回关联图标的[路径]、[索引]
- 我可以指定所需的尺寸
不幸的是,它需要一个实际存在的文件(它必须是exists在 shell 命名空间中)。当我只有一个文件类型时我无法使用提取图像
IT缩略图提供程序
IT缩略图提供程序 https://msdn.microsoft.com/en-us/library/windows/desktop/bb774614(v=vs.85).aspx随 Windows Vista 一起推出,是现代的替代品提取图像:
视窗VistaIThumbnailProivder 是 Vista 中的新增功能,它取代了 IExtractImage。 Vista仍然支持提取图像 https://msdn.microsoft.com/en-us/library/windows/desktop/bb761848(v=vs.85).aspx但缺乏返回图像类型(Alpha 或非 Alpha)的能力。
IThumbnailProvider 还允许我提供所需的图标大小。出色的!
IT缩略图提供程序通常要求 shell 命名空间中存在一个文件。但这只是因为 Shell API 是获取 ahold(“绑定”)的唯一受支持的方法。IT缩略图提供程序由文件类型公开的 shell 接口。
幸运的是,我可以执行与上面使用的相同的可怕黑客操作,并手动抓取注册表:
HKEY_CLASSES_ROOT/.ext/ShellEx/[InterfaceID]
(default) = [ClassID]
如果不存在:
HKEY_CLASSES_ROOT/.ext
(default) = [ProgID]
HKEY_CLASSES_ROOT/[ProgID]/ShellEx/[InterfaceID]
(default) = [ClassID]
就我的情况而言.avi
file:
HKEY_CLASSES_ROOT/.avi/ShellEx/{e357fccd-a995-4576-b01f-234630154e96}
(default) = "{9DBD2C50-62AD-11D0-B806-00C04FD706EC}"
现在我带着一个去参加比赛CLSID
!
不幸的是事情到此结束了,因为IT缩略图提供程序需要一个文件。更准确地说,它需要IInitializeWithStream
.
我没有流。我没有文件。我只有文件类型的概念。
关联查询字符串
Perhaps 关联查询字符串 https://msdn.microsoft.com/en-us/library/windows/desktop/bb773471(v=vs.85).aspx可以帮我?我实际上不知道——这是一个野兽般的函数。我对此一无所知。
问题
给定文件类型(例如“x.txt”),我如何获取关联的图标:
所以我可以提取我自己想要的大小的图标(可能使用 SHDefExtractIcon)?
脚注
1 exefile and %1