繁体   English   中英

我正在尝试对 Windows 可执行文件的图标进行资源更新,我快到了,我做错了什么?

[英]I'm trying to do a resource update on the icons of a Windows executable and I'm nearly there, what am I doing wrong?

这是我的代码的新版本。 现在更接近了,如果我查看 Resource Hacker 中的更新版本,它会告诉我该组有九个图标,这是真的,它们是 1680 万色,这是真的,它们都是 16 x 16 ,这不是真的,而且它实际上无法向我展示它们的外观,这很烦人。 此外,如果这对任何人都意味着什么,它们都有一个 150 的序号名称。

procedure TForm1.Button1Click(Sender: TObject);
var   vResHandle: THandle;
      MyIcon: TMemoryStream;
begin
  // Get the icon.
  MyIcon := TMemoryStream.Create;
  MyIcon.LoadFromFile('icon.ico');
  // Set the position in the memory stream to the start.
  MyIcon.Seek(0, soFromBeginning);

  // Get the handle.
  vResHandle := BeginUpdateResource('exec.exe', False);
  if vResHandle=0 then
    raise Exception.Create('System giving error message: '
                           + SysErrorMessage(GetLastError));
    try
    // Change the icon.
    if not UpdateResource(vResHandle
                          , RT_GROUP_ICON
                          , PChar('MAINICON')
                          , LANG_NEUTRAL
                          , MyIcon.Memory
                          , MyIcon.Size)
    then
      raise Exception.Create('System giving error message: '
                             + SysErrorMessage(GetLastError));
    finally
    EndUpdateResource(vResHandle, False);
    end;
  MyIcon.Free;
end;  

            

其工作原理的简短版本:所以。 在您尝试使用资源更新将任何数据放入 .exe 文件之前,您必须确保它适合。 图标文件很难。 在这种特殊情况下,我需要修改 .ico 文件的结构并将其拆分为不同的部分,并分别对每个部分进行资源更新。 我没有那样做。 我就像有人试图将七指手放入五指手套的一个手指中。

代码中解释了它的工作原理,但它对 Windows 的确切影响必须在此处进行解释。

(1) 虽然应用程序图标(在主窗体的左上角)可以设置为与程序的主图标完全不同,但一旦你这样做,它似乎被覆盖为与主图标一致更新。 99% 的情况下,这正是您想要的。 如果这不是你想要的,你必须从这里拿走。

(2) 文件资源管理器缓存这些内容非常困难,除非您重新启动资源管理器,否则您不会看到图标在此处的显示方式有任何变化。 这对我来说很好,如果这对你来说是个问题,那么你必须自己解决它,对不起。

(3) 这不是对常见问题“如何在基于 Pascal 的应用程序运行时更改其工具栏图标?”的回答。 因为您无法对正在执行的可执行文件进行资源更新,无论是您自己的还是其他人。

(4) 如果您要在 Pascal 中使用它,那么您需要将 Windows 添加到您的使用语句中。 如果你打算在 Pascal 以外的任何语言中使用它,但你仍在使用 Windows,那么它会很容易翻译,因为它基本上是在告诉 Windows 操作系统做一些事情,但你必须找出哪个图书馆或任何让你这样做的东西,以及它希望你使用什么语法。

(5) 如果您想知道如何反过来做并从可执行文件中提取 an.ico 文件,那么这在理论上当然是可能的,并且已经由比我更聪明的人完成了,并且确实在 Pascal 中完成了. (例如下载 Resource Hacker。)但是你不能仅仅通过反转我的代码来做到这一点,你的方式有障碍。 这样做 Windows 已经为我建立了这样做的设施。 以另一种方式做它似乎没有。

procedure TForm1.Button1Click(Sender: TObject);
var   vResHandle: THandle;
      MyIcon: TMemoryStream;
      i,j: integer;
      s: string;
      ImageCount: Word;
      ImageSize: DWord;
      ab, m: TMemoryStream;
 
const HeaderSize = 6;
      IcoEntrySize = 16;
      ResEntrySize = 14;
 
begin
 
// Short explanation. An icon file consists of (a) a six-byte header which
// includes among other things information about how many icons are in
// the file; (b) sixteen bytes of metadata for each icon; (c) the icons.
 
// But that's how icons are stored as files. As executable resources,
// Windows considers that (a) and (b) are one resource but (c) is a different
// resource, indeed one resource for each image, so we have to split the icon
// file up and do several resource updates.
 
// It also requires only fourteen bytes of metadata per entry: instead of the
// last parameter being a double word referring to the position of the image
// in memory, it's a single word conferring an ID.
 
// Initialize stuff
MyIcon := TMemoryStream.Create;
ab := TMemoryStream.Create;
m := TMemoryStream.Create;
 
// Get the icon
MyIcon.LoadFromFile('icon.ico');
 
// Get the handle for the resource update..
vResHandle := BeginUpdateResource('test.exe', False);
 
// We skip forward in the memory stream to where Windows keeps the image count and read it.
MyIcon.Seek(4,soFromBeginning);
ImageCount:=MyIcon.ReadWord;
 
// Go back to the beginning ...
MyIcon.Seek(0,soFromBeginning);
 
// We read the directory information into ab, modifying its format as we do so.
 
for j:=1 to HeaderSize do ab.WriteByte(MyIcon.ReadByte);
    for i:=1 to ImageCount do
        begin
        for j:=1 to IcoEntrySize - 4 do ab.WriteByte(MyIcon.ReadByte);
        MyIcon.ReadDWord;  // To skip over it.
        ab.WriteWord(i);
        end;
 
// Update the icon directory with ab, which is now in the correct format.
 
UpdateResource(vResHandle
                      , RT_GROUP_ICON
                      , PChar('MAINICON')
                      , LANG_NEUTRAL
                      , ab.Memory
                      , ab.Size);
 
// Now the size of each icon is contained as a double word in the directory
// entries for each item, so we use that to cut the remainder of the memory
// stream into chunks and update them one at a time.
 
for i := 1 to ImageCount do
    begin
    m := TMemoryStream.Create;
    ab.Seek(HeaderSize+(i-1)*ResEntrySize+8,soFromBeginning);
    ImageSize:=ab.ReadDWord;
    for j:=1 to ImageSize do m.WriteByte(MyIcon.ReadByte);
    UpdateResource(vResHandle
                  , RT_ICON
                  , MAKEINTRESOURCE(i)
                  , LANG_NEUTRAL
                  , m.Memory
                  , m.Size);
    m.Free;
    end;
 
EndUpDateResource(vResHandle,False);
MyIcon.Free;
ab.Free;
end;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM