Autor Beitrag
Hoffensterchen
Hält's aus hier
Beiträge: 5

Win XP, Win 7
Delphi 2005
BeitragVerfasst: Mi 25.05.11 20:41 
Hallo liebe Leutz,

ich schreibe ein Programm, dass in bestimmten Situationen ein laufenden Fremdprogramm beendet, ein paar Operationen durchführt und danach das Fremdprogramm wieder startet.
Leider läßt sich das Fremdprogramm nicht "still" beenden, d.h. für ein "geordnetet" Beenden muß immer eine Sicherheitsfrage geklickt werden. Das Programm läuft unsichtbar, es zeigt sich nur durch mehrere Icons im Systray.

Mein Programm beendet das Fremdprogramm also "hart" per TerminateProcess(...), was auch problemlos funktioniert, da keine Daten gespeichert oder Dateien geschlossen werden müssen.

Allerdings gibt es ein kosmetisches Problem: Die Icons im Systray verschwinden erst, wenn man mit der Maus drüberfährt. Meine Frage also:

Wie kann ich den Systray "aufräumen", d.h. per Code alle "toten" Icons zu entfernen? Gibt es dafür sowas wie ein "Refresh" oder etwas in der Art?

Danke für Eure Hilfe!

Hoffensterchen

Edith sagt: Wasse nich im Koppe has'... Sorry, ich vergaß zu erwähnen, daß mein Programm unter Windows XP SP3 läuft... :oops:
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mi 25.05.11 21:03 
Hallo und :welcome:

Nein, dafür gibt es keine Möglichkeit. Du bist nicht der erste, der danach fragt. ;-)
Manche haben versucht den Mauszeiger per Programm herumzuschubsen und sowas, aber wirklich zuverlässig funktionieren tut das nicht.

Hast du denn schon versucht die Sicherheitsabfrage einfach durch dein Programm zu bestätigen? Das wäre doch wohl der sinnvollere und vor allem einfachere Weg...
Gerd Kayser
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 632
Erhaltene Danke: 121

Win 7 32-bit
Delphi 2006/XE
BeitragVerfasst: Mi 25.05.11 21:10 
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Hast du denn schon versucht die Sicherheitsabfrage einfach durch dein Programm zu bestätigen? Das wäre doch wohl der sinnvollere und vor allem einfachere Weg...
Ich würde eine WM_Quit-Message an das Programm schicken. Dann dürfte die Sicherheitsabfrage nicht erscheinen. Bei TerminateProcess könnten Reste im System verbleiben.
Hoffensterchen Threadstarter
Hält's aus hier
Beiträge: 5

Win XP, Win 7
Delphi 2005
BeitragVerfasst: Mi 25.05.11 21:14 
Danke erstmal!

Mpft... :x

jaenicke hat folgendes geschrieben:
Hast du denn schon versucht die Sicherheitsabfrage einfach durch dein Programm zu bestätigen? Das wäre doch wohl der sinnvollere und vor allem einfachere Weg...


Ist mein Plan B... :wink:

Gerd Kayser hat folgendes geschrieben:
Ich würde eine WM_Quit-Message an das Programm schicken.


Ömm... Wie geht das...? :oops:
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mi 25.05.11 21:20 
Stichworte:
FindWindow oder EnumWindows sowie SendMessage oder PostMessage.
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Mi 25.05.11 21:26 
Eventuell ist hier die Lösung dabei: www.delphipraxis.net...chwinden-lassen.html
Gerd Kayser
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 632
Erhaltene Danke: 121

Win 7 32-bit
Delphi 2006/XE
BeitragVerfasst: Do 26.05.11 01:32 
user profile iconHoffensterchen hat folgendes geschrieben Zum zitierten Posting springen:
Wie kann ich den Systray "aufräumen", d.h. per Code alle "toten" Icons zu entfernen? Gibt es dafür sowas wie ein "Refresh" oder etwas in der Art?

Was man in der TaskbarNotification-Area sieht, sind keine Icons oder Buttons. Der Bereich ist nichts anderes als ein Bildchen mit mehreren gemalten "Icons". Deshalb kann man die einzelnen "Icons" auch nicht mit Tastaturbefehlen ansteuern, sondern nur mit der Maus. Ob nun ein Eintrag noch gültig ist, wird von dem TNA-Prozess nur geprüft, wenn der Mauszeiger direkt auf einem der Bildchen steht.

