Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi Wie das Blockieren beim Herunterfahren verhindern/umgehen? (https://www.delphipraxis.net/143445-wie-das-blockieren-beim-herunterfahren-verhindern-umgehen.html)

Schucki 16. Nov 2009 12:01


Wie das Blockieren beim Herunterfahren verhindern/umgehen?
 
Hallo DP'ler!

ich habe folgenes Problem und finde die Lösung nicht. Vielleicht kann mirhier einer helfen der das vlt. schon gelöst hat.
Meine Anwendung läst sich nicht durch die Aktion "Windos gerunterfahren" schließen. Warum weiß ich derzeit noch nicht. :-(

Wichtig ist, das ich beim Beenden noch einie Aktionen ausführen muß!
Mein Quelltext dazu sieht wie folgt aus:

Delphi-Quellcode:
procedure TfrmMain.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  if mbtnCon.Down then begin
    if (not bolMainCanClose) and (not timClose.Enabled) then begin
      mbtnCon.Click;
      intCanClose:=0;
      timClose.Enabled:=True;
    end;
    CanClose:=False;
  end;
  frmSetup.SaveSetupExit;
end;
Wenn das Programm hier gefragt wird ob es geschlossen werden darf dann wird der Timer aktiviert weil noch Handlungen vor dem Schließen ausgeführt werden müssen. Der Timer ruft nach Ende nochmal neu das frmMain.Close auf und da bolMainCanClose dann true ist, geht die Anwendung auch zu. Allerdings klappt das nicht wenn man START BEENDEN HERUNTERFAHREN macht.

:-(

Hat jemand einen Tip für mich?

Gruß Frank

helgew 16. Nov 2009 12:51

Re: Wie das Blockieren beim Herunterfahren verhindern/umgehe
 
ja, lies mal unter msdn und hier

p80286 16. Nov 2009 13:39

Re: Wie das Blockieren beim Herunterfahren verhindern/umgehe
 
Hallo Frank,

warum arbeitest Du nicht mit WM_QUIT / Application.Terminated

Gruß
K-H

helgew 16. Nov 2009 19:28

Re: Wie das Blockieren beim Herunterfahren verhindern/umgehe
 
Zitat:

Zitat von p80286
Hallo Frank,

warum arbeitest Du nicht mit WM_QUIT / Application.Terminated

Gruß
K-H

Es geht ihm hier um das Verhalten beim Beenden, sprich die Bearbeitugn von WM_ENDSESSION und WM_QUERYENDSESSION.

Schucki 17. Nov 2009 12:25

Re: Wie das Blockieren beim Herunterfahren verhindern/umgehe
 
Danke für die Hinweise,
ich habe es nur überflogen. Muß mir das nun mal viel genauer ansehen aber im Prinzip muß es das sein denn das normale "OnCloseQuery" macht's ja nicht. Das geht nur solange ich es per HAnd beende einwandfrei. Soll der PC heruntergefahren werden, dann soll das auch funktionieren... das tut's ja im Moment nicht :-(

Also selber die MSG abfangen und abarbeiten, dann wenn es fertig ist erneut sdiese MSG des herunterfahrens verschicken?


Gruß Frank

Angel4585 17. Nov 2009 12:36

Re: Wie das Blockieren beim Herunterfahren verhindern/umgehe
 
Hast schonmal CanClose auf true gesetzt?

Wird nur der Code nicht ausgeführt, oder wird das Programm und damit WIndows nicht beendet?
Welches Windows verwendest du und wie äussert sich das, dass es nicht funktioniert?

Schucki 18. Nov 2009 01:15

Re: Wie das Blockieren beim Herunterfahren verhindern/umgehe
 
Hi,

Zitat:

Zitat von Angel4585
Hast schonmal CanClose auf true gesetzt?

Habe es mal wie folgt erweitert...

Delphi-Quellcode:
procedure TfrmMain.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  if mbtnCon.Down then begin
    if (not bolMainCanClose) and (not timClose.Enabled) then begin
      mbtnCon.Click;
      intCanClose:=0;
      timClose.Enabled:=True;
    end;
    CanClose:=False;
    Exit;
  end;
  frmSetup.SaveSetupExit;
  CanClose:=True;
end;
Ergebniss ist leider das selbe...

Zitat:

Zitat von Angel4585
Welches Windows verwendest du und wie äussert sich das, dass es nicht funktioniert?

Windows XP SP3
Es funktioniert solange ich die Anwendung von Hand beende, drück ich im Windows auf herunterfahren geht zwar meine Anwendung zu aber der PC fährt nicht runter. :-(

Dank im Voraus!
Gruß Frank

helgew 19. Nov 2009 21:02

Re: Wie das Blockieren beim Herunterfahren verhindern/umgehe
 
Zitat:

Zitat von Schucki
Also selber die MSG abfangen und abarbeiten, dann wenn es fertig ist erneut sdiese MSG des herunterfahrens verschicken?

Delphi-Quellcode:
unit Unit1;

interface

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

const
  WM_DENYSHUTDOWN = WM_USER + $AB;

type
  TForm1 = class(TForm)
    procedure FormDenyShutdown(var msg: TMsg); message WM_DENYSHUTDOWN;
  protected
    procedure WndProc(var Message: TMessage); override;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.WndProc(var Message: TMessage);
const
  LONGBOOL_FALSE : Cardinal = 0;
  LONGBOOL_TRUE : Cardinal = 1;
begin
  if (Message.Msg <> WM_QUERYENDSESSION) then
    begin
      inherited WndProc(Message)
    end
  else
    begin
      SendMessage(Form1.Handle,WM_DENYSHUTDOWN,0,0);
      Message.Result := LONGBOOL_FALSE;
    end;
end;

procedure TForm1.FormDenyShutdown(var msg: TMsg);
begin
  Application.MessageBox(
          'We can''t stop here. This is bat country!',
          'Cannot stop here',
          MB_ICONWARNING or MB_OK);
end;

end.

Komplizierter wirds nicht ;-) Ich würde aber nicht mehr mit timern arbeiten, weil ich dir an der Stelle nicht garantieren kann, dass zum Zeitpunkt des Runterfahrens (dein Programm wird ja nicht als erstes gefragt) alles noch so abgearbeitet wird und einem timing folgt, wie du dir das vorstellst. Um als erster benachrichtigt zu werden, ob die Arbeitsstation heruntergefahen wird, musst du die Funktionalität in eine .dll packen und mit dem Modulhandle einen globalen message hook einrichten (keine gute Praxis ...). Wenn du das wirklich machen willst, kannst du hier einen Überblick über die Vorgehensweise bekommen.


Edit: dass einem aber auch immer erst danach noch was einfällt...
Edit: nach Hinweis unten modifiziert

himitsu 19. Nov 2009 21:10

Re: Wie das Blockieren beim Herunterfahren verhindern/umgehe
 
@helgew: so geht es "leider" nicht.

Windows gibt jedem Programm eine gewisse Zeit (ein paar Sekunden), um diese Nachricht zu beantworten.
Wenn das Programm da nicht antwortet/reagiert, dann wird es "oftmals" einfach abgeschossen.
(jenachdem, die Windows eingestellt ist und bei mir ist "schnelles Herrunterfahren" aktivert)

Also mußt du erstmal das runterfahren abbrechen (also die Nachricht fertig verarbeiten)
und dann erst die MessageBox anzeigen (z.B. dir selber eine Message schicken, welche dann die MessageBox anzeigt)


PS: WM_QUERYENDSESSION fragt erstmal alle Programme, ob sie was dageben haben.
Hier wird noch nicht runtergefahren, also ist die Reihenfolge egal, in welcher die Programme gefragt werden.
WM_ENDSESSION sagt dann erst "So, beende dich mal ... ich fahre gleich/jetzt runter".

helgew 19. Nov 2009 21:14

Re: Wie das Blockieren beim Herunterfahren verhindern/umgehe
 
himitsu:

es geht bedingt. Ich habe es hier selbst ausprobiert, bevor ich es reingestellt hab und bis auf den Schönheitsfehler, dass nach einer Zeit die "Programm reagiert nicht" Benachrichtigung kommt. Aber selbst Windowsprogramme machen es nicht besser, bei notepad beobachtet man das gleiche Verhalten (ok... schlechte Legitimation...). Allerdings ist der Einwand berechtigt. Mir ging es aber im Moment nur darum, die Frage nach der default window procedure zu beanworten. ich trage es nach...

Edit: Änderungen siehe oben :-)

ps. ich rate aber davon ab, nachträglich den Rechner herunterzufahren, denn es ist der WM_QUERYENDSESSION message nicht zu entnehmen, welcher Modus gewählt wurde. Der Nutzer soll also nachträglich noch einmal auf Start>Computer ausschalten und sich dann für Neustart, Herunterfahren (oder Ruhezustand, wenn das auch dazugehört) entscheiden können.

Schucki 23. Nov 2009 10:56

Re: Wie das Blockieren beim Herunterfahren verhindern/umgehe
 
Hi!

Danke für Eure Antworten. Ich denke das geht in die richtige Richtung obwohl es noch nicht zu 100% läuft.
Ich kann die einzelnen Msg. filtern und dann darauf reagieren. Die ganzen OnClose und OnCloseQuery Events vom Hauptformular habe ich nun gelöscht. Entweder hier oder dort... ;)

Das wird geschickt wenn man auf mbtClose drückt...

Delphi-Quellcode:
procedure TfrmMain.mbtnCloseClick(Sender: TObject);
begin
  SendMessage(frmMain.Handle,WM_CLOSE,0,0);
end;
... Msg abhandeln ...

Delphi-Quellcode:
procedure TfrmMain.WndProc(var Message: TMessage);
const
  LONGBOOL_FALSE : Cardinal = 0;
  LONGBOOL_TRUE : Cardinal = 1;
begin
  if (Message.Msg = WM_CLOSE) then begin
    Message.Result := LONGBOOL_FALSE;
    // ShowMessage('Schließen sollst du ;-)');
    if comUnit.PortOpen then begin
      if (not bolMainCanClose) and (not timClose.Enabled) then begin
        // ShowMessage('Jaja nur erst vom Gerät abmelden!');
        mbtnConnect.Click;
        timClose.Enabled:=True;
      end;
    end else begin
      ShowMessage('So, hab mich fein abgemeldet... close Ok!');
      bolMainCanClose:=True;;
    end;
    if bolMainCanClose then Close;
  end else

  if (Message.Msg = WM_QUERYENDSESSION) then begin
    bolShutDown:=True;
    if comPtc.PortOpen then begin
      ShowMessage('Jetzt noch nicht, hab was dagegen !');
      intSavW:=Message.WParam;
      intSavL:=Message.LParam;
      mbtnClose.Click;
    end else begin
      Message.Result := LONGBOOL_TRUE;
      ShowMessage('Jetzt schon, und Tschüss...');
    end;
  end else
//  if (Message.Msg = WM_ENDSESSION) then begin
//    Message.Result := LONGBOOL_FALSE;
//    ShowMessage('Dann beende mal jetzt!');
//  end else
  begin
    inherited WndProc(Message)
  end;
end;
... und der Timer sieht so aus...

Delphi-Quellcode:
procedure TfrmMain.timCloseTimer(Sender: TObject);
begin
  inc(intCanClose);
  if (intCanClose >= 10) or ((not bolDeiniRun) and (not bolForceDeini)) then begin
    timClose.Enabled:=False;
    bolMainCanClose:=True;
    if bolShutDown then SendMessage(frmMain.Handle, WM_QUERYENDSESSION, intSavW, intSavL);
    mbtnClose.Click;
  end;
end;
Nun es klappt noch nicht... ein Beantworten auf WM_QUERYENDSESSION mit TRUE sorgt dafür das die Anwendung sofort zugeht ohne das sie sich bei dem angeschlossenen Gerät abmeldet. :-( Also muß ich min 1x mit FALSE antworten. Damit ist dann aber das Herunterfahren abgebrochen :-( und müßte neu ausgelöst werden. Wäre auch nicht so schlimm denke ich wenn man den wüste was vorher von Windows bei der 1. WM_QUERYENDSESSION gefordert wurde. Stanby, Shutdown oder Logoff???

Die Info hab ich noch nicht... so dacht ich nun das ich die WM_QUERYENDSESSION das 1. mal einfach nicht beantworte und dann selber nochmal auslöse und diese dann mit TRUE beantworte. Das geht aber wohl auch nicht... Windows wertet wohl pro MSG an alle auch mit einer sofortigen Antwort. Und wenn die nicht kommt ist es FALSE?

Bei dem angeschlossenen Gerät muß ein bestimmtes Protokoll eingehalten werden, das geht nunmal nicht direkt mit 3 Zeilen die man ihm schickt. Das muß beim Beenden abgemeldet werden, das dauert ca. 3 Sekunden. Erst wenn das passiet ist, darf man das Prg Beenden.

Funktioniert 1A bei einem manuellen Click auf mbtnClose oder ALT+F$ aber das über Herunterfahren nicht. Was könnte man noch versuchen, gibt es noch einen anderen Lösungansatz von einem erfahrenen Entwickler als mich? :glaskugel:

Danke, Gruß Frank

OregonGhost 23. Nov 2009 12:07

Re: Wie das Blockieren beim Herunterfahren verhindern/umgehe
 
Als Ergänzung: Grundsätzlich ist die Vorgehensweise, dass du im ENDSESSION (nicht im QUERYENDSESSION) deine Verarbeitung zum Herunterfahren durchführst. QUERYENDSESSION dient eigentlich ausschließlich dazu, das Herunterfahren abzubrechen.

Wichtig ist, dass du einigermaßen schnell bist. Firefox hat beispielsweise früher grundsätzlich beim Herunterfahren nichts gemacht (Session ist in den AutoRecovery-Daten gespeichert), so dass die Daten beim nächsten Start wieder da waren. Das geht schnell, normales Beenden von Firefox ist sehr langsam (wenn viele Tabs offen sind). Wenn du langsam bist, kommt ab Vista relativ schnell ein abgedunkelter Bildschirm, auf dem deutlich zu sehen ist, dass DU den Start verzögerst. Der Benutzer kann dann eiskalt auf "Sofort herunterfahren" klicken und du hast keine Chance mehr, auf irgendwas zu reagieren. Aber deine ENDSESSION-Behandlung läuft immer noch weiter, auch wenn der Bildschirm abgedunkelt ist. Ab 7 hast du sogar die Möglichkeit, einen Text anzugeben, der vom abgedunkelten Bildschirm für deine Anwendung angezeigt wird (Beispiel: VMWare Workstation 7 zeigt an, dass es gerade eine VM runterfährt), so dass der Benutzer dich vielleicht noch nicht abwürgt. Sofern du immer noch schneller fertig bist als die letzten Programme, die geschlossen werden, funktioniert das eigentlich auch ganz gut. Insofern ist, meiner Meinung nach, die korrekte Vorgehensweise, einfach im ENDSESSION dein Ding durchzuziehen und zu hoffen, dass es reicht. Wenn es nicht reicht, hat der Benutzer ab Vista explizit dein Programm abgeschossen. Das kann er natürlich sowieso, auch ohne Herunterfahren.

Schucki 27. Nov 2009 16:43

Re: Wie das Blockieren beim Herunterfahren verhindern/umgehe
 
Komme erst heute Abend dazu damit weiter zu machen.
In den letzten Tagen war ich auf der Suche nach der Message die man abfangen muß wenn ein User die Anwendeung mit der rechten Maustatste aus der Taskleiste beenden möchte. Das ist mir noch nicht gelungen herauszubekommen.

Weiß einer von Euch wie die heist?

WM_CLOSE ist es nicht :-(

Danke im Voraus!!!

Gru0 Frank

DeddyH 27. Nov 2009 16:46

Re: Wie das Blockieren beim Herunterfahren verhindern/umgehe
 
IIRC ist das WM_SYSCOMMAND mit SC_CLOSE.

Schucki 27. Nov 2009 18:25

Re: Wie das Blockieren beim Herunterfahren verhindern/umgehe
 
Tch es gelingt mir nicht die MSG zu bekommen... habe folgenes gemacht...

Delphi-Quellcode:
...
   private
     procedure WMSysCommand(var Msg: TWMSysCommand); message WM_SYSCOMMAND;
...
Und dann...

Delphi-Quellcode:
procedure TfrmMain.WMSysCommand(var Msg: TWMSysCommand);
begin
  if Msg.CmdType = SC_CLOSE then begin
    if not bolMainCanClose then mbtnClose.Click;
    Msg.Result := 0;
  end;
  Inherited;
end;
Aber wenn ichnun einen BP bei "if Msg.CmdType = SC_CLOSE then begin" setze wird der nie angefahren, meine Anwendung geht einfach nur zu :-(

Was hab ich da wohl übersehen?
Gruß Frank

DeddyH 27. Nov 2009 19:11

Re: Wie das Blockieren beim Herunterfahren verhindern/umgehe
 
Tja, weiß ich auch nicht. Kleiner Gegentest bei mir:
Delphi-Quellcode:
procedure TFormTest.WMSysCommand(var Msg: TWMSysCommand);
begin
  if Msg.CmdType = SC_CLOSE then
    ShowMessage('Tschüss');
  inherited;
end;
Über die Taskleiste, über das "X", über ALT-F4, immer sagt das Programm mir Tschüss wie erwartet (Win 7 Home Premium).


Alle Zeitangaben in WEZ +1. Es ist jetzt 06:40 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz