从缓冲区加载HICON(* .ico文件)

时间:2016-12-29 11:58:48

标签: winapi icons gdi

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

可以从放置在硬盘驱动器上的HICON加载*.ico,所以我想从内存缓冲区应该有一个同样简单的方法吗?

到目前为止,我发现只有2种解决方案,但它们都不适合我。

第一个involved ATL usage and GDI+(我正在使用Rust,我没有任何绑定到GDI +)。

第二个是基于LookupIconIdFromDirectoryEx()CreateIconFromResourceEx()的使用情况。首先,我调用LookupIconIdFromDirectoryEx()来获取正确图标的偏移量,然后我尝试调用CreateIconFromResourceEx()(和CreateIconFromResource())来获取HICON,但在所有情况下我都收到{{1}结果,NULL返回GetLastError()。我对这些函数的使用基于this article(我试图不仅传递0作为第二个参数,而且传递数组缓冲区的大小,不包括偏移量,但它仍然失败)。 / p>

我唯一想到的解决方案是手动解析0文件,然后从中提取PNG图像,然后使用here描述的方法从PNG图像创建图标。但它似乎更像是一种解决方法(Qt使用类似的方法,但也许他们无法找到不同的解决方案)。是否有任何更简单的方法(可能是一些WinAPI调用)来完成工作?

UPD。以下是我尝试的一些测试代码(您应该有一个图标以便运行示例而不会崩溃)。

*.ico

2 个答案:

答案 0 :(得分:1)

Intent share = new Intent("android.intent.action.SEND");
                share.setType("image/jpeg");
                share.putExtra("android.intent.extra.STREAM", Uri.parse(this.imgUrl));
                startActivity(Intent.createChooser(share, "via"));

第二个参数不应为零。 Windows不知道在不导致缓冲区溢出的情况下可以读取缓冲区的距离。显然Windows在某些情况下确实允许出现此错误,但对于PNG文件来说可能未准备好,当它没有看到CreateIconFromResourceEx((PBYTE)data + offset, 0, ...)

时便会停止

只需提供最大可用缓冲区大小,即可解决PNG文件的问题:

BITMAPINFOHEADER

文档说CreateIconFromResourceEx((PBYTE)data + offset, fsize - offset, ...) 需要资源数据。该API确实适用于图标文件,它返回第一个图标的偏移量。无论哪种方式,它似乎都没有基于文档所说的错误。

最好手动计算偏移量。看来您已经知道如何计算偏移值。您可以根据ICONDIRENTRY

如下简单地计算偏移量
LookupIconIdFromDirectoryEx

WORD icon_count = 0; fseek(f, 2 * sizeof(WORD), SEEK_SET); fread(&icon_count, sizeof(WORD), 1, f); int offset = 3 * sizeof(WORD) + sizeof(ICONDIRENTRY) * icon_count; 为16。图标文件以3个sizeof(ICONDIRENTRY)值开头,第三个值为WORD,后跟icon_count个字节,后跟第一个{ {1}}

答案 1 :(得分:-2)

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

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

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

假设我们有两个图标:AB

我案例中的A图标包含5张图片,ICO文件中的条目按以下顺序排列:

  1. 256x256 PNG
  2. 128x128 BMP
  3. 64x64 BMP
  4. 32x32 BMP
  5. 16x16 BMP
  6. B图标包含7张图片,按以下顺序排列:

    1. 16x16 BMP
    2. 32x32 BMP
    3. 48x48 BMP
    4. 64x64 BMP
    5. 128x128 BMP
    6. 256x256 BMP
    7. 每个图标的LookupIconIdFromDirectoryEx()结果可以在下面找到。

      图标A

      1. 86
      2. 9640
      3. 9640
      4. 9640
      5. 9640
      6. 图标B

        1. 102
        2. 1230
        3. 5494
        4. 15134
        5. 未找到(功能失败并返回0
        6. 未找到(功能失败并返回0
        7. 未找到(功能失败并返回0
        8. 我解析了实际格式,根据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()实施中存在一个错误。

          UPD。可以在此处找到图标:A iconB icon