Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Delphi Icon anderer EXE Datei ändern (https://www.delphipraxis.net/187609-icon-anderer-exe-datei-aendern.html)

Satyr 14. Dez 2015 17:21

Icon anderer EXE Datei ändern
 
Huhu,

Delphi und ich, wir haben mal wieder keine gute Arbeitsbeziehung...

Ich möchte das Icon von einem anderen Programm ändern. Es läuft zu dem Zeitpunkt nicht und ist nicht anderweitig geblockt.
Teilweise funktioniert es. Es werden fast alle Icons im Ressource ersetzt. Bis auf eins. Ausgerechnet das Icon, welches im Explorer bzw. Desktop (dort liegt die EXE an der ich teste) wird nicht verändert. Und ich verstehe nicht wieso. Hier mein Code:

Delphi-Quellcode:
var hExe, hRes, hResLoad, hUpdateRes : THandle;
    lpResLock                        : Pointer;

  dlg: TOpenDialog;
  IconFile:string;
begin

  dlg := TOpenDialog.Create(self);
  with dlg do
  begin
    Title := 'Open Icon';
    Filter := DialogFilters[2];
    if Execute then
    begin
      IconFile := FileName;
    end;
    dlg.Free;
  end;


 hExe:=LoadLibrary(PWideChar(lzResDataFile));
 hRes:=FindResource(hExe,MAKEINTRESOURCE(#105),RT_ICON);
 hResLoad:=LoadResource(hExe, hRes);
 lpResLock:=LockResource(hResLoad);
 hUpdateRes := BeginUpdateResource(PWideChar(IconFile), FALSE);
 UpdateResource(hUpdateRes, RT_ICON, MAKEINTRESOURCE(105), LANG_NEUTRAL, lpResLock, SizeOfResource(hExe,hRes));
 UpdateResource(hUpdateRes, RT_GROUP_ICON, MAKEINTRESOURCE(2057), LANG_NEUTRAL, lpResLock, SizeOfResource(hExe,hRes));
 UpdateResource(hUpdateRes, RT_ICON, 'MAINICON', LANG_NEUTRAL, lpResLock, SizeOfResource(hExe,hRes));
 EndUpdateResource(hUpdateRes, False);
2057 ist die ID des Icons das nicht geändert wird. Ich habe es auf verschiedenem Weg versucht, deshalb mehrere UpdateResource Einträge. Wie gesagt, bei allen Icons klappt es außer dem einen...

Gruß,
Andreas

SMO 14. Dez 2015 17:38

AW: Icon anderer EXE Datei ändern
 
Zuerst mal solltest du nicht LoadLibrary benutzen, denn wenn "lzResDataFile" eine DLL ist, wird deren DllMain-Routine ausgeführt, was unbeabsichtigte Folgen haben könnte!

Wenn man nur an den Ressourcen einer EXE/DLL interessiert ist, und keinen Code davon aufrufen will, dann sollte man immer LoadLibraryEx benutzen, mit dem Flag LOAD_LIBRARY_AS_DATAFILE:
Delphi-Quellcode:
hLib := LoadLibraryEx(PChar(FileName), 0, LOAD_LIBRARY_AS_DATAFILE);
Außerdem solltest du PChar für diese String-Casts benutzen, nicht PWideChar, damit der Code sowohl in älteren (Ansi) als auch neueren (Unicode) Versionen von Delphi läuft.


Wie prüfst du, ob das Ersetzen des Symbols geklappt hat? Öffnest du die modifizierte Datei mit einem Ressourceneditor, oder schaust du einfach nur im Explorer/Desktop nach, ob das Symbol sich ändert? Falls letzteres: Windows hat einen Icon-Cache, es könnte also sein, dass das Symbol in der Datei geändert wurde, aber Windows durch den Cache immer noch das alte anzeigt.

Satyr 14. Dez 2015 17:45

AW: Icon anderer EXE Datei ändern
 
Naja für den Anwendungsfall weiß ich schon vorher das es keine DLL Dateien sein werden.
Aber wenn alles funktioniert ändere ich den Code ab, wie Du vorgeschlagen hast. Schon damit er sauberer ist.

Ich prüfe in einem Ressourceneditor. Bzw. erst habe ich schlicht im Explorer geguckt und wollte dann selbst sicher sein, ob es nicht am Cache liegt. Im Ressourceneditor wird mir aber angezeigt das alle Icons bis auf eins ersetzt werden. Ich verstehe einfach nicht warum dieses eine nicht.

Luckie 14. Dez 2015 17:57

AW: Icon anderer EXE Datei ändern
 
Du hast ja auch keinerlei Fehlerbehandlung im Code. Du wertest keinen einzigen Rückgabewert der Funbktionsaufrufe aus. Irgendeine Funktion wird fehlschlagen.

Satyr 14. Dez 2015 18:36

AW: Icon anderer EXE Datei ändern
 
Zugegebenermaßen kenne ich mich nicht gut aus, mit Fehlerbehandlung.

Ich habe es jetzt mal so versucht:

Delphi-Quellcode:
try
 hExe:=LoadLibrary(PWideChar(lzResDataFile));
 hRes:=FindResource(hExe,MAKEINTRESOURCE(#105),RT_ICON);
 hResLoad:=LoadResource(hExe, hRes);
 lpResLock:=LockResource(hResLoad);
 hUpdateRes := BeginUpdateResource(PWideChar(IconFile), FALSE);

 UpdateResource(hUpdateRes, RT_ICON, MAKEINTRESOURCE(105), LANG_NEUTRAL, lpResLock, SizeOfResource(hExe,hRes));
 UpdateResource(hUpdateRes, RT_GROUP_ICON, MAKEINTRESOURCE(2057), LANG_NEUTRAL, lpResLock, SizeOfResource(hExe,hRes));
 UpdateResource(hUpdateRes, RT_ICON, 'MAINICON', LANG_NEUTRAL, lpResLock, SizeOfResource(hExe,hRes));
 EndUpdateResource(hUpdateRes, False);

 except
    on e: Exception do
      ShowMessage(e.Message);
end ;
Eine Exception wird mir nicht angezeigt.

SMO 14. Dez 2015 19:30

AW: Icon anderer EXE Datei ändern
 
Zitat:

Zitat von Satyr (Beitrag 1324424)
Naja für den Anwendungsfall weiß ich schon vorher das es keine DLL Dateien sein werden.
Aber wenn alles funktioniert ändere ich den Code ab, wie Du vorgeschlagen hast. Schon damit er sauberer ist.

Gut. Sicher ist sicher. Irgendwann mal möchtest du vielleicht eine DLL benutzen, dann kannst du den Code auch wiederverwenden. ;)

Ich habe noch mal kurz recherchiert und es wundert mich nicht, dass dein Code nicht funktioniert. Er zeugt davon, dass dir der Unterschied zwischen RT_ICON und RT_GROUP_ICON nicht klar ist.

Unter RT_ICON werden die Rohdaten der Symbole abgespeichert, d.h. die Bitmaps (auch PNGs sind erlaubt seit Vista). Jedes Symbol erhält dabei eine numerische ID (ein 16-Bit-Word).
Unter RT_GROUP_ICON werden dann ein oder mehrere dieser Symbole zu einer Gesamtheit gruppiert (z.B. um dieselbe Grafik in verschiedenen Auflösungen parat zu haben).

'MAINICON' ist dabei die String-ID des Hauptsymbols wie es vom Explorer angezeigt wird. In deinem Code wendest du aber 'MAINICON' auf RT_ICON an, das ist falsch.

Also, RT_ICON = Bitmap / PNG, RT_GROUP_ICON = eine Datenstruktur des Typs "TGroupIconRsrcHeader", gefolgt von einem array of TGroupIconRsrcEntry:

Delphi-Quellcode:
type
  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;

  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;
Das ganze ist nicht so einfach, wie du es dir vorstellst.

Satyr 14. Dez 2015 19:40

AW: Icon anderer EXE Datei ändern
 
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...

hoika 14. Dez 2015 20:25

AW: Icon anderer EXE Datei ändern
 
Hallo,
kann es sein, dass das Icon intern mehrere Auflösungen enthält?


Heiko

SMO 14. Dez 2015 20:29

AW: Icon anderer EXE Datei ändern
 
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. ;)

Satyr 14. Dez 2015 21:06

AW: Icon anderer EXE Datei ändern
 
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...)

Satyr 14. Dez 2015 21:26

AW: Icon anderer EXE Datei ändern
 
Liste der Anhänge anzeigen (Anzahl: 1)
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.

SMO 14. Dez 2015 21:38

AW: Icon anderer EXE Datei ändern
 
Zitat:

Zitat von hoika (Beitrag 1324438)
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.


Zitat:

Zitat von Satyr (Beitrag 1324441)
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.

Zitat:

Zitat von Satyr (Beitrag 1324442)
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...

Satyr 14. Dez 2015 21:50

AW: Icon anderer EXE Datei ändern
 
Liste der Anhänge anzeigen (Anzahl: 1)
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.

SMO 14. Dez 2015 22:10

AW: Icon anderer EXE Datei ändern
 
Zitat:

Zitat von Satyr (Beitrag 1324446)
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.

Satyr 14. Dez 2015 22:22

AW: Icon anderer EXE Datei ändern
 
Liste der Anhänge anzeigen (Anzahl: 1)
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...

SMO 14. Dez 2015 22:37

AW: Icon anderer EXE Datei ändern
 
Du musst den Code schon richtig anwenden. ;)
Was genau möchtest du machen? Ich dachte, diese Datei mit der Symbolgruppe 105 wäre die Quelle, nicht das Ziel.

Delphi-Quellcode:
procedure Test;
var
  AGroupIcon: TSmoGroupIcon;
begin
  // Hole die Symbolgruppe #105 aus abc.exe
  if not GetGroupIcon('abc.exe', MakeIntResource(105), AGroupIcon) then
    RaiseLastOSError;
  // Speichere die Symbolgruppe in Test.exe unter dem Namen "MAINICON"
  if not SetGroupIcon('D:\Test.exe', 'MAINICON', AGroupIcon) then
    RaiseLastOSError;
end;

Satyr 14. Dez 2015 22:44

AW: Icon anderer EXE Datei ändern
 
Nene, die ist das Ziel. Bzw. ich weiß nicht ob sie es ist.

Ich möchte einfach nur bei einer bestimmten EXE das Icon das angezeigt wird ändern. Ich habe in einem Ressourcen Editor dann die Icons in der Gruppe 105 gefunden und 5 einzelne Icons. Und die dann versucht zu ersetzen. Aber das klappt irgendwie nicht so richtig...

Zacherl 14. Dez 2015 22:46

AW: Icon anderer EXE Datei ändern
 
Hatte auch mal was gebastelt, vielleicht hilft dir das ja weiter:
http://www.delphipraxis.net/170682-l...resourcen.html

Wenn die .exe schon ein Icon hat, musst du gegebenenfalls die primäre IconGroup vorher manuell löschen. Die APIs dazu wurden ja schon genannt (UpdateResource mit nil und 0 als Größe sollte den Eintrag entfernen).

Satyr 14. Dez 2015 22:56

AW: Icon anderer EXE Datei ändern
 
Zitat:

Zitat von Zacherl (Beitrag 1324451)
Hatte auch mal was gebastelt, vielleicht hilft dir das ja weiter:
http://www.delphipraxis.net/170682-l...resourcen.html

Danke, das sieht... kompliziert aus (für mich) *g*.

Ich werde mich morgen einlesen und hoffentlich rausfinden wie ich das benutzen kann. Wenns klappt, geb ich hier bescheid :).

