![]() |
Herunterfahren verhindern, Programm nicht beenden
Hallo,
beim Herunterfahren von Windows soll mein Programm das Herunterfahren stoppen (falls die offene Datei noch gespeichert werden muss). Das Programm selbst darf dann auch nicht beendet werden. Mit dem folgendem Code wird zwar das Herunterfahren von Windows gestoppt, das Programm aber trotzdem von Windows beendet. Was ist daran falsch? Bitte vor dem Herunterfahren auf Button1 klicken, damit ShutdownBlockReasonCreate() aufgerufen wird, was seit Vista nötigt ist, da Windows sonst immer herunterfährt.
Delphi-Quellcode:
unit Unit1;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); protected procedure WMQueryEndSession(var Message: TWMQueryEndSession); message WM_QUERYENDSESSION; procedure WMEndSession(var Msg: TWMEndSession); message WM_ENDSESSION; public end; var Form1: TForm1; implementation {$R *.dfm} function ShutdownBlockReasonCreate(hWnd: hWnd; pwszReason: LPCWSTR): Bool; stdcall; external user32 name 'ShutdownBlockReasonCreate'; function ShutdownBlockReasonDestroy(hWnd: hWnd): Bool; stdcall; external user32 name 'ShutdownBlockReasonDestroy'; procedure TForm1.WMQueryEndSession(var Message: TWMQueryEndSession); begin Message.Result := 0; end; procedure TForm1.WMEndSession(var Msg: TWMEndSession); begin Msg.Result := 0; end; procedure TForm1.Button1Click(Sender: TObject); begin ShutdownBlockReasonCreate(handle, 'Reason gesetzt!'); end; end. |
AW: Herunterfahren verhindern, Programm nicht beenden
Meine Idee wäre jetzt dem OnClose-Ereignis des Formulars eine Routine "zu verpassen" und dort Abzufragen, ob das Programmbeendet werden darf oder nicht.
Delphi-Quellcode:
Hier sollte das Programm dann nicht beendet werden.
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin Action := caNone; // Das Formular darf nicht geschlossen werden, daher geschieht nichts. end; |
AW: Herunterfahren verhindern, Programm nicht beenden
Zitat:
|
AW: Herunterfahren verhindern, Programm nicht beenden
Den ShutdownBlockReason musst Du nach dem Beantworten der WM_QUERYENDSESSION setzen...nicht irgendwann vorher.
Sherlock |
AW: Herunterfahren verhindern, Programm nicht beenden
|
AW: Herunterfahren verhindern, Programm nicht beenden
Zitat:
Applications should call this function as they begin an operation that cannot be interrupted, such as burning a CD or DVD. When the operation has completed, call the ShutdownBlockReasonDestroy function to indicate that the system can be shut down. Quelle: ![]() Edit: Ich habs ausprobiert: Auch damit wird das Programm beendet: procedure TForm1.WMQueryEndSession(var Message: TWMQueryEndSession); begin Message.Result := 0; ShutdownBlockReasonCreate(handle, 'Reason gesetzt!'); end; Der Text der "BlockReason" wird von Windows angezeigt, wenn ich ShutdownBlockReasonCreate per Button-Click oder per WMQueryEndSession aufrufe... |
AW: Herunterfahren verhindern, Programm nicht beenden
Zitat:
|
AW: Herunterfahren verhindern, Programm nicht beenden
Ja, BlueStarHH, hast Recht, ich hatte das falsch interpretiert.
Vertrackt... Hast Du die Möglichkeit zu loggen, was passiert, also welche Messages reinkommen? Sherlock |
AW: Herunterfahren verhindern, Programm nicht beenden
Zitat:
|
AW: Herunterfahren verhindern, Programm nicht beenden
Dumme Idee: Wenn ich den Quelltext in Vcl.Forms richtig verstehe, dann gibt eine VCL-Anwendung auf WM_QUERYENDSESSION immer True (1) zurück. Und gibt das erst gar nicht an deine Formulare weiter.
Umgehen (und richtig bearbeiten) könntest du das indem du ![]() Beispiel wäre ungefähr so:
Delphi-Quellcode:
[...]
Application.HookMainWindow(myApp.WndProcHook); [...] function TMyApp.WndProcHook(var message: TMessage): Boolean; begin Result := False; case message.Msg of WM_QueryEndSession: begin Result := True; // Wird in Vcl.Forms nicht weiter abgearbeitet (...) // z.B. an Application.MainForm weiterleiten... end; end; end; |
AW: Herunterfahren verhindern, Programm nicht beenden
Zitat:
Sherlock |
AW: Herunterfahren verhindern, Programm nicht beenden
Zitat:
Delphi-Quellcode:
procedure WMQueryEndSession(var Message: TWMQueryEndSession); message WM_QUERYENDSESSION;
procedure TForm1.WMQueryEndSession(var Message: TWMQueryEndSession); begin Message.Result := 0; end; |
AW: Herunterfahren verhindern, Programm nicht beenden
Zitat:
|
AW: Herunterfahren verhindern, Programm nicht beenden
Kommt die Message vielleicht bei dem Application-Fenster an?
Dann könntest du versuchen im WndProc(-Event) der Application die Message bearbeiten. |
AW: Herunterfahren verhindern, Programm nicht beenden
Vielleicht ein ähnlicher Ansatz, der auszugsweise wiedergegeben zum Erfolg führte.:
Der Post ![]()
Delphi-Quellcode:
Deklarationen bei Form:
type TForm1 = class(TForm) ... private { Private-Deklarationen } procedure WMQueryEndSession(var Msg: TMessage); message WM_QUERYENDSESSION; {Messageverarbeitung mit Message anmelden} procedure WMEndsession(var Msg: TMessage); message WM_ENDSESSION; {Messageverarbeitung mit Message anmelden} ... end; .....
Delphi-Quellcode:
Prozeduren: procedure TForm1.WMQueryEndSession(var Msg: TMessage); // Abfolge der Closevorgänge: http://www.delphipraxis.net/965876-post19.html // // [X] am Fenster: Abmelden/Herunterfahren: // OnCloseQuery WM_QUERYENDSESSION // OnClose OnCloseQuery // OnDestroy WM_ENDSESSION // const ENDSESSION_CLOSEAPP = $00000001; {lParam - WM_QUERYENDSESSION} ENDSESSION_CRITICAL = $40000000; ENDSESSION_LOGOFF = $80000000; var CanClose: boolean; begin if (Msg.Msg = WM_QUERYENDSESSION) then begin ShutdownBlockReasonCreate(Application.Handle, ... Form1.FormCloseQuery(NIL,CanClose); {geht, wenn Msg.Result:= 1 nicht gegeben wird, allerdings ist dann das Herunterfahren unter XP behindert - Win7 nicht} {In FormCloseQuery Aufgaben erledigen und CanClose setzen} Application.ProcessMessages; Msg.Result:= ABS(DWORD(CanClose)); {mit 1= true antworten, dann kommt WM_ENDSESSION} end else begin Msg.Result:= 1; {mit 1= true antworten, dann kommt WM_ENDSESSION - sonst wartet Windows auf die} {Beendigung - Schwarzer Abmeldewartebildschirm in Windows 7} end; end; procedure TForm1.WMEndsession(var Msg: TMessage); begin if Msg.Msg = WM_ENDSESSION then {WM_SETTINGCHANGE = 26} begin if Msg.WParam = 1 then {Msg.Result:= 1 wurde in WM_QUERYENDSESSION gegeben -> WM_ENDSESSION mit Msg.WParam = 1} begin {"If the session is being ended, this parameter is TRUE; otherwise, it is FALSE"} Form1.Close; {CloseQuery -> Close} end; ShutdownBlockReasonDestroy(Application.Handle); end; end; procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean); {Problem beim automatisierten Herunterfahren/Abmelden: Thread arbeitet nur, wenn CanClose:= false} {Abfolge: 1. X -> Form.CloseQuery -> Form.Close -> Form.Hide} begin {Aufgaben erledigen und dann ...} CanClose := False; {Applikation/Formular kann nicht geschlossen werden} {oder} CanClose := True; {Applikation/Formular geschlossen werden} end; |
AW: Herunterfahren verhindern, Programm nicht beenden
Nachtrag - natürlich zum Schluss noch:
Delphi-Quellcode:
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
{Abfolge: 1. X -> Form.CloseQuery -> Form.Close -> Form.Hide} begin .... ShutdownBlockReasonDestroy(Application.Handle); .... end; |
AW: Herunterfahren verhindern, Programm nicht beenden
Wenn ich doch von vornherein weiß - als Entwickler der Software sollte ich das wissen - dass die Anwendung beim Beenden noch etwas speichern muss (was auch länger dauert), dann kann man
Delphi-Quellcode:
direkt beim Öffnen der Datei, Datenbank, whatever absetzen und wenn alles fertig ist, dann ein
ShutdownBlockReasonCreate
Delphi-Quellcode:
.
ShutdownBlockReasonDestroy
Das ist auch wesentlich einfacher abzubilden als dieses Rumgefrickel wenn denn dann ein Herunterfahren ansteht. Kann man so auch in der Doku lesen: Zitat:
|
AW: Herunterfahren verhindern, Programm nicht beenden
Zitat:
|
AW: Herunterfahren verhindern, Programm nicht beenden
Zitat:
|
AW: Herunterfahren verhindern, Programm nicht beenden
Liste der Anhänge anzeigen (Anzahl: 1)
Ich habe mal was zusammen geschraddelt. Das ist nicht wirklich gut. Aber die angefragte Funktionalität ist da. D.h. der Neustart des Systems wird verhindert. Getestet mit Delphi 2007 unter Windows 10Pro-64Bit und Windows 7Pro-32Bit.
Edit: Geänderte Version. Zusätzlich mit ausführbarer Datei. |
AW: Herunterfahren verhindern, Programm nicht beenden
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:
Wenn ich das Projket mit Delphi 10 Seattle neu compliere ist alles OK. Was macht Delphi 2010 also anders? Evtl. eine Compiler-Einstellung oder ein Bug? Kann das jemand mal bitte mit Delphi 2010 ausprobieren? Im Anhang Dein Log, was meine mit Delphi 2010 erzeugte EXE geschrieben hat. Das sieht schon komisch aus. |
AW: Herunterfahren verhindern, Programm nicht beenden
|
AW: Herunterfahren verhindern, Programm nicht beenden
Unter Windows 10 funktioniert dein beispielprojekt. Unter Windows 7 nicht mehr.
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 02:45 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-2025 by Thomas Breitkreuz