在C++中更改exe图标

3

我一直在尝试通过编程的方式在Windows上更改exe文件的图标。我有一个.exe文件和一个.ico文件,我想让.exe文件的图标变成.ico文件。

我看到了这个帖子,但我不确定它是否适用于我的情况。那个用户知道以下信息:“exe在应用程序的.rc文件中使用的图标是IDR_MAINFRAME(ID 128)”。我不确定IDR_MAINFRAME具体是什么或者它是否对我的情况有用(此外,我甚至找不到需要哪个#include)。

我的当前代码如下:

HANDLE exe = BeginUpdateResourceW(exe_path, FALSE);

UpdateResourceW(exe, 
                RT_GROUP_ICON, 
                RT_GROUP_ICON,    // I think this might be the issue?
                MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), 
                icon,             // a .ico file, in memory, as raw binary data
                icon_size);

EndUpdateResource(exe, FALSE);

CloseHandle(exe);

我省略了错误处理代码,但我正在检查所有Windows API调用的返回值,并且它们都成功返回。我还注意到,所涉及的.exe以某种方式进行了更新:它获得了新的“修改日期”值,并且OneDrive(我在该目录中运行)将文件识别为已修改,因为它提示将其上传到云端。然而,即使在重新启动资源管理器后,甚至在明确删除图标缓存时,图标也不会更改。

我认为问题可能是UpdateResourceWlpName参数,但我不确定应该放置什么值。正如我上面所说,先前的帖子使用了MAKEINTRESOURCE(IDR_MAINFRAME),但我不确定这是否合适或如何获取IDR_MAINFRAME


你已经弄清楚了可执行文件中每个资源的ID吗?也许可以使用类似Resource Hacker这样的工具?如果你无法识别要更新的资源的ID,那么你可能无法取得太大进展,因此你需要使用资源查看器/编辑器或者如果是你自己的应用程序,则查看RC文件并确定ID是什么。 - PaulMcKenzie
是的,请使用MAKEINTRESOURCE()。但这并不是唯一的问题,当然如何得到错误的方法,资源管理器会缓存图标以加快其窗口更新。请搜索“重置shell图标缓存”以获取更多信息。 - Hans Passant
有用的资源:图标资源的格式,以及ICO文件格式的演变,第1部分:单色开端(和该系列的其他文章)。是的,在调用UpdateResourceW时需要将资源ID调整为应用程序所假定的值。 - IInspectable
@PaulMcKenzie 这是一个好建议,谢谢您提供那个程序的链接。 - alex
@IInspectable 感谢您提供的信息。您是否知道是否有Windows API调用可以实现我所希望的功能?即以正确的格式加载.ico文件以更新资源?此线程展示了如何加载.ico文件以在某种程度上更改图标(这是与我想要的不同类型的图标,因此我理解它并不相同,但它在概念上似乎相似)。如果没有通过API调用实现这一点的方法,我会感到惊讶... - alex
显示剩余7条评论
2个回答

1

你是正确的,问题出在 lpName 参数上。(可能还有其他问题,但这个问题肯定存在。)

对于 lpName(第三个参数),你需要传递 MAKEINTRESOURCE(128) 而不是 RT_GROUP_ICON

IDR_MAINFRAME 可能是可执行文件源代码中引用该图标的名称,所以它对你来说完全无关紧要。不过,你找到的文档说明它的值为 128,所以这就是你关心的全部内容。


似乎我表达不够清楚,但那只是一个例子 - 我想修改的不是可执行文件。我已经在答案中写出了似乎是解决方案(将此放在这里以供潜在的未来读者参考)。 - alex
@alex 好的,我很高兴你找到了解决方案。 - Mike Nakis

1

我认为我已经收集了足够的信息来回答这个问题。

主要有两个问题:

  1. 更新“错误”的资源
  2. 使用格式不正确的二进制数据来更新资源

关于第一个问题,似乎:

  • .exe文件使用它们能找到的第一个图标资源(RT_GROUP_ICON),这似乎是字典序最小的名称
  • 一些常见的主要图标“名称”是数字ID 1(MAKEINTRESOURCE(1))或字符串“MAINICON”,但通常没有硬性规定

在我的情况下,我试图更改一个没有图标(即具有默认图标)的可执行文件的图标,这实际上是添加资源,因此我可以选择任何我喜欢的ID或名称作为我的资源,并且它会起作用(因为它将是文件中唯一的图标资源)。

有关此主题的更多资源,请参见:

并非所有内容都是关于C++的,但它们似乎都使用相同的基础Windows API调用。

关于(2),主线程下的评论链表明,简单地将.ico数据转储为资源的方法行不通,因为图标资源的格式与.ico文件不同。@IInspectable在上面链接了一些很好的相关资源,在此我将重复列出:

第二个资源的后续文章(部分2、3、4)一般都非常有信息量。然后我想要完成的任务就变成了解析.ico文件并将其转换为图标资源格式的练习。


事实上,关于.ico和图标资源的权威资源可能是这个 - alex
我在寻找一个答案,想知道当资源管理器显示应用程序时选择哪个图标,所以这个链接很有帮助。我没想到Win9x要做这么多工作。这里还有几件事情要做:当替换现有图标时,你会想要删除(现在未使用的)RT_ICON资源。如果新图标中没有更多的图像,你可以重用这些ID并删除剩下的。如果新图标中有更多的图像,你将需要为它们找到空闲的RT_ICON资源ID。反复调用FindResource可能会起作用。 - IInspectable

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接