Entwickler-Ecke

Windows API - anderes Programm sauber beenden (hat kein Fenster)


White-Tiger - Di 30.09.08 18:51
Titel: anderes Programm sauber beenden (hat kein Fenster)
Hallo,

Ich möchte ein fremdes Programm sauber beenden so das dieses noch selber auf das beenden reagieren kann.
Ich habe dazu auch schon einiges Probiert.. leider ohne erfolg bzw. ein mit erfolg nur das dann ein Windows Fehlersound kommt den ich nicht zuordnen kann.. da das Programm normal geschloßen wurde und auch mein Programm nicht rumeckert.

Der Funktionierende Code war/ist:

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:
function TaskClose(AHandle :HWND; AProcessID: DWord): LongBool; stdcall;
var
  myProcessID: DWord;
begin
  GetWindowThreadProcessId(AHandle, @myProcessID);
  // compare process id of AHandle against AProcessID
  if myProcessID=AProcessID then
    PostMessage(AHandle, WM_CLOSE, 00);
  Result:= True;
end;
function TaskEnd(const AExeName: string): boolean;
var
  p: TProcessEntry32;
  h,ph: THandle;
begin
  Result:= false;
  p.dwSize:= SizeOf(p);
  h:= CreateToolHelp32Snapshot(TH32CS_SnapProcess, 0);
  try
    if Process32First(h, p) then
      repeat
        if AnsiLowerCase(p.szExeFile) = AnsiLowerCase(AExeName) then
          Result:= EnumWindows(@TaskClose, p.th32ProcessID)
      until (not Process32Next(h, p)) or Result;
  finally
    CloseHandle(h);
  end;
end;


Nur dieser Code greift eigentlich auf ein Fenster zu um das Programm zu beenden.. wie gesagt das Programm schließt sich auch normal.. aber danach kommt halt ein Windows Fehler Sound..

Probiert habe ich auch schon via OpenProcess(PROCESS_ALL_ACCESS, false, p.th32ProcessID); den Handle des Programms zu bekommen.. allerdings bringt mir das nichts bei PostMessage() da dies ein Fenster Handle will.. und mein Programm eigentlich keins hat..
Daher ist meine Frage wie kann ich ein Programm schließen anhand der ProzessID

Ich bedanke mich schon im vorraus über eventuelle Hilfe.
P.S. ich hatte mittlerweile gesammt 3-6 Stunden nach was passendem gegooglet.. enteder ich bin zu bläd für google oder keine Ahnung.. ich fand jedenfalls nichts...


MfG
White-Tiger


Moderiert von user profile iconNarses: Topic aus Delphi Language (Object-Pascal) / CLX verschoben am Di 30.09.2008 um 19:53


:oops:... sry war wohl falscher bereich... wusste ich nicht tut mir leid


jaenicke - So 05.10.08 17:00

Was ist das denn für ein Programm? Jedes Windows-Programm hat normalerweise ein Fenster, und sei es ein unsichtbares.

Da es also anscheinend ein Konsolenprogramm ist, da könntest du versuchen, die Tastendrücke zu simulieren, die es normal schließen.

Aber ohne mehr über das Programm zu wissen, kann man nix genaueres sagen. :nixweiss:


Hidden - So 05.10.08 17:26

user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Jedes Windows-Programm hat normalerweise ein Fenster, und sei es ein unsichtbares.

Vielleicht hilft da der Taskmanager von Yogu: http://www.delphi-forum.de/viewtopic.php?t=77955&highlight=taskmanager


White-Tiger - So 05.10.08 17:40

es handelt sich um TeamSpeak2 Server oder hat das ein Fenster.. wie gesagt der Code oben verursacht nach dem beenden vom TS Server einen Fehler Sound... nur ich kann keinen Fehler sehn^^ Das ist mein eigentliches Problem..


edit:
dazu kommt das wenn man z.B. einen Dienst hat... der ja auch kein Fenster hat, aber als normaler Prozess auftauchen kann... da müsste es doch auch eine Art geben dem zu sagen beende sich ohne das man das über die Dienst Ansteuerung macht... oder seh ich das falsch?

