我只是想知道,如果在Windows中有一个API用于从字节数组(缓冲区)加载 HICON
?假设我下载了一个 *.ico
文件,我将该文件的内容放在某个缓冲区中 . 我希望能够从该缓冲区创建 HICON
.
可以从放置在硬盘驱动器上的 *.ico
加载 HICON
,所以我想从内存缓冲区应该有一个同样简单的方法吗?
到目前为止,我发现只有2种解决方案,但它们都不适合我 .
第一个involved ATL usage and GDI+(我'm using Rust and I don't与GDI有任何绑定) .
第二个是基于 LookupIconIdFromDirectoryEx()
和 CreateIconFromResourceEx()
的使用 . 首先,我调用 LookupIconIdFromDirectoryEx()
来获取正确图标的偏移量,然后我尝试调用 CreateIconFromResourceEx()
(和 CreateIconFromResource()
)来获取HICON,但是在所有情况下我都收到 NULL
值,但是 GetLastError()
返回 0
. 我对这些函数的使用是基于this article(我试图不仅传递 0
作为第二个参数,而且还传递数组缓冲区的大小,不包括偏移量,但它仍然失败) .
我想到的唯一剩下的解决方案是手动解析 *.ico
文件,然后从中提取PNG图像,然后使用here描述的方法从PNG图像创建一个图标 . 但它似乎更像是一种解决方法(Qt使用类似的方法,但也许他们无法找到不同的解决方案) . 是否有任何更简单的方法(可能是一些WinAPI调用)来完成工作?
UPD. 这是我尝试的一些测试代码(你应该有一个图标,以便运行没有崩溃的例子) .
#include <cstdio>
#include <cstdlib>
#include <Windows.h>
#pragma comment(lib, "User32.lib")
int main()
{
// Read the icon into the memory
FILE* f = fopen("icon.ico", "rb");
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
fseek(f, 0, SEEK_SET);
char* data = (char*)malloc(fsize + 1);
fread(data, fsize, 1, f);
fclose(f);
static const int icon_size = 32;
int offset = LookupIconIdFromDirectoryEx((PBYTE)data, TRUE, icon_size, icon_size, LR_DEFAULTCOLOR);
if (offset != 0) {
HICON hicon = CreateIconFromResourceEx((PBYTE)data + offset, 0, TRUE, 0x30000, icon_size, icon_size, LR_DEFAULTCOLOR);
if (hicon != NULL) {
printf("SUCCESS");
return 0;
}
}
printf("FAIL %d", GetLastError());
return 1;
}
2 回答
第二个参数不应为零 . Windows没有准备好在PNG文件的情况下,它在没有看到
BITMAPINFOHEADER
时停止只需提供最大可用缓冲区大小,即可解决PNG文件的问题:
文档说
LookupIconIdFromDirectoryEx
期望资源数据 . 此API似乎与图标文件一起使用,它返回第一个图标的偏移量 . 无论哪种方式,它似乎都没有基于文档所说的错误 .最好手动计算偏移量 . 您似乎已经知道如何计算偏移值 . 您可以根据ICONDIRENTRY简单地计算偏移量,如下所示
sizeof(ICONDIRENTRY)
是16.图标文件以3个WORD
值开头,第三个值是icon_count
,后跟sizeof(ICONDIRENTRY) * icon_count
个字节,后跟第一个HICON
的字节我找到了解决方案 . 实际上经过一些研究后发现,我放在样本中的代码确实是正确的 .
WinAPI函数
LookupIconIdFromDirectoryEx()
中存在错误 . 我注意到,对于某些图标,我可以获得正确的图标并进行设置,但对于其他图标,它会在后期CreateIconFromResourceEx()
或早期的LookupIconIdFromDirectoryEx()
上失败 . 我注意到,即使图标在文件中,有时功能也无法找到图标 . 有时,函数为图标文件中的不同图标返回相同的值 .我做了几轮测试,并根据format definition自己解析每个图标文件的格式 . 然后我将实际偏移量与
LookupIconIdFromDirectoryEx()
返回的值进行了比较 .假设我们有2个图标:
A
和B
.在我的案例中,
A
图标包含5个图像,ICO文件中的条目按以下顺序放置:256x256 PNG
128x128 BMP
64x64 BMP
32x32 BMP
16x16 BMP
B
图标包含7张图片,按以下顺序放置:16x16 BMP
32x32 BMP
48x48 BMP
64x64 BMP
128x128 BMP
256x256 BMP
每个图标的
LookupIconIdFromDirectoryEx()
的结果可以在下面找到 .图标
A
:86
9640
9640
9640
9640
图标
B
:102
1230
5494
15134
未找到(功能失败并返回
0
)未找到(功能失败并返回
0
)未找到(功能失败并返回
0
)我解析了实际的格式,根据definition in wikipedia(下面的表格包含图标条目,每行是一个单独的条目,每列都是此条目的字段)两个图标文件 .
A
的实际布局是:B
的实际布局是:所以你可以清楚地看到,在
A
的情况下,只有第一张图像的偏移被识别为正确,其他图像的偏移是不正确的并且等于...第三张图像的大小(??),可能只是巧合 .在第二张图像的情况下,所有偏移都是正确的,直到我们达到128x128图像,甚至没有找到 .
这两种情况之间的共同点是,在解析128x128图标后,函数开始表现得很奇怪,这是一个有趣的事情 - 查看128x128图标的大小,并将其与其他图像的大小进行比较 . 在这两种情况下,128x128图像的大小都不适合2个字节 . 解析大小超过2个字节的图标条目后,函数行为未定义 . 从这些数据来看,我可以假设在代码中的某个地方,他们期望图标的大小不能大于2个字节 . 如果大小更大,则行为未定义 .
我使用ImageMagick重新组装一个新的图标,里面没有这样的图像,现在该功能在所有情况下都正常工作 .
所以我可以肯定地说
LookupIconIdFromDirectoryEx()
实现中存在一个错误 .UPD . 图标可以在这里找到:A icon,B icon .