Vorbemerkung zu meiner Lösung:
1. Getestet habe ich es nur unter Windows 7 32-Bit. Bei anderen Windows-Versionen sind die Parameter bei FindWindow(Ex) anzupassen.
2. Fehlerbehandlung habe ich keine eingebaut. Das überlasse ich Euch (vorgerückte Stunde und mit meiner Schäferhündin muß ich noch eine Runde Gassi gehen).
3. Ob man besondere Rechte benötigt, habe ich nicht geprüft.

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
procedure TForm1.Button1Click(Sender: TObject);
var
  Anzahl : integer;
begin
  Anzahl := TNA_Refresh;
  Label1.Caption := 'Gelöschte Icon-Leichen: ' + IntToStr(Anzahl);
end;

// uses CommCtrl;
function TForm1.TNA_Refresh: integer;
var
  wnd            : HWND;
  AnzahlIcons    : integer;
  Schleife       : integer;
  Koordinaten    : TPoint;
  AltKoordinaten : TPoint;
  pID            : cardinal;
  hProg          : THandle;
  Rect           : TRect;
  pAdr           : Pointer;
  Gelesen        : cardinal;
  AnzahlBytes    : integer;
begin
  // Result initialisieren. "- 1" = Fehler
  Result := - 1;

  // Fenster finden (Windows 7)
  wnd :=  FindWindow('Shell_TrayWnd'nil);
  wnd :=  FindWindowEx(wnd, 0'TrayNotifyWnd'nil);
  wnd :=  FindWindowEx(wnd, 0'SysPager'nil);
  wnd :=  FindWindowEx(wnd, 0'ToolbarWindow32'nil);

  if wnd <> 0 then
    begin
      // akt. Mauskoordinaten merken
      GetCursorPos(AltKoordinaten);

      // Anzahl der "Icons" ermitteln
      AnzahlIcons := SendMessage(wnd, TB_ButtonCount, 00);

      // Prozess ermitteln, der die TaskbarNotificationArea verwaltet, und öffnen.
      GetWindowThreadProcessID(wnd, @pID);

      hProg := OpenProcess(Process_VM_Operation
                             or Process_VM_Read
                             or Process_VM_Write,
                           false,
                           pID);

      // Speichergröße festlegen und im anderen Prozess den Speicher anfordern.
      AnzahlBytes := SizeOf(Rect);

      pAdr := VirtualAllocEx(hProg,
                         nil,
                         AnzahlBytes,
                         MEM_Reserve
                           or MEM_Commit,
                         Page_ReadWrite);

      for Schleife := AnzahlIcons - 1 downto 0 do
        begin
          // Position des "Icons" abfragen und aus dem anderen Prozess auslesen.
          SendMessage(wnd, TB_GetRect, Schleife, integer(pAdr));

          ReadProcessMemory(hProg,
                            pAdr,
                            @Rect,
                            AnzahlBytes,
                            Gelesen);

          // Die Koordinaten des Icons beziehen sich auf den Bereich der Taskbar-
          // NotificationArea und sind deshalb in Koordinaten für den Desktop-Screen
          // umzurechnen. Zur Sicherheit addiere ich hier jeweils 3 Pixel.
          Koordinaten.X := Rect.Left + 3;
          Koordinaten.Y := Rect.Top + 3;
          Windows.ClientToScreen(wnd, Koordinaten);
          SetCursorPos(Koordinaten.X, Koordinaten.Y);
        end;

      // aufräumen und Speicher freigeben
      VirtualFreeEx(hProg,
                    pAdr,
                    0,
                    MEM_Release);
      CloseHandle(hProg);

      // Maus wieder auf die alten Koordinaten setzen
      SetCursorPos(AltKoordinaten.X, AltKoordinaten.Y);

      // Anzahl gelöschter "Icons" ermitteln
      Result := AnzahlIcons - SendMessage(wnd, TB_ButtonCount, 00);
    end;
end;


Edit-1: Schleife in eine downto-Schleife geändert.


Zuletzt bearbeitet von Gerd Kayser am Do 26.05.11 12:24, insgesamt 1-mal bearbeitet
thepaine91
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 763
Erhaltene Danke: 27