edit² [nach dem unteren Thread]
Hmm.. dann hat sich glaub ich edit 1 mehr oder weniger geklärt^^
Bin nen edit freak :lol: :shock:


jaenicke - So 05.10.08 17:43

[Antwort vor deinem Edit :mrgreen:]Ja, auch ein Dienst hat Fenster, zwar keine sichtbaren Fenster, aber ein Fensterhandle, denn sonst wäre ja keine Kommunikation möglich.[/Antwort]

Warum da der Fehlersound kommt, das müsste ich mal testen.


White-Tiger - So 05.10.08 17:54

Hier noch mal die funktion... wurde nen bissle optimiert:

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:
// TaskClose
procedure TaskClose(const AExeName: string);
  function TaskCloseFunc(AHandle :HWND; AProcessID: DWord): LongBool; stdcall;
  var
    myProcessID: DWord;
  begin
    GetWindowThreadProcessId(AHandle, @myProcessID);
    // compare process id of AHandle against AProcessID WM_CLOSE_QUERY  WM_CLOSE
    if myProcessID=AProcessID then
      PostMessage(AHandle, WM_CLOSE, 00);
    Result:= TRUE;
  end;
var
  p: TProcessEntry32;
  h: THandle;
begin
  p.dwSize:= SizeOf(p);
  h:= CreateToolHelp32Snapshot(TH32CS_SnapProcess, 0);
  try
    if Process32First(h, p) then
      repeat
        if AnsiLowerCase(p.szExeFile) = AnsiLowerCase(AExeName) then
        begin
          EnumWindows(@TaskCloseFunc, p.th32ProcessID);
        end;
      until (not Process32Next(h, p));
  finally
    CloseHandle(h);
  end;
end;

Aber daran dürfte es nicht liegen... habe den fehler sound aber auch nur bei TeamSpeak Server... soweit ich es getestet habe^^


Delete - Mo 06.10.08 08:55

user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
[Antwort vor deinem Edit :mrgreen:]Ja, auch ein Dienst hat Fenster, zwar keine sichtbaren Fenster, aber ein Fensterhandle, denn sonst wäre ja keine Kommunikation möglich.[/Antwort]

Warum hat ein Dienst zwingendermaßen ein Fenster? Zur Kommunikation bzw. Konfiguration sollte ein Deinst kein Fenster auf dem Benutzerdesktop anzeigen, da dies eine Sicherheitslücke darstellt. Denn dadurch wird eine Verbindung zwischen der "unsicheren" interaktiven WindowsStation und der "System"-WindowsStation geschaffen. Und ein Fenster auf dem Desktop in dem der Dienst läuft hat keinen Sinn, wenn es zur Kommunikation genutzt werden soll, da Fensterhandle Desktop spezifisch sind. Unter Windows Vista gibt es deshalb gar keine interaktiven Dienste mehr. Also eigentlich ist die gegenteilige Aussage "richtiger". Dienste haben kein Fenster.

Um eine Dienst sauber zu beenden, sollte man den Servicemanager-API-Funktionen benutzen. Dies setzt allerdings Administartive Rechte voraus.


White-Tiger - Mo 06.10.08 11:26

Anfangs hatte ich geschrieben das es Darum geht einen Dienst zu beenden^^
Eigentlich ja aber nur TS2 Server oder viel mehr jedes Programm.. und das eben ohne die "harte" variante wählen zu müssen.
TeamSpeak z.B. meldet sich bei allen Leuten die drauf sind ab... kann es aber nicht wenn es Terminiert wird^^

Die funktion die ich benutze geht zwar... nur ich bin mir nicht sicher ob TS2 nen Fenster hat bzw. es kommt nach dem es beendet wurde ein Fehler sound... und eben den möchte ich wenn möglich nicht haben.

Ansonsten... kann noch einer eine Aussage zu Diensten und Festern machen?


uall@ogc - Mo 06.10.08 11:36

Der Teamspeak Server hat also kein Fenster. WIE beendest du den denn dann normal? (Damit dieser sich abmeldet wie du beschrieben hast)


jaenicke - Mo 06.10.08 12:28

