AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Programmieren allgemein Delphi Icon anderer EXE Datei ändern
Thema durchsuchen
Ansicht
Themen-Optionen

Icon anderer EXE Datei ändern

Ein Thema von Satyr · begonnen am 14. Dez 2015 · letzter Beitrag vom 15. Dez 2015
Antwort Antwort
Satyr

Registriert seit: 8. Feb 2012
Ort: Essen
305 Beiträge
 
Delphi 10.4 Sydney
 
#1

AW: Icon anderer EXE Datei ändern

  Alt 14. Dez 2015, 20:40
Naja ich versuch Schnipsel zu verwenden die ich mit Google gefunden habe.
Im Ressourcen Editor hat die Exe ja definitiv beides. Icon und Icon Group. Und beides tauscht mein Code richtig aus, bis auf das eine Icon.

Ich habe jetzt mal einen anderen Ressource Editor verwendet. Der zeigt mir an das dieses Icon was Probleme macht ein Vista Icon ist und die anderen nicht. Kann es daran liegen? Ich verstehe nicht ganz was ich anders machen muss...
  Mit Zitat antworten Zitat
hoika

Registriert seit: 5. Jul 2006
Ort: Magdeburg
8.276 Beiträge
 
Delphi 10.4 Sydney
 
#2

AW: Icon anderer EXE Datei ändern

  Alt 14. Dez 2015, 21:25
Hallo,
kann es sein, dass das Icon intern mehrere Auflösungen enthält?


Heiko
Heiko
  Mit Zitat antworten Zitat
SMO

Registriert seit: 20. Jul 2005
178 Beiträge
 
Delphi XE6 Professional
 
#3

AW: Icon anderer EXE Datei ändern

  Alt 14. Dez 2015, 21:29
Probier's mal damit:

Delphi-Quellcode:
// Transplant / inject icon resources.
// Author: SMO, DelphiPraxis.net, 2015

uses
  System.Types; // TWordDynArray

const
  ICON_HEADER_RESERVED = 0;
  ICON_HEADER_TYPE_ICO = 1;
  ICON_HEADER_TYPE_CUR = 2;

type
  PGroupIconRsrcEntry = ^TGroupIconRsrcEntry;
  TGroupIconRsrcEntry = packed record
    bWidth, bHeight: Byte; // 0 means 256, which is the maximum
    bColorCount: Byte; // number of colors in image (0 if wBitCount > 8)
    bReserved: Byte; // 0
    wPlanes: Word; // 1
    wBitCount: Word; // number of bits per pixel
    dwSize: DWORD; // size of the icon data, in bytes
    wID: Word; // resource ID of the icon (for RT_ICON entry)
  end;

  PGroupIconRsrcHeader = ^TGroupIconRsrcHeader;
  TGroupIconRsrcHeader = packed record
    wReserved: Word; // 0
    wType: Word; // 1 for icons
    wCount: Word; // number of icons in this group, each has a following TGroupIconRsrcEntry
    // Entries: array [0..idType - 1] of TGroupIconRsrcEntry;
  end;


  TSmoGroupIcon = record
    Header: TGroupIconRsrcHeader;
    Entries: array of TGroupIconRsrcEntry;
    IconData: array of array of Byte;
  end;


function GetGroupIconFromIcoFile(const FileName: string; out GroupIcon: TSmoGroupIcon): Boolean;
var
  hFile: THandle;
  i, Size: Integer;
  Offsets: array of DWORD;