Win XP, Windows 7, (Linux)
D6, D2010, C#, PHP, Java(Android), HTML/Js
BeitragVerfasst: Do 26.05.11 09:37 
Ich würde empfehlen mal dem Link von Luckie zu folgen dort sind ein paar gute Lösungsansätze die vor allem sauberer sind als die Maus hin und her zu schieben.
Gerd Kayser
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 632
Erhaltene Danke: 121

Win 7 32-bit
Delphi 2006/XE
BeitragVerfasst: Do 26.05.11 12:34 
user profile iconthepaine91 hat folgendes geschrieben Zum zitierten Posting springen:
dort sind ein paar gute Lösungsansätze die vor allem sauberer sind als die Maus hin und her zu schieben.

Wenn ich den Thread dort richtig gelesen habe, geht es dort um das Verstecken eines Icons und nicht um das Aktualisieren des TNA-Bereichs. Auch wenn man eine Leiche im Keller versteckt, so ändert das nichts daran, dass im Keller eine Leiche liegt. ;-)
Zur Mausschieberei: Ich habe die Ausführungszeit der Funktion mit GetTickCount gemessen. Sie beträgt 0 MSek. Der Cursor ist weder am Flackern noch sonstwas. Der Anwender bekommt davon überhaupt nichts mit.
Meine Lösung funktioniert jedenfalls unter Windows 7 32-Bit. Das müssen andere Lösungsansätze erst einmal zeigen. Wenn ich nachher mal etwas Zeit habe, werde ich es unter XP mal testen (nach dem Heraussuchen der FindWindow-Parameter).
thepaine91
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 763
Erhaltene Danke: 27

Win XP, Windows 7, (Linux)
D6, D2010, C#, PHP, Java(Android), HTML/Js
BeitragVerfasst: Do 26.05.11 13:27 
Ja aber auf Seite 4 ist eine Lösung zu finden die laut Author die Icons nicht nur versteckt sondern entfernt. Genauer hab ich es mir auch nicht angeguckt.

Nebenbei das Mauszeigerverschieben mag wunderbar funktionieren wenn aber ein Topmost Fenster drüber liegt trifft der Mauszeiger das Icon nicht also wird es auch nicht entfernt. Sobald das Fenster dann aber verschoben wird kommt es wieder zum Vorschein. Der Fall ist zwar selten aber dennoch kann es vorkommen.
Gerd Kayser
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 632
Erhaltene Danke: 121

Win 7 32-bit
Delphi 2006/XE
BeitragVerfasst: Do 26.05.11 16:30 
user profile iconthepaine91 hat folgendes geschrieben Zum zitierten Posting springen:
Ja aber auf Seite 4 ist eine Lösung zu finden die laut Author die Icons nicht nur versteckt sondern entfernt. Genauer hab ich es mir auch nicht angeguckt.

Meinst Du tna_181.zip? An die Datei komme ich leider nicht heran, weil ich dort im Forum keinen Account habe. Und überall Accounts anlegen möchte ich auch nicht gerade. Aber vielleicht kannst Du mir das per Mail schicken.
Zitat:
wenn aber ein Topmost Fenster drüber liegt trifft der Mauszeiger das Icon nicht also wird es auch nicht entfernt.

Werde ich nachher mal versuchen hier nachzustellen. Bislang ist es mir auf die Schnelle nur gelungen, Fenster hinter die Taskbar zu verschieben. Dabei ist mir allerdings aufgefallen, dass ich einen Fall übersehen habe. Nämlich: Wenn die Taskbar auf automatisches Ausblenden eingestellt ist. Aber das Problem lässt sich ja lösen.
thepaine91
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 763
Erhaltene Danke: 27

Win XP, Windows 7, (Linux)
D6, D2010, C#, PHP, Java(Android), HTML/Js
BeitragVerfasst: Do 26.05.11 16:36 
Jo hab einen Account in der DP, schicke es dir per PN.

Ich hab es getestet und es passiert das was ich beschrieben habe. Ist aber nach wie vor ein seltener Fall denke ich.
Gerd Kayser
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 632
Erhaltene Danke: 121