SMO 14. Dez 2015 22:59

AW: Icon anderer EXE Datei ändern
 
Zitat:

Zitat von Satyr (Beitrag 1324450)
Nene, die ist das Ziel. Bzw. ich weiß nicht ob sie es ist.

Ich möchte einfach nur bei einer bestimmten EXE das Icon das angezeigt wird ändern. Ich habe in einem Ressourcen Editor dann die Icons in der Gruppe 105 gefunden und 5 einzelne Icons. Und die dann versucht zu ersetzen. Aber das klappt irgendwie nicht so richtig...

Ok, dann müsste Post #15 aber schon gestimmt haben.
MAINICON ist das Hauptsymbol. Falls das schon im Ziel existiert, wird es überschrieben. Falls nicht, hinzugefügt. Es macht doch nichts, dass da noch eine andere Symbolgruppe ist. Aber denke an den Icon-Cache, der kann dazu führen, dass du immer noch in Windows das alte Symbol siehst.


Zitat:

Zitat von Zacherl (Beitrag 1324451)
Hatte auch mal was gebastelt, vielleicht hilft dir das ja weiter:
http://www.delphipraxis.net/170682-l...resourcen.html

Wenn die .exe schon ein Icon hat, musst du gegebenenfalls die primäre IconGroup vorher manuell löschen. Die APIs dazu wurden ja schon genannt (UpdateResource mit nil und 0 als Größe sollte den Eintrag entfernen).

Danke für den Link, das schaue ich mir mal an. UpdateResource hat Satyr ja schon von Anfang an benutzt, das Problem waren eher die Language IDs. UpdateResource funktionier nämlich nur dann, wenn man die richtige Language ID angibt.

Satyr 14. Dez 2015 23:10

AW: Icon anderer EXE Datei ändern
 
Zitat:

Zitat von SMO (Beitrag 1324455)
Ok, dann müsste Post #15 aber schon gestimmt haben.
MAINICON ist das Hauptsymbol. Falls das schon im Ziel existiert, wird es überschrieben. Falls nicht, hinzugefügt. Es macht doch nichts, dass da noch eine andere Symbolgruppe ist. Aber denke an den Icon-Cache, der kann dazu führen, dass du immer noch in Windows das alte Symbol siehst.

Auch im RessourceEditor (Resource Tuner)? MAINICON war noch nicht da. Wird das automatisch als Anzeigesymbol genommen, statt der anderen Icons? Kann ich auch einfach alles was ist rauslöschen (so hab ich zumindest Zacherl verstanden), MAINICON Gruppe reinladen und fertig?

SMO 14. Dez 2015 23:54

AW: Icon anderer EXE Datei ändern
 
Zitat:

Zitat von Satyr (Beitrag 1324456)
Auch im RessourceEditor (Resource Tuner)? MAINICON war noch nicht da. Wird das automatisch als Anzeigesymbol genommen, statt der anderen Icons? Kann ich auch einfach alles was ist rauslöschen (so hab ich zumindest Zacherl verstanden), MAINICON Gruppe reinladen und fertig?