begin
  // clear the output record
  Finalize(GroupIcon);
  FillChar(GroupIcon.Header, SizeOf(GroupIcon.Header), 0);

  hFile := FileOpen(FileName, fmOpenRead or fmShareDenyNone);
  Result := hFile <> INVALID_HANDLE_VALUE;
  if Result then
  try
    // read header
    Size := SizeOf(GroupIcon.Header);
    Result := FileRead(hFile, GroupIcon.Header, Size) = Size;
    if not Result then Exit;
    with GroupIcon.Header do
      if (wReserved <> ICON_HEADER_RESERVED) or (wType <> ICON_HEADER_TYPE_ICO) then
      begin
        SetLastError(ERROR_BAD_FORMAT);
        Exit(False); // invalid data in header
      end;
    // read entries...
    // ico file entries are almost identical to TGroupIconRsrcEntry, with one small difference
    SetLength(GroupIcon.Entries, GroupIcon.Header.wCount);
    SetLength(Offsets, GroupIcon.Header.wCount);
    Size := SizeOf(GroupIcon.Entries[0]) - 2;
    for i := 0 to High(GroupIcon.Entries) do
    begin
      // read a TGroupIconRsrcEntry but without the last "wID" field
      Result := Result and (FileRead(hFile, GroupIcon.Entries[i], Size) = Size);
      // ico files have a dwFileOffset field there instead, read it separately
      Result := Result and (FileRead(hFile, Offsets[i], 4) = 4);
      GroupIcon.Entries[i].wID := i + 1;
    end;
    if not Result then Exit;
    // read icon image data
    SetLength(GroupIcon.IconData, GroupIcon.Header.wCount);
    for i := 0 to High(GroupIcon.IconData) do
    begin
      Size := GroupIcon.Entries[i].dwSize;
      SetLength(GroupIcon.IconData[i], Size);
      FileSeek(hFile, Offsets[i], FILE_BEGIN);
      Result := FileRead(hFile, GroupIcon.IconData[i, 0], Size) = Size;
      if not Result then Exit;
    end;
  finally
    FileClose(hFile);
    if not Result then
    begin
      // clear the output record
      Finalize(GroupIcon);
      FillChar(GroupIcon.Header, SizeOf(GroupIcon.Header), 0);
    end;
  end;
end;


// GetRsrcPointer: get pointer to the specified resource
// Returns nil on error
function GetRsrcPointer(hModule: HMODULE; lpName, lpType: PChar): Pointer;
var
  hResInfo: HRSRC;
  hResData: HGLOBAL;
begin
  Result := nil;
  hResInfo := FindResource(hModule, lpName, lpType);
  if hResInfo <> 0 then
  begin
    hResData := LoadResource(hModule, hResInfo);
    if hResData <> 0 then
      Result := LockResource(hResData);
    // UnlockResource & FreeResource are not necessary in 32 & 64 bit Windows
  end;
end;


// GetGroupIcon: get the complete data from the specified RT_GROUP_ICON resource.
// Returns true on success and false on error.
function GetGroupIcon(const FileName: string; GroupName: PChar; out GroupIcon: TSmoGroupIcon): Boolean;
var
  hLib: HMODULE;
  PData: Pointer;
  PEntry: PGroupIconRsrcEntry;
  LastError: DWORD;
  i: Integer;
begin
  // clear the output record
  Finalize(GroupIcon);
  FillChar(GroupIcon.Header, SizeOf(GroupIcon.Header), 0);

  hLib := LoadLibraryEx(PChar(FileName), 0, LOAD_LIBRARY_AS_DATAFILE);
  Result := hLib <> 0;
  if Result then
  try
    PData := GetRsrcPointer(hLib, PChar(GroupName), RT_GROUP_ICON);

    if not Assigned(PData) then Exit(False); // resource not found
    with PGroupIconRsrcHeader(PData)^ do
      if (wReserved <> ICON_HEADER_RESERVED) or (wType <> ICON_HEADER_TYPE_ICO) then
      begin
        SetLastError(ERROR_BAD_FORMAT);
        Exit(False); // invalid data in header
      end;
    // copy header
    GroupIcon.Header := PGroupIconRsrcHeader(PData)^;
    i := GroupIcon.Header.wCount;
    SetLength(GroupIcon.Entries, i);
    SetLength(GroupIcon.IconData, i);
    // copy entries & icon data
    PEntry := PGroupIconRsrcEntry(UIntPtr(PData) + SizeOf(TGroupIconRsrcHeader));
    for i := 0 to i - 1 do
    begin
      GroupIcon.Entries[i] := PEntry^;
      // load icon data (bitmap or PNG)
      PData := GetRsrcPointer(hLib, MakeIntResource(PEntry^.wID), RT_ICON);
      if Assigned(PData) then
      begin
        SetLength(GroupIcon.IconData[i], PEntry^.dwSize);
        Move(PData^, GroupIcon.IconData[i, 0], PEntry^.dwSize);
      end
      else // icon data wasn't found... wrong ID? Should not happen...
        GroupIcon.Entries[i].dwSize := 0;
      Inc(PEntry);
    end;
  finally
    LastError := GetLastError;
    FreeLibrary(hLib);
    if LastError <> ERROR_SUCCESS then SetLastError(LastError);
  end;