Win 7 32-bit
Delphi 2006/XE
BeitragVerfasst: So 29.05.11 13:51 
Heute habe ich mal ausgiebig das Programm aus tna_181.zip unter Windows 7 32-Bit getestet. Als Testobjekt habe ich TV-Guide (Fernsehprogramm von Sky) benutzt. Die Anwendung erzeugt zusätzlich einen Prozess (iSaverCtrl.exe) mit einem TNA-Icon. Bei meinen Tests ist mir Folgendes aufgefallen:
1. Das Programm löscht nur das TNA-Icon eines vorgegebenen, laufenden Prozesses und lässt eine Prozessleiche zurück (Icon wird gelöscht, Prozess aber nicht beendet).
2. Ein verwaistes Icon (Prozess gekillt) wird nicht gelöscht.
3. Das Programm enthält eine Stolperfalle.
ausblenden Delphi-Quelltext
1:
ProcPath:= 'C:\Programme\iSaver\iSaverCtrl.exe';					

Das nachfolgende FileExists funktioniert zwar, aber
ausblenden Delphi-Quelltext
1:
if SameText(ProcPath, GetProcPath(IconData.Wnd)) then					

wird immer fehlschlagen, weil GetProcPath "C:\Program Files\..." zurückliefert.
Fazit: In der vorliegenden Form ist das Programm völlig ungeeignet, weil es die Icons im TNA-Bereich nicht aufräumt (siehe Punkt 2). Und das Löschen eines Icons, ohne den dazugehörigen Prozess zu beenden, ist eigentlich sinnlos (siehe Punkt 1).
Aber das Programm hat mich auf eine Idee gebracht, wie man das Refreshen realisieren könnte (auch unter XP und Vista). Dazu brauche ich aber einige Tage Zeit. Auch als Ruheständler ist man nicht immer Herr seiner Zeit.
Gerd Kayser
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 632
Erhaltene Danke: 121

Win 7 32-bit
Delphi 2006/XE
BeitragVerfasst: Do 02.06.11 14:13 
Hier ist die Lösung. Hat zwar einige Stunden gedauert, weil ich mal wieder zu kompliziert gedacht hatte. Dabei ist die Lösung eigentlich recht simpel. ;-)

Die Lösung funktioniert auch bei einer Taskleiste, die ausgeblendet ist. Ich habe zwar das Programm nur unter Windows 7 32-Bit getestet, aber es sollte ab Windows XP funktionieren. Ob das Programm unter 64-Bit funktioniert, kann ich hier leider nicht testen.

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
unit Main;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, CommCtrl, ShellAPI;

type
  TMainform = class(TForm)
    Refresh: TButton;
    Label1: TLabel;
    procedure RefreshClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
    function TNA_Refresh : integer;
    function SuchenTNAWindow : HWnd;
  end;

var
  Mainform: TMainform;

implementation

{$R *.dfm}

function TMainform.TNA_Refresh : integer;
var
  Wnd          : HWnd;            // Fenster-Handle des TNA-Bereichs
  AnzahlIcons  : integer;         // Anzahl Icons im TNA-Bereich
  Schleife     : integer;         // Schleifenvariable
  pID          : THandle;         // Handle für Prozess, der die TNA verwaltet
  HProcess     : THandle;         // OpenProcess-Handle zum pID-Prozess
  pMemory      : Pointer;         // Zeiger auf reservierten Speicher im TNA-Prozess
  AnzahlBytes  : integer;         // Anzahl der im TNA-Prozess zu reservierenden Bytes
  Gelesen      : cardinal;        // Anzahl gelesener Bytes;
  TB           : TTBButton;       // für ReadProcessMemory
  IconData     : TNotifyIconData; // für ReadProcessMemory