user profile iconLuckie hat folgendes geschrieben Zum zitierten Posting springen:
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
[Antwort vor deinem Edit :mrgreen:]Ja, auch ein Dienst hat Fenster, zwar keine sichtbaren Fenster, aber ein Fensterhandle, denn sonst wäre ja keine Kommunikation möglich.[/Antwort]

Warum hat ein Dienst zwingendermaßen ein Fenster?
Also wenn ich mit den Delphi-Funktionen einen Service erstelle, dann habe ich soweit ich weiß das unsichtbare Application-Fenster, über das ich auch Botschaften empfange, unter anderem WM_ENDSESSION, wenn Windows beendet wird, etc.

Ob es auch eine Möglichkeit gibt, einen Service komplett ohne unsichtbare Fensterhandles für den Botschaftenempfang zu schreiben, weiß ich nicht, kann sein, wie dann die Kommunikation zur Steuerung des Dienstes durch den Dienstemanager funktioniert, weiß ich nicht.


White-Tiger - Mo 06.10.08 12:44

user profile iconuall@ogc hat folgendes geschrieben Zum zitierten Posting springen:
Der Teamspeak Server hat also kein Fenster. WIE beendest du den denn dann normal? (Damit dieser sich abmeldet wie du beschrieben hast)

Tray Icon... wie gesagt kann sein das der auch nen Fenster hat... zumindest ist beim start so nen Bild da...
Wie dem auch sein.. ich kann Ihn ja auch mit der Oben genannten Funktion beenden... nur eben dieser blöde Fehler Sound dabei nervt.. und ich weiß nicht wo der Herkommt das sich der Server soweit ich es gesehn habe normal schließt...


Delete - Mo 06.10.08 13:57

Das Taryicon wird wohl vom Konfigurationsprogramm stammen, um den Dienst zu konfigurieren. Wenn du dieses Programm schliesst, hat das natürlich keinerlei auswirkungen auf den Dienst. aber läuft der Teamspeak Server denn wirklich als Dienst oder nicht?


jaenicke - Mo 06.10.08 14:11

Wenn man die entsprechenden Konfigurationsschritte macht, dann läuft er als Dienst, standardmäßig nicht, aber davon war ich eigentlich ausgegangen, dass er bei user profile iconWhite-Tiger als Dienst konfiguriert ist.

Nach user profile iconLuckies Beitrag ist mir gerade mal so aufgefallen, dass der Fehlersound daher rühren könnte, dass das Konfigurationsprogramm beendet wird, ohne dass der Dienst beendet wird, du also keinen Zugriff mehr über den vorgesehenen Weg auf den Dienst hast. Was beendest du?


White-Tiger - Mo 06.10.08 14:27

Mom.. also zum anfang sollte mal gesagt sein das ich den TeamSpeak Server so gelassen habe wie er ist :P
Also kein Dienst.
Allerdings beendet ein Dienst der TeamSpeak zuvor gestartet hat, diesen eben wieder... soweit ich es getestet habe entsteht dieser Sound auch nur wenn ich TeamSpeak über den Dienst beende.. andere Programme meine ich hatten das nicht..

Bin halt dabei einen TS2 Server Controller zu basteln.. derzeit überwacht es den Server status und startet Ihn gegebenenfalls neu. Beim beenden des Dienstes beendet eben dieser auch wieder TeamSpeak 2 Server.
Soll ich den Ganzen Code Posten? Wären dann aber 2 Units.. einmal die Haupt Unit und einmal der Thread der TS überwacht.


jaenicke - Mo 06.10.08 14:31

Also Moment, du hast selbst einen Dienst programmiert, der auf den TS-Server im Benutzerdesktop zugreift? Warum startest du nicht einfach den Server direkt als Dienst?


White-Tiger - Mo 06.10.08 14:50

Zum einen Kann sich TS nicht selber überwachen, keine geplanten Shutdowns ausführen mit Benachrichtigung auf allen Aktiven Servern, Floods überwachen, den bot.2x.to bot Starten und überwachen, keine TS Admin Client Like server Controlle per Programm bieten, Logs und Die Server Automatisch Backupen etc^^


jaenicke - Mo 06.10.08 14:55

Was ich meine: Das Problem ist aber, dass du von einem Dienst aus auf den TS-Server auf dem Benutzerdesktop zugreifst (mehrere TS-Server als Dienst ginge ja auch nicht). Entweder startest du den TS-Server selbst als Dienst, dann könnte der Zugriff gehen, oder solltest auch dein Überwachungsprogramm nicht als Dienst starten.

Unter XP kannst du die Interaktion mit dem Benutzerdesktop deinem Dienst erlauben, unter Vista nicht mehr.

Ich habe mich nicht damit beschäftigt, inwiefern man eine solche Überwachung einer Desktopanwendung trotzdem als Dienst implementieren kann, aber soweit ich das kenne hört sich das nach keiner guten Idee an.

// EDIT:
Aber da kennt sich user profile iconLuckie besser aus :mrgreen:.


MagicRain - Mo 06.10.08 14:56

Also ich würde das via TaskKill und Timer machen....

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:
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
function KillTask(ExeFileName: string): Integer;
const
  PROCESS_TERMINATE = $0001;
var
  ContinueLoop: BOOL;
    FSnapshotHandle: THandle;
  FProcessEntry32: TProcessEntry32;
begin
  Result := 0;
    FSnapshotHandle := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    FProcessEntry32.dwSize := SizeOf(FProcessEntry32);
  ContinueLoop := Process32First(FSnapshotHandle, FProcessEntry32);
while Integer(ContinueLoop) <> 0 do
  begin
    if ((UpperCase(ExtractFileName(FProcessEntry32.szExeFile)) =
      UpperCase(ExeFileName)) or (UpperCase(FProcessEntry32.szExeFile) =
        UpperCase(ExeFileName))) then
          Result := Integer(TerminateProcess(
            OpenProcess(PROCESS_TERMINATE,
          BOOL(0),
        FProcessEntry32.th32ProcessID),0));
      ContinueLoop := Process32Next(FSnapshotHandle, FProcessEntry32);
  end;
    CloseHandle(FSnapshotHandle);
end;
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
procedure TForm1.taskkill2Timer(Sender: TObject);
begin
  KillTask('NOTEPAD.EXE');
end;
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<


jaenicke - Mo 06.10.08 14:59

Damit stürzt du das Programm aber ab :roll:, da ist die Lösung oben tausendmal besser.

// EDIT:
MSDN Dokumentation [http://msdn.microsoft.com/en-us/library/ms686714(VS.85).aspx] hat folgendes geschrieben:
The TerminateProcess function is used to unconditionally cause a process to exit. The state of global data maintained by dynamic-link libraries (DLLs) may be compromised if TerminateProcess is used rather than ExitProcess.

TerminateProcess initiates termination and returns immediately. This stops execution of all threads within the process and requests cancellation of all pending I/O. The terminated process cannot exit until all pending I/O has been completed or canceled.

A process cannot prevent itself from being terminated.


White-Tiger - Mo 06.10.08 15:03

Nur das bei nem Task kill alle User auf dem TS nen Disconnect nach 30Secunden bekommen und nicht wissen was los ist :P

Außerdem startet mein Dienst TeamSpeak.. daher startet es Ihn auch Als System... und nicht als ein bestimmter User...
Wie gesagt mein dienst kann TS auch killen bzw. normal beenden nur danach ist nen Fehlersound... der mich eigentlich nicht weiter stört aber ich find es unprofessionell :P
Und ich will das Programm eventuell auch veröffentlichen und nicht nur für meinen Hoster nutzen^^

Mir ging es im dem Thread auch nur ums allgemeine Beenden von Programmen.. aber wenn jedes nen Fenster hat dann müsste ja alles mit der Funktion die ich benutze gehn^^

Das mein Dienst ein Dienst ist hat den Grund das es A Beim Start Laufen soll was auch bedeutet das kein User eingeloggt sein soll (eben Server betrieb) und B selber keine Verwaltung hat.. außer eine übers Internet gesteuert
Wo dann eben die Admin Verwaltung für Kunden und Server betreiber möglich ist.. So brauchen die Kunden nicht mehr zwingend eine Webinterface und wir admins können den TS jeder zeit überwachen... und steuern