Ich hab's nochmal getestet: Das Hauptsymbol ist nicht unbedingt das, welches "MAINICON" heißt, sondern das mit der kleinsten ID. IDs können ja Namen (Strings) und Nummern sein. Namen "gewinnen" über die Nummern.

Soll heißen:
Hast du zwei Symbolgruppen, "MAINICON" und 105, dann gewinnt "MAINICON", weil es keine Nummer ist.
Hast du zwei Symbolgruppen, "MAINICON" und "BLA", dann gewinnt "BLA", weil es kleiner ist, d.h. alphabetisch sortiert zuerst kommt.
Hast du zwei Symbolgruppen, 105 und 13, dann gewinnt 13, weil es kleiner ist.
Hast du vier Symbolgruppen, 105, 13, "MAINICON" und "BLA", dann gewinnt "BLA".

Wenn du das neue Symbol als Hauptsymbol einrichten willst, dann nimm also einfach "A" als Name, der kommt alphabetisch immer als erstes! (Ressourcennamen übrigens bitte immer nur in Großbuchstaben.)

Alles klar?

Satyr 15. Dez 2015 00:04

AW: Icon anderer EXE Datei ändern
 
Verstehe. Dann such ich morgen bei Google wie ich vorhandene Icons alle lösche, eine neue Icongroup importiere und dann müsste das alles sein, wenn ich das richtig verstanden habe.

SMO 15. Dez 2015 00:10

AW: Icon anderer EXE Datei ändern
 
Wieso willst du alle vorhandenen Icons löschen? Das halte ich für keine gute Idee. Ein Programm könnte die Icons ja eventuell im Code benutzen. Wenn sie nicht mehr existieren, könnte es dann zu Fehlern kommen.

Wenn du sie wirklich löschen willst, dann kannst du mit EnumResourceNames die IDs aller RT_GROUP_ICON herausfinden und z.B. mit der DeleteGroupIcon-Funktion aus meinem Code löschen. Aber ich rate wie gesagt davon ab. Wenn du einfach nur das Symbol ändern willst, welches der Windows Explorer anzeigt, dann benutze SetGroupIcon mit 'A' als GroupName-Parameter.