begin
  Result := - 1;
  AnzahlBytes := 256;
  IconData.cbSize:= SizeOf(TNotifyIconData);

  Wnd := SuchenTNAWindow;
  if Wnd <> 0 then
    begin
      AnzahlIcons := SendMessage(Wnd, TB_ButtonCount, 00);

      // TNA-Prozess öffnen
      GetWindowThreadProcessId(Wnd, @pID);

      HProcess := OpenProcess(Process_VM_Operation
                                or Process_VM_Read
                                or Process_VM_Write,
                              false,
                              pID);

      // Speicher im TNA-Prozess reservieren.
      pMemory := VirtualAllocEx(HProcess,
                                nil,
                                AnzahlBytes,
                                MEM_Reserve
                                  or MEM_Commit,
                                Page_ReadWrite);

      // Jedes TNA-Icon daraufhin prüfen, ob das Handle "IconData.Wnd"
      // existiert. Wenn nicht, dann liegt eine Icon-"Leiche" vor,
      // die gelöscht wird.
      for Schleife := AnzahlIcons - 1 downto 0 do
        begin
          if SendMessage(Wnd, TB_GetButton, Schleife, Cardinal(pMemory)) <> 0 then
            if ReadProcessMemory(HProcess,
                                 pMemory,
                                 @TB,
                                 SizeOf(TB),
                                 Gelesen) then
              if ReadProcessMemory(HProcess,
                                   Pointer(TB.dwData),
                                   @IconData.Wnd,
                                   SizeOf(IconData.Wnd) + SizeOf(IconData.uID),
                                   Gelesen) then
                if not IsWindow(IconData.Wnd) then          // Icon-Leiche ???
                  Shell_NotifyIcon(NIM_Delete, @IconData);  // Icon löschen
        end;

      // aufräumen
      VirtualFreeEx(HProcess,
                    pMemory,
                    0,
                    MEM_Release);
      CloseHandle(HProcess);

      // Anzahl gelöschter Icons ermitteln
      Result := AnzahlIcons - SendMessage(wnd, TB_ButtonCount, 00);
    end;
end;

procedure TMainform.FormCreate(Sender: TObject);
begin
  // Speicherlecks beim Programmende anzeigen
  ReportMemoryLeaksOnShutdown := true;
end;

function TMainform.SuchenTNAWindow : HWnd;
begin
  // Sollte bei allen Windowsversionen ab XP gleich sein.

  Result :=  FindWindow('Shell_TrayWnd'nil);
  Result :=  FindWindowEx(Result, 0'TrayNotifyWnd'nil);
  Result :=  FindWindowEx(Result, 0'SysPager'nil);
  Result :=  FindWindowEx(Result, 0'ToolbarWindow32'nil);
end;

procedure TMainform.RefreshClick(Sender: TObject);
var
  Ergebnis : integer;
begin
  Ergebnis := TNA_Refresh;
  if Ergebnis > - 1 then
    Label1.Caption := 'Gelöschte Icons: ' + IntToStr(Ergebnis)
  else
    Label1.Caption := 'TNA-Fenster nicht gefunden!';
end;

end.
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Do 02.06.11 14:59 
Na, das sieht doch nach einer sauberen Lösung aus.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Do 02.06.11 16:14 
user profile iconGerd Kayser hat folgendes geschrieben Zum zitierten Posting springen:
Ob das Programm unter 64-Bit funktioniert, kann ich hier leider nicht testen.
Nein, so nicht, da die Datenstruktur logischerweise bei einem 64-Bit Prozess anders aussieht. (64-Bit Pointer, ...)

Diese Version funktioniert immer (wobei eigentlich die Prüfung sein müsste, ob der Zielprozess 64-bittig ist, aber da war ich zu faul nachzuschauen wie das geht und für 32-Bit Delphi geht es auch so ;-)):
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
function FindTNAWindow: HWND;
begin
  Result := FindWindow('Shell_TrayWnd'nil);
  Result := FindWindowEx(Result, 0'TrayNotifyWnd'nil);
  Result := FindWindowEx(Result, 0'SysPager'nil);
  Result := FindWindowEx(Result, 0'ToolbarWindow32'nil);
end;

function IsWow64Process: Boolean;
type
  TIsWow64Process = function(hProcess: THandle; var Wow64Process: BOOL): BOOL; stdcall;
var
  Value: BOOL;
  IsWow64ProcessFunc: TIsWow64Process;
begin
  IsWow64ProcessFunc := GetProcAddress(GetModuleHandle('kernel32'), 'IsWow64Process');
  Result := Assigned(IsWow64ProcessFunc);
  if Result then
  begin
    if not IsWow64ProcessFunc(GetCurrentProcess, Value) then
      raise Exception.Create('Bad process handle');
    Result := Value;
  end;
end;

