Announcement

Collapse
No announcement yet.

Anwendung beenden

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Anwendung beenden

    Hallo!

    Ich habe eine Anwendung erstellt die sich "manuell" - aufruf von "Close" normal beenden lässt.

    Wird jedoch Windows (NT) beendet, wird meine Anwendung nicht - wie alle anderen Anwendungen - automatisch beendet und verhindert das herunterfahren des Rechners.

    Wie ist das möglich - was mache ich falsch?

    Gruss

    Ahiram

  • #2
    Das Thema hatten wir schon mal. Bitte <font color=#ff0000>nicht</font> als Vorwurf verstehen. Meine Frage ist, ob du irgendwelche speziellen Komponenten benutzt, die dir evtl. ein paar Systemeingriffe abnehmen. Ich dachte da z.B. an:<br><br>
    1. Hotkey-Funktionen<br>
    2. Funktionen, die dein Programm in der TNA anzeigen usw.<br><br>
    Alles Funktionen, für die du sonst diverse WinAPI-Aufrufe tätigen müsstest. Es hat sich nämlich hier und im DF herausgestellt, dass solche Komponenten intern die Botschaften selbst bearbeiten und offenbar die eine, die zum Beenden wichtig ist, nicht korrekt zurückgeben, bzw. sich selbst nicht korrekt beenden. Und dadurch hängt alles. System-mäßig, meine ich ... das andere ist altersbedingt ... ;o)<br><br>
    Alternativ könnte man das Programm ja mal unter Win9x testen.<br>
    Und dann noch dies als Schnellhilfe:
    http://entwickler-forum.de/webx?50@@.ee86305<br><br>
    Gruß,<br>Mathias

    Comment


    • #3
      Hallo,

      erstmal danke für deine Hinweise

      Auch ich lass meine Anwendung als Tray in der Taskbar erscheinen.

      Das Problem trat erst auf als ich eine Tray-Komponente (TCoolTrayIcon)
      aus meinem Projekt entfernte und diese durch folgenden (sparsamen) Quelltext ersetzte:

      const WM_TRAYMSG = WM_USER + 99; // User Message für Tray

      type
      TForm1 = class(TForm) ...
      private
      FnotiTray: TNotifyIconData;
      procedure TrayMessage(var Message : TMessage); message WM_TRAYMSG;
      ...
      public
      end;

      implementation
      ...

      procedure TForm1.FormCreate..
      begin
      //notifyIconData-Struktur installieren ...
      with FnotiTray do begin
      cbSize := SizeOf(FnotiTray);
      Wnd := Handle;
      uFlags := NIF_ICON + NIF_MESSAGE + NIF_TIP;
      uCallBackMessage := WM_TRAYMSG;
      hIcon := Application.Icon.Handle;
      szTip := 'Zeiterfassung';
      end;
      Shell_NotifyIcon(NIM_ADD, @FnotiTray); //*)
      ....
      end;

      procedure TForm1.TrayMessage(var Message: TMessage);
      var i:integer;
      begin
      if message.LParam = WM_LBUTTONDBLCLK then
      begin
      frmZeit.Show;
      dmZeit.connectingDB;
      for i:= 0 to componentCount -1 do
      if components[i] = frmFile then frmFile.FormStyle := fsStayOnTop;
      end;
      end; //*)

      procedure TForm1.FormClose .....
      begin
      ...
      Shell_NotifyIcon(NIM_DELETE, @FnotiTray); //tray icon löschen
      ...
      end;

      Woher ich genau den Quelltext hatte weiss ich nicht mehr. Sicher ist das erst seit dem Austausch Windows NT nicht mehr automatisch beendet.

      Gruss
      ahira

      Comment


      • #4
        Ich weiß nicht, ob´s für das Problem verantwortlich ist. Ich habe meine TNA-Funktion immer so abgefragt:
        <pre>
        procedure TForm1.TrayMessage...
        begin
        &nbsp;&nbsp;<b>if(Message.msg = WM_TRAYMSG) then</b>
        &nbsp;&nbsp;&nbsp;&nbsp;begin
        &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(Message.lPa ram = ....) ...
        &nbsp;&nbsp;&nbsp;&nbsp;end;
        &nbsp;&nbsp;<b>inherited;</b>
        end;</pre>
        Also, er führt die Kontrolle aus, ob überhaupt die Nachricht "WM_TRAYMSG" angekommen ist, dann macht er die Sache mit dem Mausklick usw., und ganz egal wie - am Ende gibt er die Kontrolle (was auch immer) mit "inherited" an das System zurück. Hilft das weiter?, denn ansonsten kann ich - so auf den ersten Blick - keinen Fehler in der Funktion entdecken.<br><br>Gruß,<br>Mathias

        Comment


        • #5
          der inherited Call ist in diesem Moment sinnlos. Die Message wurde als wm_User + X erst für und in dieser Unit definiert. Sollte vom inherited System genau diese Message wm_User + X schon vorbelegt und benutzt sein dann hat sie garantiert NICHT die gleiche Bedeutung. Es ist also falsch hier inherited zu benutzen.

          Besser wäre sowieso mit wm_TrayIcon := RegisterMessage(UniqueMessageNameHere); erst zur Laufzeit, dynamisch eine Systemeineindeutige Message-ID zu erstellen. Dann ist auch garantiert sichergestellt das diese Message eindeutig ist und nicht zu Problemen führen wird. Eine Annahme das wm_User + 99 noch NICHT andersweitig benutzt wird führt zur zwangsläufigen Konsequenz das sie schon benutzt sein könnte und wäre dann keine exakter Programmierstil, und zweites MUSS dann sichergestellt sein das auch NUR dieses Formular auf wm_user+99 regaiert, kein inherited oder anderes Formluar auch nicht der DefaultHandler hat nämlich das Wissen darüber was wm_User + 99 bedeutet und wie darauf zu reagieren wäre. Bzw. viel fataler wäre demnach das wm_user +99 schon mal definiert wurde und nun der inherited Handler diese Message als was ganz anderes interpretiert als sie tatsächlich ist.

          Gruß hage

          Comment


          • #6
            Nächstes problem: Die NotifyStruct benötigt ein Wnd: hWnd um diesem die benutzerdefinierte Message zu senden. Nun wird erstmal das Trayicon registriert, danach wird z.B. Form.BorderStyle geändert und schwups wird das FensterHandle Form.Handle zerstört und ein neues erzeugt, siehe .RecreateWnd(). Ein erneuter Aufruf dieser NotifyStruct() wird dann mit dem neuen hWnd arbeiten, also nicht mehr das originale TrayIcon ansprechen.<br>

            Zusätzlich sollte das uID Member mit einer eindeutigen ID <> 0 belegt werden, ansonsten MUSS nämlich die Shell das hWnd Member als Identifizierungsmerkmal nutzen. Und wie oben angedeutet kann das mit Delphi TWinControls und Descends zu Problemen führen.<br>

            Gruß Hage

            Comment


            • #7
              Zwei Fragen, Hagen, wenn du gestattest.<br><br>
              1. Ist "inherited" nun einfach nur überflüssig oder wirklich <b>falsch</b>?<br><br>
              2. Ich überlege schon seit einiger Zeit, was passiert, wenn verschiedene Programme die selben Nachrichten á "WM_USER + 99" usw. benutzen? Es könnte ja sein, dass jemand mein Programm <u>und</u> das von Ahiram benutzt, und in beiden käme jetzt die besagte Message vor. Sollte ich also meine Programme umändern, um solche Probleme zu vermeiden? Ich denke: ja.<br><br>
              Mathias.<br><br>
              PS: Und vielleicht hättest du ja auch eine Idee zu meiner Frage hier:<br>
              http://entwickler-forum.de/webx?50@@.ee7127e.ee87828/0<br><br>
              (Der Delphi-API-Ordner geht nämlich ein bisschen unter.)Nur wenn du die Zeit hast, natürlich

              Comment


              • #8
                Hm, ich finde "RegisterMessage" nirgendwo dokumentiert. Hättest du da mal mehr Infos, Hagen?<br><br>Mathias

                Comment


                • #9
                  Hallo Mathias,

                  Hagen meint bestimmt die Win-Funktion RegisterWindowMessage().

                  Tschüß

                  Torste

                  Comment


                  • #10
                    Ja, <b>RegisterWindowMessage</b> ist richtig, sorry.

                    @Mathias:
                    1.) FALSCH,
                    da die Bedeutung von wm_User + 99 = wm_MyTaskIconID nur der Unit die sie definiert hat, bekannt ist. Mit inherited wird nun diese Message an die Vorgänger Routine weitergeleitet. Da diese ja viel früher als Deine wm_MyTaskIconID programmiert wurde konnte sie auch nichts von wm_MyTaskIconID wissen. Wie soll nun die Vorgänger methode damit umgehen ? Eigentlich sollte sie sie ignorieren, es gäbe also überhaupt keinen Vorgänger sondern nur den DefaultHandler. Dieser rührt sich aber nur bei allgemein fest definierten Messages. Tatsächlich würde also mit inherited meistens NICHTS passieren da die Message ignoriert würde. Einfach gesagt: wm_user + 99 ist noch niemals irgendwo benutzt wurden und nur DEINE wm_MyTaskIconID ist wm_User + 99. Also bei benutzerdefinierten Messages ist inherited sinnlos. Aber, was ist wenn in Unit Forms o.ä. mit wm_AktivateAtomBomb = wm_User + 99; schon eine Message mit der gleichen ID wie wm_MyTaskIconID existierte ?! Nun, mit inherited würde dann von procedure .WMMyTaskIcon() das inherited = .WMActivateAtomBomb() aufgerufen. Der Parameter von WMMyTaskIcon.Active = Boolean ist an der selben stelle wie WMActivateAtomBomb.DestroyEarth = Boolean;<br>

                    In beiden Fällen würde entweder inherited sinnlos sein, da nichts passiert oder sogar gefählich, da inherited dann garantiert falsch interpretiert, weil die gerade eben definierte Message und deren Bedeutung dem inherited garnicht bekannt sein kann.<br>
                    Oder eben eine komplett andere Bedeutung besäße, es könnte also durchaus eiges zerstört werden.

                    gruß Hage

                    Comment


                    • #11
                      Nun, mit RegisterWindowMessage() hat man die Möglichkeit eine ID die wirklich eindeutig ist zu definieren. Oder genauer gesagt zu einem eindeutigen Namen die eindeutige ID vom System zu bekommen. Damit würden auch zwei verschiedene Prozesse immer zum gleichen Namen die gleiche ID erhalten. Das ist gut da somit beide Prozesse sich per Messages unterhalten können, und sich denoch sicher sein können das beide die gleiche Message-ID benutzen.<br>

                      Nachteilig im delphi ist aber, daß keine Variablen als Message ID Bezeichner in der "message" deklaration benutzt werden können. Das heist um auf eine mit registerWindowMessage() aquirierte ID reagieren zu können muß immer die .WndProc() überschrieben werden und in dieser kann auch keine CASE Msg.Msg OD benutzt werden. Wir müssen also immer umständlich WndProc überschreiben und jede solch registrierte ID mit if Msg.Msg = wm_MyID then ; abfragen.<br>

                      Gruß Hage

                      Comment


                      • #12
                        Normalerweise ist es REGEL das eine Anwendung die an eine andere Anwendung Messages verschickt NUR solche verschickt die auch klar bekannt und definiert sind. Also eigentlich nur die SystemMessages wie wm_GetText usw. Natürlich steht es dem Coder frei das wm_Gettext = 13 anders zu interpretiern, z.B. als wm_ActivateAtomBomb <br>

                        Die Regeln und die exakte Einhaltung dieser, macht erst dieses Konzept tragfähig.

                        Gruß Hage

                        Comment


                        • #13
                          Gut, dann werd´ ich mein TNA-Programm mal ändern, damit es auch auf Systemen lauffähig ist und bleibt, auf denen Ahirams Programm läuft. )

                          Mathias

                          Comment


                          • #14
                            Na das war ja mal relativ einfach, Hagen. )<br><br>
                            1. Das Unwissen mit dem evtl. mehrfachen Benutzen von Messages á "WM_USER + 99" lässt sich, denke ich, damit entschuldigen, dass es sich auch Buchautoren manchmal sehr einfach machen. Mein bisheriger TNA-Code stammt aus einem Buch, und da geschah es genau so. Ich muss aber zugeben, dass der Autor nie "inherited" aufgerufen hat. Soviel dazu. (<br><br>
                            2. Gibt es evtl. eine Art Gegenstück zu "RegisterWindowMessage", oder wird diese automatisch beim Beenden des Programms wieder ... sagen wir mal: freigegeben. Ich habe nämlich nichts finden können.<br><br>
                            3. Ich musste mein Programm auch gleich noch im DPR-Quelltext ändern. Ich hatte nämlich eine Funktion drin, die prüfte, ob das Programm schon läuft. Wenn ja, dann hat sie (falls das Tool minimiert war) die Tray-Botschaft verschickt, damit mein Programm quasi in den Vordergrund geholt wird. Na ja, ich hab´s jetzt mit der Botschaft "WM_SYSCOMMAND" und "SC_RESTORE" gelöst, und das klappt ja auch. )<br><br>
                            So, Ahiram, damit du auch was davon hast, werde ich mich mal als Verkünder betätigen. Bei Fehlern bitte korrigierend eingreifen, Hagen! )<br><br>
                            Mathias.<br><br>
                            <pre>
                            type
                            &nbsp;&nbsp;TForm1 = class(TForm)
                            &nbsp;&nbsp;&nbsp;&nbsp;procedure FormCreate(Sender: TObject);
                            &nbsp;&nbsp;&nbsp;&nbsp;procedure FormClose(Sender: TObject; var Action: TCloseAction);
                            &nbsp;&nbsp;private
                            &nbsp;&nbsp;&nbsp;&nbsp;FnotiTray : TNotifyIconData;
                            &nbsp;&nbsp;public
                            &nbsp;&nbsp;protected
                            &nbsp;&nbsp;&nbsp;&nbsp;procedure WndProc(var Message: TMessage); override;
                            &nbsp;&nbsp;end;</pre>
                            <pre>implementation</pre>
                            <pre>
                            const
                            &nbsp;&nbsp;myTaskbarId = 250901; // eine eindeutige ID
                            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n bsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// du kannst z.B. das Datum nehmen (25.09.01)
                            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n bsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// oder die Maße deiner Freundin ...
                            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n bsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// hi hi
                            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n bsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// ´ne ID "906090" )
                            var
                            &nbsp;&nbsp;WM_TRAYMSG : UINT = 0;</pre>

                            <pre>
                            procedure TForm1.FormCreate(Sender: TObject);
                            begin
                            &nbsp;&nbsp;WM_TRAYMSG := RegisterWindowMessage('AhiramsSuperDuperProgramm') ; // ;o)
                            &nbsp;&nbsp;//
                            &nbsp;&nbsp;// laut Hilfe ist der Rückgabewert im Fehlerfall Null
                            &nbsp;&nbsp;// also nur mit der TNA verbinden, wenn die Rückgabe ungleich Null ist
                            &nbsp;&nbsp;//
                            &nbsp;&nbsp;if(WM_TRAYMSG <> 0) then
                            &nbsp;&nbsp;&nbsp;&nbsp;begin
                            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FnotiTray.cbSi ze := sizeof(TNotifyIconData);
                            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FnotiTray.W nd := {Form1.}Handle;
                            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FnotiTray.u ID := PopEyh5TaskbarId;
                            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FnotiTray.uFla gs := NIF_MESSAGE OR NIF_ICON OR NIF_TIP;
                            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FnotiTray.uCal lbackMessage := WM_TRAYMSG;
                            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FnotiTray.hIco n := Application.Icon.Handle;
                            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FnotiTray.szTi p := 'Zeiterfassung';
                            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Shell_NotifyIc on(NIM_ADD, @FnotiTray);
                            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end;
                            end;</pre>
                            <pre>
                            procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
                            begin
                            &nbsp;&nbsp;if(WM_TRAYMSG <> 0) then
                            &nbsp;&nbsp;&nbsp;&nbsp;begin
                            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Shell_NotifyIc on(NIM_DELETE, @FnotiTray);
                            &nbsp;&nbsp;&nbsp;&nbsp;end;
                            end;</pre&gt

                            Comment


                            • #15
                              <pre>
                              procedure TForm1.WndProc(var Message: TMessage);
                              var
                              &nbsp;&nbsp;i : integer;
                              begin
                              &nbsp;&nbsp;if(Message.Msg = WM_TRAYMSG) then
                              &nbsp;&nbsp;&nbsp;&nbsp;begin
                              &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(Message.lPa ram = WM_LBUTTONDBLCLK) then
                              &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;be gin
                              &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n bsp;&nbsp;frmZeit.Show;
                              &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n bsp;&nbsp;dmZeit.connectingDB;
                              &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n bsp;&nbsp;for i := 0 to ComponentCount - 1 do
                              &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&n bsp;&nbsp;&nbsp;&nbsp;if Components[i] = frmFile then frmFile.FormStyle := fsStayOnTop;
                              &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;en d;
                              &nbsp;&nbsp;&nbsp;&nbsp;end
                              &nbsp;&nbsp;else
                              &nbsp;&nbsp;&nbsp;&nbsp;inherited WndProc(Message);
                              end;
                              </pre&gt

                              Comment

                              Working...
                              X