Satyr 15. Dez 2015 00:27

AW: Icon anderer EXE Datei ändern
 
Ich dachte ich komme dann weniger in Konflikte, wenn ich nur meine Icons da habe, quasi.
Sag mal... kann ich Dir die exe mal schicken an der ich rumversuche? Ich wüsste nur gerne ob Du es schaffst das Icon zu ändern. Ich frage nicht nach dem Code. Ich habe das Gefühl das irgendetwas bei der exe anders ist, ich komme aber nicht drauf was. Ist nur ein Gefühl.

SMO 15. Dez 2015 00:46

AW: Icon anderer EXE Datei ändern
 
Klar, kannst du mir gerne schicken.
Aber du kannst auch einfach mal für dich selbst eine Kopie deiner Exe erstellen, der Kopie dann einen zufälligen Namen geben, um dem Icon-Cache zu entgehen und das aktuelle Symbol sofort zu sehen.

Satyr 15. Dez 2015 00:51

AW: Icon anderer EXE Datei ändern
 
Das habe ich schon versucht, leider ohne Erfolg...

Hab Dir den Dropbox Link per PM geschickt.

SMO 15. Dez 2015 01:04

AW: Icon anderer EXE Datei ändern
 
Funktioniert problemlos bei mir mit dem Code aus #9.

So bin ich vorgegangen (deine Exe nennen wir mal z.exe):

Delphi-Quellcode:
procedure ChangeIcon;
var
  IconA: TSmoGroupIcon;
begin
  // Hole die neue Symbolgruppe... hier als Beispiel #2 aus Notepad.exe
  if not GetGroupIcon('C:\Windows\System32\Notepad.exe', MakeIntResource(2), IconA) then RaiseLastOSError;
  // Speichere die Symbolgruppe in z.exe unter dem Namen "A"
  if not SetGroupIcon('D:\z.exe', 'A', IconA) then RaiseLastOSError;
end;
Im Explorer hatte D:\z.exe dann nach wie vor das alte Symbol - wegen des Icon-Caches.
Also habe ich z.exe im Explorer einfach schnell kopiert (Strg+C, Strg+V) und schon wurde bei der Kopie das Notepad-Symbol angezeigt, wie erwartet.

Satyr 15. Dez 2015 01:09

AW: Icon anderer EXE Datei ändern
 
Merkwürdig... dann scheint es irgendwie an meinem (VMWare) System zu liegen. Viell. ist da der Cache noch kurioser als eh schon.
Ich danke Dir für all die Hilfe und das geklärt ist, das es im Grunde funktionieren müsste.

Kann ich den Code eig. auch mit einer ico Datei benutzen oder nur mit exe Dateien?

SMO 15. Dez 2015 01:35

AW: Icon anderer EXE Datei ändern
 
Ich benutze übrigens Windows 8.1.

Im jetzigen Zustand kannst du den Code nur mit Exe/Dll benutzen. Aber eine Lade-Routine für Ico-Dateien ist überhaupt kein Problem, weil Ico-Dateien praktisch dasselbe Format haben: ein TGroupIconRsrcHeader, gefolgt von einem oder mehreren TGroupIconRsrcEntry (nicht ganz, kleine Änderung), gefolgt von den Rohdaten der Bitmaps/PNGs. Die Lade-Routine schreibe ich vielleicht morgen.

Satyr 15. Dez 2015 02:08

AW: Icon anderer EXE Datei ändern
 
Das wäre super!
Aber mach Dir keinen Stress, ich bin für alles dankbar :)

Ich wünsche noch einen angenehmen Abend. Mein Bett ruft so langsam. Vielen Dank nochmal!

SMO 15. Dez 2015 14:09

AW: Icon anderer EXE Datei ändern
 
Code auf erster Seite wurde aktualisiert, inklusive des Anwendungsbeispiels.

Satyr 15. Dez 2015 16:18

AW: Icon anderer EXE Datei ändern
 
Vielen Dank, das funktioniert perfekt.
In der VM von gestern hatte ich noch win7. Heute habe ich das in einer VM mit win10 getestet und der cache verwirrt mich nicht mehr. Alles wie es sein soll. Vielen Dank :)


Alle Zeitangaben in WEZ +1. Es ist jetzt 06:04 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz