2016-12-29 66 views
0

我只是想知道,如果在Windows中从字节数组(缓冲区)加载HICON的API?假设我下载了一个*.ico文件,并且我在某个缓冲区中包含了这个文件的内容。我希望能够从该缓冲区创建HICON从缓冲区(* .ico文件)加载HICON

可以从*.ico加载HICON放置在硬盘上,所以我想应该有一个同样简单的方法来从内存缓冲区中做到这一点?

到目前为止,我只找到2个解决方案,但没有一个适合我。

第一个involved ATL usage and GDI+(我正在使用Rust,我没有任何与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; 
} 
+0

看起来您的代码中存在一个错误。除非你提供[mcve],否则我们无法帮助你。 – IInspectable

+0

修复你的代码而不是放弃 –

+0

@IInspectable,我没有在最初添加它,因为它基本上与我链接的文章中的相同。但是现在我更新了描述并附上源代码。在我的情况下,它总是打印“失败0”。 – ScienceSE

回答

-2

我找到了解决方案。事实上,经过一番研究后发现,我在样本中放置的代码确实是正确的。

WinAPI函数LookupIconIdFromDirectoryEx()中存在一个错误。我注意到,对于某些图标,我可以得到正确的图标并进行设置,但对于其他图标,它可能会在后面的阶段CreateIconFromResourceEx()或更早的LookupIconIdFromDirectoryEx()上失败。我注意到,即使图标在文件中,有时该函数也无法找到该图标。有时函数为图标文件中的不同图标返回相同的值。

我做了几轮测试,并根据format definition分析了每个图标文件的格式。然后我将实际偏移与LookupIconIdFromDirectoryEx()返回的值进行比较。

比方说,我们有2个图标:AB

在我的情况下的A图标含有5个图像,ICO文件内的条目置于顺序如下:

  1. 256x256的PNG
  2. 128x128的BMP
  3. 64×64 BMP
  4. 32×32 BMP
  5. 16x16 BMP

B图标含有7倍的图像,它们被安置在下面的命令:

  1. 16×16 BMP
  2. 32×32 BMP
  3. 48x48的BMP
  4. 64×64 BMP
  5. 128x128的BMP
  6. 256x256的BMP

结果LookupIconIdFromDirectoryEx() fo每个图标都可以在下面找到。

图标A

图标B

  1. 未找到(函数失败并返回0
  2. 未找到(函数失败并返回0
  3. 未找到(函数失败和返回0

我根据definition in wikipedia(下面的表格包含图标条目,每行是一个单独的条目,每一列是这个条目的一个字段)解析实际格式,这两个图标文件都是。

A的实际布局是:

W  H  * * * **  SIZE  OFFSET 
------------------------------------------------ 
0  0  0 0 1 32  43253 86 
128 128 0 0 1 32  67624 43339 
48 48 0 0 1 32  9640  110963 
32 32 0 0 1 32  4264  120603 
16 16 0 0 1 32  1128  124867 

B的实际布局是:

W  H  * * * **  SIZE  OFFSET 
------------------------------------------------ 
16 16 0 0 0 32  1128  102 
32 32 0 0 0 32  4264  1230 
48 48 0 0 0 32  9640  5494 
64 64 0 0 0 32  16936 15134 
128 128 0 0 0 32  67624 32070 
0  0  0 0 0 32  270376 99694 

所以,你可以清楚地看到,在A情况下,只有第一个图像偏移是正确的,其他图像的偏移量不正确,等于第三张图像的大小(??),也许只是巧合。

在第二张图像的情况下,所有的偏移都是正确的,直到我们达到128x128的图像,甚至没有找到。

这两种情况之间的共同之处在于,函数在解析128x128图标后开始显得很奇怪,这里有一件有趣的事情 - 查看128x128图标的大小并将其与其他图像的大小进行比较。在这两种情况下,128x128图像的大小都不适合2个字节。在解析其中大小大于2个字节的图标条目之后,函数行为未定义。从这些数据来看,我可以假设代码中的某处他们期望图标的大小不能大于2个字节。如果尺寸较大,则行为未定义。

我用ImageMagick重新组装了一个新的图标,里面没有这样的图像,现在该功能在所有情况下都能正确工作。

所以我可以肯定地说LookupIconIdFromDirectoryEx()执行中有一个bug。

UPD。图标可以在这里找到:A icon,B icon

+0

非常不可能,Windows API在这里有一个bug。更可能是你误解了结果。带有PNG图像的图标与带有BMP图像的图标非常不同。 Raymond Chen有关于ICO文件格式的多部分系列。 [ICO文件格式的演变,第4部分:PNG图像](https://blogs.msdn.microsoft.com/oldnewthing/20101022-00/?p=12473)可能有助于理解您观察的结果。 – IInspectable

+0

@IInspectable,但结果表明,即使我使用仅包含BMP图像的图标,它也不能正常工作。在我的答案中查看图标文件'B',当我尝试搜索大于128x128像素的图标时,该功能失败。 – ScienceSE

+0

我最初问的是从ICO文件中加载'HICON'的方式,但似乎没有其他可靠的解决方案(至少我没有听到别人的答案,我也无法找到更好的解决方案我)。为我工作的唯一方法就是我描述的那个。然后我做了一个小研究,找出失败的原因。奇怪的是,我的答案收到了太多的反对票而没有解释他们的理由。 – ScienceSE