function RefreshTNAIcons: Integer;
type
  TTBButton64 = packed record
    iBitmap: Integer;
    idCommand: Integer;
    fsState: Byte;
    fsStyle: Byte;
    bReserved: array [1 .. 6of Byte;
    dwData: Int64;
    iString: Int64;
  end;
var
  TNAWindow: HWND; // Fenster-Handle des TNA-Bereichs
  i, IconCount: Integer; // Anzahl Icons im TNA-Bereich
  TrayProcessID: THandle; // Handle für Prozess, der die TNA verwaltet
  TrayProcessHandle: THandle; // OpenProcess-Handle zum pID-Prozess
  pMemory: Pointer; // Zeiger auf reservierten Speicher im TNA-Prozess
  BufferSize, // Anzahl der im TNA-Prozess zu reservierenden Bytes
  ReadBytes: Cardinal; // Anzahl gelesener Bytes;
  TB: TTBButton; // für ReadProcessMemory
  TB64: TTBButton64; // 64-Bit
  IconData: TNotifyIconData; // für ReadProcessMemory
  ReadSuccessful, UseWow64Data, CanProcessEntry: Boolean;
begin
  Result := -1;
  BufferSize := 256;
  IconData.cbSize := SizeOf(TNotifyIconData);

  TNAWindow := FindTNAWindow;
  if TNAWindow <> 0 then
  begin
    IconCount := SendMessage(TNAWindow, TB_BUTTONCOUNT, 00);
    // TNA-Prozess öffnen
    GetWindowThreadProcessId(TNAWindow, @TrayProcessID);
    TrayProcessHandle := OpenProcess(PROCESS_VM_OPERATION or PROCESS_VM_READ or PROCESS_VM_WRITE, False,
      TrayProcessID);
    // Speicher im TNA-Prozess reservieren.
    pMemory := VirtualAllocEx(TrayProcessHandle, nil, BufferSize, MEM_RESERVE or MEM_COMMIT, PAGE_READWRITE);
    try
      UseWow64Data := IsWow64Process;
      // Jedes TNA-Icon daraufhin prüfen, ob das Handle "IconData.Wnd"
      // existiert. Wenn nicht, dann liegt eine Icon-"Leiche" vor,
      // die gelöscht wird.
      for i := IconCount - 1 downto 0 do
      begin
        if SendMessage(TNAWindow, TB_GETBUTTON, i, lParam(pMemory)) <> 0 then
          if UseWow64Data then
            CanProcessEntry := ReadProcessMemory(TrayProcessHandle, pMemory, @TB64, SizeOf(TB64), ReadBytes)
              and ReadProcessMemory(TrayProcessHandle, Pointer(TB64.dwData), @IconData.Wnd,
              SizeOf(IconData.Wnd) + SizeOf(IconData.uID), ReadBytes)
          else
            CanProcessEntry := ReadProcessMemory(TrayProcessHandle, pMemory, @TB, SizeOf(TB), ReadBytes) and
              ReadProcessMemory(TrayProcessHandle, Pointer(TB.dwData), @IconData.Wnd,
              SizeOf(IconData.Wnd) + SizeOf(IconData.uID), ReadBytes);
        if CanProcessEntry and not IsWindow(IconData.Wnd) then // Icon-Leiche ???
          Shell_NotifyIcon(NIM_DELETE, @IconData); // Icon löschen
      end;
    finally
      // aufräumen
      VirtualFreeEx(TrayProcessHandle, pMemory, 0, MEM_RELEASE);
      CloseHandle(TrayProcessHandle);
    end;
    // Anzahl gelöschter Icons ermitteln
    Result := IconCount - SendMessage(TNAWindow, TB_BUTTONCOUNT, 00);
  end;
end;
Wie wäre es, wenn du das gleich einmal in der Library als neuen Eintrag einstellst? ;-)
ral24092
Hält's aus hier
Beiträge: 1



BeitragVerfasst: Di 07.05.19 08:04 
Man muss "NOTIFYICONOVERFLOWWINDOW" finden, dann "NOTIFYICONOVERFLOWWINDOW" aktivieren und zum Schluss die Maus über "NOTIFYICONOVERFLOWWINDOW" laufen lassen.

Im Anhang der vollständige Code.

LG Rale
Einloggen, um Attachments anzusehen!