end;


function EnumResLangProc(hModule: HMODULE; lpszType, lpszName: PChar; wIDLanguage: Word;
  var LangArray: TWordDynArray): BOOL; stdcall;
var
  i: Integer;
begin
  i := Length(LangArray);
  SetLength(LangArray, i + 1);
  LangArray[i] := wIDLanguage;
  Result := True;
end;

function GetResourceLangIDs(hModule: HMODULE; lpType, lpName: PChar): TWordDynArray;
begin
  Result := nil;
  if not EnumResourceLanguages(hModule, lpType, lpName, @EnumResLangProc, IntPtr(@Result)) then
    Result := nil;
end;


// DeleteIconGroup: deletes the specified RT_GROUP_ICON resource and the referenecd RT_ICON
// resources. Deletes ALL language versions, if several exist.
// Returns true if the resource does not exist or was deleted successfully.
// Returns false if an error occured.
function DeleteGroupIcon(const FileName: string; GroupName: PChar): Boolean;
var
  GroupIcon: TSmoGroupIcon;
  hUpdate: THandle;
  hLib: HMODULE;
  LastError: DWORD;
  i, n: Integer;
  LangArray: TWordDynArray;
begin
  Result := GetGroupIcon(FileName, GroupName, GroupIcon);
  if not Result then
  begin
    case GetLastError of
      ERROR_RESOURCE_DATA_NOT_FOUND,
      ERROR_RESOURCE_TYPE_NOT_FOUND,
      ERROR_RESOURCE_NAME_NOT_FOUND,
      ERROR_RESOURCE_LANG_NOT_FOUND: Result := True;
    end;
    Exit;
  end;
  Assert(GroupIcon.Header.wCount = Length(GroupIcon.Entries));

  hLib := 0;
  hUpdate := 0;
  try
    hUpdate := BeginUpdateResource(PChar(FileName), False);
    if hUpdate <> 0 then
      hLib := LoadLibraryEx(PChar(FileName), 0, LOAD_LIBRARY_AS_DATAFILE);
    Result := (hUpdate <> 0) and (hLib <> 0);
    if not Result then Exit;

    // delete the RT_GROUP_ICON, all languages
    LangArray := GetResourceLangIDs(hLib, RT_GROUP_ICON, PChar(GroupName));
    for n := 0 to High(LangArray) do
      Result := Result and UpdateResource(hUpdate, RT_GROUP_ICON, PChar(GroupName),
        LangArray[n], nil, 0);
    // delete the actual icon data (RT_ICON), all languages
    // TODO: check if we're actually allowed to do that... other RT_GROUP_ICON could still
    // be referencing some of these RT_ICON we're about to delete!
    for i := 0 to High(GroupIcon.Entries) do
    begin
      if not Result then Break;
      LangArray := GetResourceLangIDs(hLib, RT_ICON, MakeIntResource(GroupIcon.Entries[i].wID));
      for n := 0 to High(LangArray) do
        Result := Result and UpdateResource(hUpdate, RT_ICON,
          MakeIntResource(GroupIcon.Entries[i].wID), LangArray[n], nil, 0);
    end;
  finally
    LastError := GetLastError;
    if hLib <> 0 then FreeLibrary(hLib);
    if hUpdate <> 0 then EndUpdateResource(hUpdate, not Result);
    if LastError <> ERROR_SUCCESS then SetLastError(LastError);
  end;
