Entwickler-Ecke

Windows API - Fremdes Programm sauber beenden


FriFra - Mo 24.06.02 17:08
Titel: Fremdes Programm sauber beenden
Wie kann ich en fremdes Programm (ich habe das Handle) sauber beenden?
TerminateProcess killt ja nur die Anwendungen. Ich will aber erreichen, dass die Programme normal beendet werden.


Chatfix - Mo 24.06.02 18:33

ich glaub das geht so


Quelltext
1:
PostMessage(FindWindow(nil,pchar('ANWENDUNGSNAME'),WM_CLOSE, 0, 0);                    


Torsten - Mo 24.06.02 19:08

Ansonsten mal WM_QUIT testen.

Es gibt aber auch noch andere, weitaus aufwendigere, Methoden.

Doch probiere erst mal die oben genannte.

Grüße

Torsten


FriFra - Mo 24.06.02 20:59

:cry: Es geht leider nicht...


Auf WM_CLOSE reagiert die Anwendung nicht und WM_QUIT beendet das Programm nicht sauber, sondern schiesst einfach nur den Task ab.


Chatfix - Mo 24.06.02 21:05

Was ist den "sauber" beenden.. wenn man den Task beendet wird die anwendung doch auch geschlossen :?:


FriFra - Mo 24.06.02 21:13

Task abschiessen ist kein sauberes Beenden, da die Applikation dann keine chance mehr hat zu reagieren! Die Anwendung soll so geschlossen werden, wie wenn man auf [X] klickt...
Die fremde Anwendung soll "merken", dass sie beendet wird...


Torsten - Mo 24.06.02 21:13

Hast Du das andere Programm mit CreateProcess gestartet?
Oder ist es eine völlig fremde Anwendung?

Grüße

Torsten


FriFra - Mo 24.06.02 21:16

Ich habe das Programm mit CreateProcess gestartet, deshalb habe ich auch das Processhandle :wink:


Chatfix - Mo 24.06.02 21:18

du kannst ja noch

WM_Destroy
WM_Endsession

probieren


Chatfix - Mo 24.06.02 21:19

oder schau mal in der Delphi-Hilfe nach ob du was findest


Torsten - Mo 24.06.02 21:22

Ah ja, sorry. Hatte ich überlesen.

OK, dann hätte ich noch eine andere Variante.

Da Du ja das Programm selber geschrieben hast, müsstest Du ja auch die Klassennamen kennen.
Somit gehe doch den direkten Weg:


Quelltext
1:
2:
if(findwindow(pchar('TMyForm'),nil) <> 0) then 
  SendMessage(findwindow(pchar('TMyForm'),nil),WM_CLOSE,0,0);


Dabei gibt es lediglich ein Problem.
Nämlich, wenn Du alle Programme mit Formularnamen TMyForm nutzt.

Grüße

Torsten[/code]


FriFra - Mo 24.06.02 21:29

Wie schon gesagt, auf WM_CLOSE reagiert das Programm nicht und WM_QUIT ist das gleiche wie TerminateProcess...

Es scheint ja keiner eine echte Lösung zu haben... Ich muss aber das Programm richtig beenden, da es sein Trayicon OnClose bzw. OnDestroy selbst entfernt und ich keine Metode kenne verweiste Trayicons zu entfernen ohne mit der Maus drüber zu fahren...


Torsten - Mo 24.06.02 21:33

Auch die letzte Lösung funzt nicht?
Komisch.

Na ich schau mich noch mal um.

Grüße

Torsten


Chatfix - Mo 24.06.02 21:33

also wen ich ein programm was ein tray-icon besitzt abschiese (prozess bzw. task beende) dann is auch das tray-icon weg...

wenn du die tray-icon-anwendung im form OnDestroy die "icon-löschen-funktion" reinmachst müsste es auch funktionieren


FriFra - Mo 24.06.02 21:36

Es funzt aber nicht... OnDestroy wird das Icon entfernt, das klappt auch beim normalen beenden, wenn ich aber den Task abschiesse bleibt das Icon... beim drüberfahren mit der Maus verschwindet es...


Chatfix - Mo 24.06.02 21:39

dan kanst dus nur noch mit DLLs versuchen die beide programme nutzen, da hört mein wissen aber auf


FriFra - Mo 24.06.02 21:46

Es müsste ja auch gehen, wenn man dem Tray eine Message sendet, damit er sich aktualisiert...


Torsten - Mo 24.06.02 21:47

Moinsen!

OK, noch mal zum Verständniss.
Die Anwendung, die beendet werden soll, ist auch von Dir geschrieben! Richtig?

Wenn dem so ist, dann kannst Du in das Programm, welches beendet werden soll, einen MessageHandler einbauen.

Beispiel:


Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
private
  procedure MyMsgHandler(var: msg: TMsg; var Handled: Boolean);
public

...

procedure TForm1.FormCreate(Sender: TObject);
begin
   Application.OnMessage:= MyMsgHandler;
end;

...

procedure MyMsgHandler(var: msg: TMsg; var Handled: Boolean);
begin
   if msg.Message = WM_IRGENDWAS then
  ...
end;


Sollte funktionieren. Habe aber jetzt gerade nicht getestet.

Grüße

Torsten


FriFra - Mo 24.06.02 21:55

Das aktuelle Programm ist von mir, aber die eigentliche Anwendung soll universell einsetzbar sein. Und das Problem mit den verwaisten Trayicons besteht bei alle Programmen welche im Tray laufen... deshalb wäre mir eine Lösung lieber, die entweder das Programm richtig schliesst oder aber den Systray repaintet...


Chatfix - Mo 24.06.02 21:59

komisch, also wenn ich z.B. icq abschiese dann ist das rtray-icon auhc mit weg.. aber du kannst ja kurzzeitig die taskleiste verstecken und wieder einlbenden

var hTaskBar: THandle;

Taskleiste verstecken:


Quelltext
1:
hTaskbar:=FindWindow('Shell_TrayWnd',nil); ShowWindow(hTaskBar, SW_HIDE);                    


Taskleiste sichbar machen:


Quelltext
1:
hTaskBar:=FindWindow('Shell_TrayWnd', nil); ShowWindow(hTaskBar, SW_SHOWNORMAL);                    


FriFra - Mi 26.06.02 16:30

Die Funktion "Task beenden" unter Win98 enspricht dem "Schliessen" aus dem Kontextmenü!
Deshalb verschwindet z.B. auch das ICQ icon... Wenn man aber den Process killt bleibt auch das ICQ Icon (ich habs getestet!).
Der Taskmanager von NT/2000 und XP kann unter Prozesse die Task genauso killen wie terminateprocess... die Trayicons bleiben...


FriFra - Do 27.06.02 11:45

Ich habe mir jetzt eine Procedure gebastelt, welche verweiste Icons beseitigt:


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:
procedure TService1.RemoveOldFromTray();
var
TrayWnd, TrayNWnd:HWND;
TrayRect:TRect;
Xo,Yo,X,Y,CX,CY:integer;
begin
//Save old position
Xo:=Mouse.CursorPos.X;
Yo:=Mouse.CursorPos.Y;
//Traywindow finden
TrayWnd :=FindWindow('Shell_TrayWnd',nil);
TrayNWnd:=FindWindowEx(TrayWnd, 0, 'TrayNotifyWnd', nil);
GetWindowRect(TrayNWnd,TrayRect);
//move the mouse over the systray area
CX:=0;
CY:=0;
for Y:=TrayRect.Top to TrayRect.Bottom do
 begin
 if CY=10 then
  begin
  for X:=TrayRect.Left to TrayRect.Right do
   begin
   if CX=10 then
    begin
    SetCursorPos(X,Y);
    //a little pause, whithout this the systray does'nt notify the mousemove
    Sleep(1);
    CX:=0;
    end;
   CX:=CX+1;
   end;
  CY:=0;
  end;
 CY:=CY+1;
 end;
//ResetCursorPos
SetCursorPos(Xo,Yo);
end;


Das ist zwar im Grunde nur ein Workaround, aber bis sich etwas besseres findet geht das auch so.


Chatfix - Do 27.06.02 14:07

FriFra hat folgendes geschrieben:
Die Funktion "Task beenden" unter Win98 enspricht dem "Schliessen" aus dem Kontextmenü!
Deshalb verschwindet z.B. auch das ICQ icon... Wenn man aber den Process killt bleibt auch das ICQ Icon (ich habs getestet!).
Der Taskmanager von NT/2000 und XP kann unter Prozesse die Task genauso killen wie terminateprocess... die Trayicons bleiben...


Ich benutze ICQ und das Icon geht manchmal und manchmal nicht :?: keine ahnung warum *g*


damadmax - Sa 27.07.02 18:24

ganz einfach: ICQ ist der letzte dreck.


Chatfix - Sa 27.07.02 18:35

passt ja voll zum thema *fg*


damadmax - So 28.07.02 04:40

ja sorry! :twisted: :twisted: :twisted:

das kam mir grad so *gg*


Chatfix - So 28.07.02 04:46

*grins* Es sei dir verziehen gggggg


SpeedyGTD - So 28.07.02 11:10

Hallo Leute ich hab zu dem ganzen jetzt auch noch ne Frage, nach dem ich Programme nur Killen wollte, bei mir heissen die meisten nur Form1 was auch geht hab ich jetzt das Problem wie ich manche Programme schließe, zB. den Windows Explorer, kann man nicht den Form Namen auslesen. :wink:


Chatfix - So 28.07.02 11:37

ich glaub solche programme kannst du nach dem "anwendungsname" killen...

aber bin grad aufgestanden.. muss ich mal guggn ob ich sowas find....


SpeedyGTD - So 28.07.02 12:03

geht leider nicht, hab ich schon probiert, wenn es geht, geht das auch mit der Systemsteuerung. :oops:
Ich hab auch schon den Internen Namen probiert, geht auch nicht.


Cyberbob - Mi 20.11.02 21:26

Chatfix hat folgendes geschrieben:



Quelltext
1:
PostMessage(FindWindow(nil,pchar('ANWENDUNGSNAME'),WM_CLOSE, 0, 0);                    


Wie binde ich den Quelltext denn ein? Wenn ich das ganze in eine Button procedure packe, dann bekomme ich die Fehlermeldung zuviele Pararmeter...


Cyberb :twisted: b


Delete - Mi 20.11.02 21:37


Quelltext
1:
PostMessage(FindWindow(nil,pchar('ANWENDUNGSNAME'),WM_CLOSE, 0, 0);                    

Da fehlt eine Klammer.


Quelltext
1:
PostMessage(FindWindow(nil,pchar('ANWENDUNGSNAME')),WM_CLOSE, 0, 0);                    


Chatfix - Do 21.11.02 16:47

ui sorry *gg*

aber mit ein bischen guggn hätt das jeder rausgefunden :oops:


Cyberbob - Do 21.11.02 19:28

ja, das habe ich mittlerweile auch rausgefunden, aber as ist denn nun besser zum sauberen beenden, wm_quit oder close?


Delete - Do 21.11.02 19:41

Cyberbob hat folgendes geschrieben:
ja, das habe ich mittlerweile auch rausgefunden, aber as ist denn nun besser zum sauberen beenden, wm_quit oder close?

Ich seh schon kein Plan wie Windows funktioniert. Kuck mal hier: http://www.luckie-online.de/delphi/tutorials/fenster.shtml
Wenn du das gelesen hast, sollte alles klar sein.


noeppel - Fr 29.11.02 17:19

Um einen Klick auf das (X) zu simulieren schickt man die WM_SYSCOMMAND mit SC_CLOSE.

Quelltext
1:
SendMessage(Handle,WM_SYSCOMMAND,SC_CLOSE,0);                    

Wenn das Programm, dass geschlossen werden soll auf einen Klick auf (X) reagiert, dann sollte der Code auch funktionieren.