簡體   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