end;

// FindUnusedIconID: returns the first unused RT_ICON resource ID in the specified module.
// A return value of 0 means that no unused ID could be found.
function FindUnusedIconID(const hModule: HMODULE; const StartID: Word = 0): Word;
var
  hResInfo: HRSRC;
begin
  Result := StartID;
  if Result = 0 then Inc(Result);
  while Result > 0 do
  begin
    hResInfo := FindResource(hModule, MakeIntResource(Result), RT_ICON);
    if hResInfo = 0 then Break;
    Inc(Result);
  end;
end;


// SetGroupIcon: set the complete data of the specified RT_GROUP_ICON resource, and add the
// referenced RT_ICON resources. If a RT_GROUP_ICON of the same name exists, it'll be deleted
// first, including all RT_ICON resources it references.
// Returns true on success and false on error.
function SetGroupIcon(const FileName: string; GroupName: PChar; var GroupIcon: TSmoGroupIcon): Boolean;
var
  hLib: HMODULE;
  hUpdate: THandle;
  PData: Pointer;
  LastError: DWORD;
  i, SizeOfEntries: Integer;
  wLanguage, IconID: Word;
begin
  Assert(GroupIcon.Header.wCount = Length(GroupIcon.Entries));
  Assert(Length(GroupIcon.Entries) = Length(GroupIcon.IconData));
  // if the group already exists, then delete it first
  Result := DeleteGroupIcon(FileName, GroupName);
  hLib := 0;
  hUpdate := 0;
  PData := nil;
  if Result then
  try
    hUpdate := BeginUpdateResource(PChar(FileName), False);
    if hUpdate <> 0 then
      hLib := LoadLibraryEx(PChar(FileName), 0, LOAD_LIBRARY_AS_DATAFILE);
    Result := (hUpdate <> 0) and (hLib <> 0);
    if not Result then Exit;

    wLanguage := MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
    IconID := 0;
    // add the RT_ICON data
    for i := 0 to High(GroupIcon.Entries) do
    begin
      // find the next unused ID
      IconID := FindUnusedIconID(hLib, IconID + 1);
      Result := Result and (IconID > 0) and
        UpdateResource(hUpdate, RT_ICON, MakeIntResource(IconID), wLanguage,
        @GroupIcon.IconData[i, 0], Length(GroupIcon.IconData[i]));
      // update the entry's ID with the new value
      GroupIcon.Entries[i].wID := IconID;
    end;
    // add the RT_GROUP_ICON data
    if Result then
    begin
      // copy data from the GroupIcon structure to a contiguous block of memory
      i := SizeOf(GroupIcon.Header);
      SizeOfEntries := GroupIcon.Header.wCount * SizeOf(GroupIcon.Entries[0]);
      GetMem(PData, i + SizeOfEntries);
      PGroupIconRsrcHeader(PData)^ := GroupIcon.Header;
      Move(GroupIcon.Entries[0], Pointer(IntPtr(PData) + i)^, SizeOfEntries);
      Result := UpdateResource(hUpdate, RT_GROUP_ICON, PChar(GroupName), wLanguage,
        PData, i + SizeOfEntries);
    end;
  finally
    LastError := GetLastError;
    if Assigned(PData) then FreeMem(PData);
    if hLib <> 0 then FreeLibrary(hLib);
    if hUpdate <> 0 then EndUpdateResource(hUpdate, not Result);
    if LastError <> ERROR_SUCCESS then SetLastError(LastError);
  end;
end;
Benutzt wird das ganze dann so:

Delphi-Quellcode:
procedure Test;
var
  IconA, IconB, IconC: TSmoGroupIcon;
begin
  // Hole die Symbolgruppe "ICO_MYCOMPUTER" aus Explorer.exe
  if not GetGroupIcon('C:\Windows\System32\Explorer.exe', 'ICO_MYCOMPUTER', IconA) then
    RaiseLastOSError;
  // Hole die Symbolgruppe mit der ID 2 aus Notepad.exe
  if not GetGroupIcon('C:\Windows\System32\Notepad.exe', MakeIntResource(2), IconB) then
    RaiseLastOSError;
  // Lade eine Symbolgruppe aus einer Ico-Datei
  if not GetGroupIconFromIcoFile('D:\Test.ico', IconC) then
    RaiseLastOSError;
  // Speichere die Symbolgruppen in Test.exe unter verschiedenen Namen/IDs
  if not (SetGroupIcon('D:\Test.exe', 'MAINICON', IconA)
    and SetGroupIcon('D:\Test.exe', MakeIntResource(123), IconB)
    and SetGroupIcon('D:\Test.exe', 'A', IconC)) then
    RaiseLastOSError;
end;
Der Code ist nicht perfekt, er löscht eventuell Symbole, die noch von anderen Gruppen referenziert werden. Außerdem könnte man eine schöne Klasse daraus machen, oder einen Record mit Methoden, aber für den Anfang sollte es reichen.

Geändert von SMO (15. Dez 2015 um 19:37 Uhr)
  Mit Zitat antworten Zitat
Satyr

Registriert seit: 8. Feb 2012
Ort: Essen
305 Beiträge
 
Delphi 10.4 Sydney
 
#4

AW: Icon anderer EXE Datei ändern

  Alt 14. Dez 2015, 22:06
Ich verstehe das nicht. Wenn ich das dann umschreibe für meine Bedürfnisse, dann hab ich doch keine Symbolgruppe die ich eintragen will.

Und ist das als eigene Unit zu verstehen?

(Entschuldigt, ich bin der Typ Autodidakt der sich vielews bei Google zusammensucht und Zusammenhänge meist erst spät versteht...)
  Mit Zitat antworten Zitat
Satyr

Registriert seit: 8. Feb 2012
Ort: Essen
305 Beiträge
 
Delphi 10.4 Sydney
 
#5

AW: Icon anderer EXE Datei ändern

  Alt 14. Dez 2015, 22:26
Das Resultat ist leider das selbe. Alle Icons werden verändert bis auf dieses eine *sfz*.

Edit: Hier mal bein Screenshot. Oben das erste Icon macht die Probleme und ändert sich nicht.
Angehängte Grafiken
Dateityp: jpg Image 1.jpg (211,8 KB, 14x aufgerufen)

Geändert von Satyr (14. Dez 2015 um 22:33 Uhr)
  Mit Zitat antworten Zitat
SMO

Registriert seit: 20. Jul 2005
178 Beiträge
 
Delphi XE6 Professional
 
#6

AW: Icon anderer EXE Datei ändern

  Alt 14. Dez 2015, 22:38
Hallo,
kann es sein, dass das Icon intern mehrere Auflösungen enthält?
Symbole sind ein Zusammenspiel von zwei Ressourcentypen: RT_ICON und RT_GROUP_ICON.
Ein RT_GROUP_ICON ist mehr oder weniger nur eine Liste, die mehrere RT_ICON referenziert.
Ein RT_ICON hat nur eine feste Auflösung, es ist das RT_GROUP_ICON welches mehrere Auflösungen zu einer Einheit bündelt.


Ich verstehe das nicht. Wenn ich das dann umschreibe für meine Bedürfnisse, dann hab ich doch keine Symbolgruppe die ich eintragen will.

Und ist das als eigene Unit zu verstehen?

