![]() |
anderes Programm beenden
Hallo,
ich möchte eine .exe Datei bei Programmstart meines Programms starten und bei Beenden meines Programms auch wieder mit beenden. Ein anderes Programm aus meinem Programm heraus starten krieg ich ja noch hin, aber wie beende ich es denn wieder? Gruß Gambit |
Re: anderes Programm beenden
Du kannst z.B. an das Fensterhandle eine WM_CLOSE Nachricht schicken. Besser wäre eine SC_CLOSE Nachricht. Oder eine PostQuitMessage an den Thread. Und zu allerletzt kannst du das Programm brutal mit TerminateProcess beenden.
|
Re: anderes Programm beenden
Das Teil läuft aber nur im Tray ohne ein Fenster. Ein Fensterhandle habe ich da wohl nicht, oder?
|
Re: anderes Programm beenden
Zitat:
|
Re: anderes Programm beenden
Also folgendermaßen funzt es jetzt:
Delphi-Quellcode:
Aber wie müsste denn meine Anweisung in Button2Click ausehen, wenn ich den Prozess "kontrolliert" beenden möchte?
procedure TForm1.Button1Click(Sender: TObject);
begin FillChar(StartupInfo, SizeOf(TStartupInfo), 0); StartupInfo.cb := Sizeof(TStartupInfo); if CreateProcess(nil, // Anwendungsname PChar(edit1.text), // Parameter nil, // Security nil, // Security False, NORMAL_PRIORITY_CLASS, // Priorität nil, // Environment PChar(edit2.text), // Verzeichnis StartupInfo, ProcessInfo) then begin end else Showmessage('Fehler!'); end; procedure TForm1.Button2Click(Sender: TObject); begin TerminateProcess(ProcessInfo.hProcess,0); Showmessage('Prozess beendet!'); end; Gruß Gambit |
Re: anderes Programm beenden
@Sprint:
Habe mal versucht dein Beispiel, welches du hier im Forum mal gepostet hattest auf meines umzusetzten, funzt damit aber nicht, ich muss wohl auf terminateProcess zurückgreifen und die Keule nehmen... Hier noch Mal dein Code:
Delphi-Quellcode:
Gruß
procedure TForm1.Button1Click(Sender: TObject);
function EnumWindowsProc(hWnd: HWND; lParam: LPARAM): BOOL; stdcall; begin TList(lParam).Add(Pointer(hWnd)); Result := True; end; var SI: TStartupInfo; PI: TProcessInformation; List: TList; ProcessId: DWORD; AppHWnd: HWND; I: Integer; begin AppHWnd := 0; FillChar(SI, SizeOf(TStartupInfo), 0); SI.cb := SizeOf(TStartupInfo); SI.dwFlags := STARTF_USESHOWWINDOW; SI.wShowWindow := SW_SHOW; if CreateProcess(nil, 'NOTEPAD.EXE', nil, nil, False, 0, nil, nil, SI, PI) then begin WaitForInputIdle(PI.hProcess, INFINITE); CloseHandle(PI.hProcess); CloseHandle(PI.hThread); List := TList.Create; try if EnumWindows(@EnumWindowsProc, Longint(List)) then begin for I := 0 to List.Count - 1 do if GetWindowThreadProcessId(HWND(List.Items[I]), @ProcessId) <> 0 then if ProcessId = PI.dwProcessId then begin AppHWnd := HWND(List.Items[I]); Break; end; if IsWindow(AppHWnd) then begin ShowMessage('Fensterhandle ist $' + IntToHex(AppHWnd, 8)); SendMessage(AppHWnd, WM_SYSCOMMAND, SC_CLOSE, 0); end; end; finally List.Free; end; end; end; Gambit |
Re: anderes Programm beenden
Zitat:
Delphi-Quellcode:
var
AppPID: DWORD;
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var SI: TStartupInfo; PI: TProcessInformation; begin FillChar(SI, SizeOf(TStartupInfo), 0); SI.cb := SizeOf(TStartupInfo); if CreateProcess(nil, 'NOTEPAD.EXE', nil, nil, False, 0, nil, nil, SI, PI) then begin AppPID := PI.dwProcessId; CloseHandle(PI.hProcess); CloseHandle(PI.hThread); end; end;
Delphi-Quellcode:
Ich musste da mal ein Wait einbauen. Normalerweise würde ich Sleep nehmen. Dann läuft der Code aber auch in einem eigenen Thread. So ähnlich sieht die Funktion in meinem nachprogrammierten Task-Manager aus, um Anwendungen zu schließen.
procedure TForm1.Button2Click(Sender: TObject);
function EnumWindowsProc(hWnd: HWND; lParam: LPARAM): BOOL; stdcall; begin TList(lParam).Add(Pointer(hWnd)); Result := True; end; procedure Wait(MilliSeconds: DWORD); var Stop: DWORD; begin Stop := GetTickCount + MilliSeconds; while Stop > GetTickCount do begin Sleep(100); Application.ProcessMessages; end; end; var List: TList; I: Integer; ProcessId: DWORD; ThreadId: DWORD; ProcessHandle: THandle; ExitCode: DWORD; begin if AppPID <> 0 then begin List := TList.Create; try EnumWindows(@EnumWindowsProc, LPARAM(List)); for I := 0 to List.Count - 1 do begin ThreadId := GetWindowThreadProcessId(HWND(List.Items[I]), ProcessId); if ProcessId = AppPID then begin SendMessageTimeout(HWND(List.Items[I]), WM_SYSCOMMAND, SC_CLOSE, 0, SMTO_ABORTIFHUNG, 500, DWORD(nil^)); Wait(3000); if IsWindow(HWND(List.Items[I])) then begin PostThreadMessage(ThreadId, WM_QUIT, 0, 0); Wait(3000); ProcessHandle := OpenProcess(PROCESS_ALL_ACCESS, False, ProcessId); if ProcessHandle <> 0 then begin GetExitCodeProcess(ProcessHandle, ExitCode); TerminateProcess(ProcessHandle, ExitCode); CloseHandle(ProcessHandle); end; end; Break; end; end; finally List.Free; end; end; end; |
Re: anderes Programm beenden
OK, Danke! Dann versuch ichs mal damit...
Gruß Gambit |
Re: anderes Programm beenden
Ja, das funzt dann so auch. Einziger Schönheitsfehler - und das war auch bei meiner Haudraufundschluss-Version so - ist, dass das Icon des zu beendenden Programms nicht aus dem Tray verschwindet...erst wenn mann mit der Maus drüber fährt...
Gruß Gambit |
Re: anderes Programm beenden
Das wirst du nicht ändern könne, weil das Fenster kein WM_CLOSE oder WM_DESTROY mehr bekommt, in denen er wohl das Icon aus der TNA entfernt.
|
Re: anderes Programm beenden
Ist das immer das selbe Programm das zu beenden willst? Gibt es ein PopupMenu mit einem "Beenden" Menü`? Dann könnte man auch eine Tastenkombination schicken.
|
Re: anderes Programm beenden
Ja, es ist immer das selbe Programm. Ist ein SSL-Wrapper, den ich einsetzte um verschlüsselt an einen Datenbankserver zu senden. Nach Aufruf erscheint das Teil auch nur im Tray. Es hat nur ein Kontextmenu zum Beenden...ich wüßte nicht, was für eine Tastenkombination ich senden sollte, das Kontextmenu hat drei Menupunkte wobei der unterste "close" ist...korrektur, der Menupunkt ist "exit"...
|
Re: anderes Programm beenden
Um welches Programm handelt es sich? Stunnel?
|
Re: anderes Programm beenden
ganz genau! Ich habe auch den Source vorliegen aber mit C kenn ich mich nicht aus und ich habe auch keinen Compiler. Habe aber jetzt rausgefunden, dass man das Programm beenden kann über das PopUpMenu und dann mit der Taste "x" der Tastatur...kann man da was machen?
Gruß Gambit |
Re: anderes Programm beenden
Das schöne an solchen C Programm ist, das oft die Menus als Resource gespeichert sind. Und siehe da, das ExitMenu hat die ID 32.
Delphi-Quellcode:
FindWindow musst du eventuell noch anpassen. Ich weiß ja nicht, welche Version du benutzt.
procedure TForm1.Button1Click(Sender: TObject);
const ID_EXIT = 32; var AppHWnd: HWND; begin AppHWnd := FindWindow('stunnel 4.07 on Win32', 'stunnel 4.07 on Win32'); if IsWindow(AppHWnd) then SendMessage(AppHWnd, WM_COMMAND, MakeWParam(ID_EXIT, 0), 0); end; |
Re: anderes Programm beenden
Genial, funzt perfekt! Danke!!
Warum ist FindWindow eigentlich nicht in der Delphi Hilfe zu finden? Bei mir zumindest nicht? Was du da an Parametern übergibst ist doch der Titel des Fensters. Aber dank diesen Forums konnte ich es dann finden. Damit müsste es doch auch möglich sein, einem bestimmten Programm ferngesteuert den Focus zu geben, oder? Könnte ich gut für Premiere Pro von Adobe gebrauchen... Aber nochmals vielen Dank! Gambit |
Re: anderes Programm beenden
Weil
![]() |
Re: anderes Programm beenden
naja, andere API-Funktionen werden ja auch erklärt...
|
Re: anderes Programm beenden
Welche?
|
Re: anderes Programm beenden
CreateProcess?
|
Re: anderes Programm beenden
Ist bei mir nicht drinne: Delphi 6 Personal.
|
Re: anderes Programm beenden
Bei mir schon, ist aber glaube ich auch nicht wirklich ne API Funktion...wirst wohl recht haben...
eine Frage noch Luckie, wenn ich durch Klicken auf ein inaktives Fenster dem Fenster den Focus gebe, wird dann auch ne Windows Botschaft gesendet bzw. welche? |
Re: anderes Programm beenden
an das Fenster: WM_ACTIVATE und wohl noch WM_PAINT und WM_NCPAINT, Das dürften die wichtigsten sein.
|
Re: anderes Programm beenden
Zitat:
|
Re: anderes Programm beenden
Zitat:
So würde es gehen...zumindest versuchsweise...
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var AppHWnd: HWND; begin AppHWnd := FindWindow(nil, 'Unbenannt - Editor'); if IsWindow(AppHWnd) then BringWindowToTop(AppHWnd)else ShowMessage('Pech gehabt') end; |
Re: anderes Programm beenden
Irgendwann mal war es BringWindowToTop. Dann SetForegroundWindow. Mit der Einführung von IE4, ging es nur noch, wenn du du dich in den Thread eingehackt hast. Kann das Verhalten von den Microsoft Entwicklern irgendwie nicht nachvollziehen. Aber die werden sich bestimmt etwas dabei gedacht haben.
Delphi-Quellcode:
Hab ich jetzt so aus einem alten Projekt kopiert. Sollte aber immer noch funktionieren.
procedure TTaskMgrForm.ForceSetForegroundWindow(AHandle: HWND);
var AppHWnd: HWND; AppThreadId: DWORD; ThisThreadId: DWORD; TimeOut: DWORD; begin if GetForegroundWindow <> AHandle then begin BringWindowToTop(AHandle); SetForegroundWindow(AHandle); AppHWnd := GetForegroundWindow; if AppHWnd <> AHandle then begin AppThreadId := GetWindowThreadProcessId(AppHWnd, nil); ThisThreadId := GetCurrentThreadId; if (AppThreadId <> 0) and (ThisThreadId <> 0) then begin if AttachThreadInput(ThisThreadId, AppThreadId, True) then begin BringWindowToTop(AHandle); SetForegroundWindow(AHandle); AttachThreadInput(ThisThreadId, AppThreadId, False); end; if GetForegroundWindow <> AHandle then begin SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, @TimeOut, 0); SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, TObject(0), SPIF_SENDCHANGE); BringWindowToTop(AHandle); SetForegroundWindow(AHandle); SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, TObject(TimeOut), SPIF_SENDCHANGE); end; end; end; end; end; |
Re: anderes Programm beenden
Super, Danke!!
Und schönes Wochenende noch... Gambit |
Re: anderes Programm beenden
Shit, geht doch nicht, weil Premiere je nach Projekt seinen Fenstertitel ändert...
Gambit |
Re: anderes Programm beenden
Zitat:
|
Re: anderes Programm beenden
Tja, da bin ich wieder dumm...bei STunnel hast du ja für den Klassennamen das Gleiche verwendet wie für den Fenstertitel. Bei Notepad beispielsweise klappt es, wenn ich als Klassenname nur 'notepad' eingebe.
Wie bekomme ich denn den Klassennamen heraus? Gruß Gambit |
Re: anderes Programm beenden
Kann ich dir leider nichts sagen, da ich keine Adobe Produkte außer Acrobat Reader installiert habe.
Aber über EnumWindows und GetClassName kannst du dir selber eine Liste erstellen und guckst einfach nach. Oder du benutzt ein Tool wie Microsoft Spy++, Borland WinSight32 oder halt X-Spy von Motzi oder WinSpy von toms. Die Tools von toms und Motzi findest du hier im Forum. |
Re: anderes Programm beenden
alles klar! Danke!
|
AW: anderes Programm beenden
Hallo zusammen,
ich hatte ein ähnliches Problem und mir den Codes aus Beitrag 7 ( ![]()
Delphi-Quellcode:
Kann ich dabei den Grund irgendwie lokalisieren? Ich vermute das die Funktion hier irgendwie auf einen Fehler läuft.
EnumWindows(@EnumWindowsProc, LPARAM(List));
//--> function EnumWindowsProc(hWnd: HWND; lParam: LPARAM): BOOL; stdcall; begin TList(lParam).Add(Pointer(hWnd)); Result := True; end; Hier die einzelnen Codes von "mir":
Delphi-Quellcode:
Kann das durch meine Umstellung des Programms auf 64Bit kommen?
//...global private
private { Private-Deklarationen } AppPID : DWORD; //...Programm (als bestimmter Nutzer) starten function TTools.CreateProcessAsLogon(const User, PW, Application, param, CmdLine: WideString): DWORD; var s : WideString; si : TStartupInfoW; pif : TProcessInformation; begin ZeroMemory(@si, sizeof(si)); si.cb := sizeof(si); si.dwFlags := STARTF_USESHOWWINDOW; si.wShowWindow := 1; if CmdLine = '' then s := Application else s := Application + ' "' + CmdLine + '"'; SetLastError(0); SI.cb := SizeOf(TStartupInfo); if CreateProcessWithLogonW(PWideChar(User), nil, PWideChar(PW), 0, nil, PWideChar(s), CREATE_DEFAULT_ERROR_MODE, nil, PChar(param), @si, @pif) then begin AppPID := PIf.dwProcessId; CloseHandle(PIf.hProcess); CloseHandle(PIf.hThread); end; Result := GetLastError; end; //...gestartetes Programm beenden procedure TTools.EscapeClick(Sender: TObject); function EnumWindowsProc(hWnd: HWND; lParam: LPARAM): BOOL; stdcall; begin TList(lParam).Add(Pointer(hWnd)); Result := True; end; var List : TList; I, answer : Integer; ProcessId : DWORD; ThreadId : DWORD; ProcessHandle: THandle; ExitCode : DWORD; begin if Instant.Enabled = true then begin answer := messagedlg('Wollen sie wirklich abbrechen?', mtConfirmation, [mbYes,mbNo], 0); if answer = mrYes then begin if AppPID <> 0 then begin List := TList.Create; try EnumWindows(@EnumWindowsProc, LPARAM(List)); //<---Hier kommt die Zugriffsverletzung for I := 0 to List.Count - 1 do begin ThreadId := GetWindowThreadProcessId(HWND(List.Items[I]), ProcessId); if ProcessId = AppPID then begin if IsWindow(HWND(List.Items[I])) then begin PostThreadMessage(ThreadId, WM_QUIT, 0, 0); ProcessHandle := OpenProcess(PROCESS_ALL_ACCESS, False, ProcessId); if ProcessHandle <> 0 then begin GetExitCodeProcess(ProcessHandle, ExitCode); TerminateProcess(ProcessHandle, ExitCode); CloseHandle(ProcessHandle); end; end; Break; end; end; finally List.Free; end; end; //Log schreiben Logging(PfadP + Programs.items[Programs.itemindex] + ' wurde abgebrochen!'); answer := messagedlg('Wollen sie die bisherigen Daten einlesen?', mtConfirmation, [mbYes,mbNo], 0); if answer = mrYes then begin FertigClick(Sender); end; AppPID := 0; Progress.Animate := False; Run.Enabled := False; Programs.Enabled := True; Data.Enabled := True; TxTLogs.Enabled := True; Escape.Enabled := False; LogL.Hide; LogA.Hide; Timer3.Enabled := False; Instant.Enabled := False; Kopieren.Enabled := True; FilialeC.Enabled := True; BezirkS.Enabled := True; FilialenPS.Enabled := True; Manuell.Enabled := True; Last.Enabled := True; end; end else begin Progress.Animate := False; Run.Enabled := False; Programs.Enabled := True; Data.Enabled := True; TxTLogs.Enabled := True; Escape.Enabled := False; LogL.Hide; LogA.Hide; Timer3.Enabled := False; Instant.Enabled := False; Kopieren.Enabled := True; FilialeC.Enabled := True; BezirkS.Enabled := True; FilialenPS.Enabled := True; Manuell.Enabled := True; Last.Enabled := True; Watch.Stop; watch.Destroy; end; end; Edit: Wenn ich es als 32-Bit kompiliere funktioniert es einwandfrei. Wie kann ich den Teil für 64Bit ändern? |
AW: anderes Programm beenden
Zitat:
Delphi-Quellcode:
Du kannst keine nested procedure als callback für eine API-Funktion verwenden, Du mußt die EnumWindowsProc aus der Methode herausnehmen und als eigenständige Funktion implementieren. Nested procedures erfordern einen besondere struktur des callstacks, damit sie auf die parameter und lokalen variabled der umgebenden Procedure zugreifen können. Damit sind sie nicht kompatibel mit einem API callback.
procedure TTools.EscapeClick(Sender: TObject);
function EnumWindowsProc(hWnd: HWND; lParam: LPARAM): BOOL; stdcall; begin TList(lParam).Add(Pointer(hWnd)); Result := True; end; |
AW: anderes Programm beenden
Ok, habs.
Aber warum macht er das in 64-Bit anders? Ist das etwas was man generell wissen sollte oder einfach Willkür? |
AW: anderes Programm beenden
Zitat:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 19:05 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