(Entschuldigt, ich bin der Typ Autodidakt der sich vielews bei Google zusammensucht und Zusammenhänge meist erst spät versteht...)
Kein Problem. Du musst den Code auch nicht unbedingt verstehen, um ihn zu benutzen (aber gut wäre es).

In deinem ursprünglichen Code möchtest du ein RT_ICON mit der ID 105 "transplantieren" und zum MAINICON machen. Das geht aber so nicht, weil MAINICON nicht vom Typ RT_ICON, sondern RT_GROUP_ICON ist. Ein RT_GROUP_ICON verwendet ein oder mehrere RT_ICON anhand ihrer ID. Du musst MAINICON auf jeden Fall anpassen, es sei denn es verwendet schon von Anfang an nur ein RT_ICON mit der ID 105, was sehr unwahrscheinlich ist.

Am einfachsten für dich wäre folgendes: Finde heraus, zu welchem RT_GROUP_ICON dein Quellicon mit der ID 105 gehört. Dann benutze den Namen bzw. die ID dieses RT_GROUP_ICON mit meinem Code (kannst du in eine eigene Unit machen oder auch nicht, deine Entscheidung). Fertig.

Das Resultat ist leider das selbe. Alle Icons werden verändert bis auf dieses eine *sfz*.

Edit: Hier mal bein Screenshot. Oben das erste Icon macht die Probleme und ändert sich nicht.
Ok, ich sehe das ist ein Problem mit den doofen Sprachcodes...
  Mit Zitat antworten Zitat
Satyr

Registriert seit: 8. Feb 2012
Ort: Essen
305 Beiträge
 
Delphi 10.4 Sydney
 
#7

AW: Icon anderer EXE Datei ändern

  Alt 14. Dez 2015, 22:50
ID 105 ist ja schon eine Icon Gruppe, wenn ich das richtig sehe. Die wurde bei meinem Code auch ersetzt. Aber im Ordner "Icon" das mit der ID 1 eben nicht. Auch nicht mit dem Code von Dir.
Angehängte Grafiken
Dateityp: jpg Image 2.jpg (108,5 KB, 8x aufgerufen)
  Mit Zitat antworten Zitat
SMO

Registriert seit: 20. Jul 2005
178 Beiträge
 
Delphi XE6 Professional
 
#8

AW: Icon anderer EXE Datei ändern

  Alt 14. Dez 2015, 23:10
ID 105 ist ja schon eine Icon Gruppe, wenn ich das richtig sehe. Die wurde bei meinem Code auch ersetzt. Aber im Ordner "Icon" das mit der ID 1 eben nicht. Auch nicht mit dem Code von Dir.
Stimmt. Ich habe den Code auf der letzten Seite angepasst, probier's damit nochmal.
Das Problem sind die Language IDs, bei dir eben "Englisch (Großbritannien)". Die musst du beim Aufruf von UpdateResource exakt angeben, sonst schlägt der fehl.
("Englisch (Großbritannien)" = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_UK))

Mein Code benutzt jetzt die Holzhammermethode und löscht die Icons in sämtlichen Sprachen, in denen sie vorhanden sind. Die neuen Icons werden dann als "sprachneutral" eingefügt.
  Mit Zitat antworten Zitat
Satyr

Registriert seit: 8. Feb 2012
Ort: Essen
305 Beiträge
 
Delphi 10.4 Sydney
 
#9

AW: Icon anderer EXE Datei ändern

  Alt 14. Dez 2015, 23:22
Ich dachte das würde einfach überschrieben.

Aber irgendwie stimmt es noch nicht. Jetzt wird einen neue Icongruppe erzeugt (mainicon) und bei den Einzelicons einige hzinzugefügt (Sprache Neutral) und die existierenden bleiben die alten Icons...
Angehängte Grafiken
Dateityp: jpg Image 4.jpg (172,2 KB, 8x aufgerufen)
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 02:18 Uhr.
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz