[Delphi] Aktie bij sluiten applicatie*

Pagina: 1
Acties:

  • DiGuru
  • Registratie: April 2003
  • Laatst online: 05-09-2008
Ik heb een programmaatje gemaakt, dat iedere seconde logt welke applicaties een gebruiker aktief heeft, om te kunnen zien of het aantal licenties in orde is.

Het is geschreven in Delphi, maar dat zal niet veel uitmaken.

Het probleem: daar ik het 'onzichtbaar' heb gemaakt (om te voorkomen dat gebruikers het afsluiten), ziet Windows het niet als een 'echte' applicatie (denk ik) en krijg ik ook geen WM_CLOSE message (daar kontroleer ik op), maar wordt het met TerminateProcess afgesloten (denk ik) als de gebruiker uitlogt. Maar als de applicatie wordt afgesloten, moet ik dat in de logfile kunnen schrijven. Anders klopt de registratie niet.

Hoe kan ik dat toch voor elkaar krijgen?

Tussen twee haakjes, het is dus geen 'spyware' of een virus of zo iets, ik registreer alleen maar welke applicaties aktief zijn, niet wat die mensen er mee doen. Ik log ook alleen de naam van de executable, niet de naam van het aktieve document/url of wat dan ook.

Verwijderd

Check de TApplication.BeforeDestruction methode..

//edit
maw: maak een eigen afgeleide van TApplication, en overrule de beforedestruction methode. Zet daar je 'schrijfnaarlogfile' code in, en inherit de rest. Kloar.

Het kan ongetwijfeld eenvoudiger, maar dan moet je eerst meer vertellen over hoe je die app 'hide'.

[ Voor 74% gewijzigd door Verwijderd op 04-06-2003 20:39 ]


  • DiGuru
  • Registratie: April 2003
  • Laatst online: 05-09-2008
Als de TApplication.BeforeDestruction afgaat, moet hij toch ook in de destructor van het form terechtkomen? En dat treed toch op nadat de applicatie een WM_CLOSE of een SC_CLOSE message genereert of ontvangt? Ik ga er van uit, dat als ik een Application.Terminate doe, dat ik dan ook per definitie altijd in de destructor terecht kom. En dat gebeurt dus niet. De destructor gaat niet af.

Hoe kan ik trouwens een method van het TApplication object overriden?

EDIT: Als ik de applicatie zelf afsluit (kruisje klikken of Application.Terminate) werkt het wel goed. Als ik hem afkill met de task manager (bij processen), dan gaat het ook fout. En volgens mij gebruikt de Task Manager een TerminateProcess.

[ Voor 22% gewijzigd door DiGuru op 04-06-2003 21:07 ]


  • DiGuru
  • Registratie: April 2003
  • Laatst online: 05-09-2008
De relevante code:

code:
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
// In de project file:

begin
  Application.Initialize;
  Application.Title := '';
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.


// de constructor:

procedure TForm1.FormCreate(Sender: TObject);
begin
  SetWindowLong(Application.Handle, GWL_EXSTYLE, WS_EX_TOOLWINDOW);
  ShowWindow(Application.Handle,SW_HIDE);
end;


// de destructor:

procedure TForm1.FormDestroy(Sender: TObject);
begin
    Log(UserName + #9 + ComputerName + #9 + DateTimeToStr(Now) + #9 + 
        '----------'  + #9 + 'Program' +#9 + 'De-activated');
end;


// de event-handler:

procedure TForm1.ApplicationEvents1Message(var Msg: tagMSG;
  var Handled: Boolean);
begin
  if (Msg.message = WM_CLOSE) or
     ((Msg.message = WM_SYSCOMMAND) and (Msg.wParam = SC_CLOSE)) then
  begin
    Log(UserName + #9 + ComputerName + #9 + DateTimeToStr(Now) + #9 + 
        '----------' + #9 + 'Program' +#9 + 'De-activated');
    Handled := true;
  end                                     
  else
  begin
    Handled := False;
  end;
end;


// de timer:

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  Form1.Hide;
  // Hier ga ik dus mijn lijst maken en vergelijken
end;


Het onzichtbaar maken gaat goed, het programma werkt ook prima.

Verwijderd

Verplaats je code eens van FormDestroy naar OnClose. Je probleem is dan waarsch. gefixord..

//edit

het overriden van TApplication.BeforeDestruction :

code:
1
2
3
4
5
type
   ThzApplication = class(TApplication)
   public
      procedure BeforeDestruction; override;
   end;

[ Voor 53% gewijzigd door Verwijderd op 04-06-2003 21:13 ]


  • DiGuru
  • Registratie: April 2003
  • Laatst online: 05-09-2008
Als ik ook in de OnClose die logging toevoeg, werkt het nog steeds niet.

Als ik op die manier de TApplication.BeforeDestruction override, hoe zorg ik er dan voor dat mijn applicatie een ThzApplication is in plaats van een TApplication? Ik wil niet gaan editen in de standaard units.

  • martijn_brinkers
  • Registratie: November 2001
  • Laatst online: 31-10-2025
Waarschijnlijk sluit jouw applicatie niet netjes af als windows daar om vraagt. Wat je moet doen is WM_QUERYENDSESSION event afvangen. Die wordt gestuurd door windows als windows een shutdown doet. Als je dat event krijgt moet de app zichzelf netjes afsluiten omdat hij anders door windows wordt gekilled en dus de destructors niet aan roept.

zie oa

http://www.geocities.com/SiliconValley/8055/tips.htm
http://bdn.borland.com/article/0,1410,16357,00.html

  • DiGuru
  • Registratie: April 2003
  • Laatst online: 05-09-2008
Voor de volledigheid (alhoewel ik niet denk dat het daaraan ligt):

code:
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
procedure Log(s: string);
var
  f: TextFile;
begin
  if LogFile <> '' then
  begin
    {$I-}
    if FileExists(LogFile) then
    begin
      AssignFile(f, LogFile);
      Append(f);
    end
    else
    begin
      AssignFile(f, LogFile);
      Rewrite(f);
    end;
    if (IOResult = 0) then
    begin
      Writeln(f, s);
      Flush(f);
      CloseFile(f);
    end;
    {$I+}
  end;
end;


LogFile is een globale var met een volledig pad naar een file. Alle andere keren dat deze procedure wordt aangeroepen werkt het goed.

Verwijderd

Ik heb dat even getest (overriden) en dat werkt ook niet lekker..

Hoe zit het met de WM_QUIT message?

Verwijderd

OnCloseQuery gebruik ik bij een projectje en dat werk perfect (Windows 2000)

  • martijn_brinkers
  • Registratie: November 2001
  • Laatst online: 31-10-2025
Nog een link naar een Delphi voorbeeld

http://tinyurl.com/dhaw

Vergeet niet het laaste bericht te lezen (over het verwijderen van inherit)

  • DiGuru
  • Registratie: April 2003
  • Laatst online: 05-09-2008
Ik hoopte dat de WM_QUERYENDSESSION zou werken, dat klonk heel logisch. Maar helaas...

De WM_QUIT heb ik ook geprobeerd, maar die komt (zoals de beschrijving ook aangeeft) nooit bij de applicatie aan, die termineert de message handler voor die applicatie.

Kortom: het lijkt er heel sterk op, dat ik die 'standaard' messages nooit krijg, omdat Windows het niet ziet als een 'echte' applicatie. Zou het zinvol zijn om te proberen er een service van te maken? Ik moet het wel tijdens het opstarten kunnen aktiveren indien nodig. Als ik het eerst moet installeren, dan wordt het een stuk lastiger, omdat het niet de bedoeling is dat dit programma altijd aktief is: je moet het gebruiken om af en toe te kijken of je voldoende licenties hebt, niet om de aktiviteiten van de gebruikers te kontroleren.

  • martijn_brinkers
  • Registratie: November 2001
  • Laatst online: 31-10-2025
[quote]
Kortom: het lijkt er heel sterk op, dat ik die 'standaard' messages nooit krijg, omdat Windows het niet ziet als een 'echte' applicatie
[\quote]

Ik gebruik WM_QUERYENDSESSION en dat werkt. Echter heb ik niet een 'Hidden' app. Zou je kunnen kijken of het wel werkt als je de app tijdelijk niet hidden maakt?

  • DiGuru
  • Registratie: April 2003
  • Laatst online: 05-09-2008
Geweldig! Dank je, TijnFLiP! Zowel de WMQueryEndSession als de WMEndSession gaan af!!!

Ik heb het nagemaakt van je laatste link, en het werkt perfect! Ik heb hem nu zelfs twee keer :)

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 13-08 16:46

curry684

left part of the evil twins

WMQueryEndSession is hier niet voor bedoeld, die is zodat je uitlog acties kunt voorkomen tijdens langdurige operaties (installers bijvoorbeeld). WMEndSession is om bijvoorbeeld bij uitloggen persistent handlers te mollen of juist te installeren. Als jij in Task Mgr bij 'Processes' op 'End Process' klikt gaat er idd een TerminateProcess langt, maar zoals je zelf al zegt gaat het bij de Applications tab wel goed: en zo gaat het bij uitloggen ook. Je hebt 2 opties om de 'correcte' shutdown af te vangen: het Application.OnExit event, of simpelweg code schrijven in de projectfile achter de regel met 'Application.Run'.

[ Voor 6% gewijzigd door curry684 op 05-06-2003 10:53 . Reden: oeps ]

Professionele website nodig?


  • martijn_brinkers
  • Registratie: November 2001
  • Laatst online: 31-10-2025
Ik denk dat het probleem zo is dat het programma niet moet afsluiten alleen wanneer er een shutdown is (ik denk dat OnCloseQuery in zn prog False terug geeft). Windows stuurt alle programmas eerst netjes een boodschap bij afsluiten zodat de progs op een nette manier kunnen afsluiten. Als daar niet binnen een bepaalde tijd op reageren worden ze ge-terminate ( en zal dus OnExit of wat dan ook niet meer worden aangeroepen ). Wil je nou toch dat je prog netjes afsluit dan zal je toch moeten detecteren dat windows wil afsluiten en dan vervolgens moet het progje ook netjes afsluiten. WMQueryEndSession wordt eerst gestuurd naar alle progs om te vragen of het ok is om af te sluiten. Als ze allemaal OK geven dan zal er naar alle progs een WMEndSession worden gestuurd. Hierop moet het progje van DiGure dan zichzelf afsluiten.

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 13-08 16:46

curry684

left part of the evil twins

Ik zie niet zo hard in waarom het programma alleen mag terminaten op system shutdown als je bedenkt dat het toch altijd gekilled kan worden daar het onder de useraccount draait. Handel dan gewoon de close requests netjes af, want zo nodig je uit tot unclean shutdowns die de logging verneuken.

Professionele website nodig?


  • DiGuru
  • Registratie: April 2003
  • Laatst online: 05-09-2008
De enige twee manieren om het programma te killen zijn via de taskmanager (die doet dat op de botte manier, daar kun je niets mee) of via een shutdown. De huidige oplossing is dus heel bevredigend: op de WMQueryEndSession reageer ik positief, bij de WMEndSession schrijf ik de laatste gegevens weg. Werkt heel goed.

Ik had nog een ander probleempje, wat ik hiermee ook kan oplossen: een ander onderdeel van het pakket is een loginprogramma. Dat moet altijd als eerste en helemaal afgaan. Het crashed nooit, dus dat is geen probleem. Maar als de gebruiker het afkillt met de taskmanager, is de staat van het systeem onbepaald.

Om dat te voorkomen, kan ik dus tegen het systeem zeggen, dat het over 1 seconde moet rebooten. Op het moment dat ik een WMQueryEndSession krijg, zeg ik dat Windows niet plat mag gaan en zeg meteen weer dat het systeem over 1 seconde plat moet gaan. Op die manier weet ik zeker dat het loginprogramma in zijn geheel is afgegaan!

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 13-08 16:46

curry684

left part of the evil twins

DiGuru schreef op 11 June 2003 @ 21:04:
De enige twee manieren om het programma te killen zijn via de taskmanager (die doet dat op de botte manier, daar kun je niets mee)
Err wrong. Alleen bot op de 'Processes' tab. Op de 'Applications' tab gaat het zo hopeloos vriendelijk als mogelijk :)

Professionele website nodig?


  • DiGuru
  • Registratie: April 2003
  • Laatst online: 05-09-2008
curry684 schreef op 11 June 2003 @ 21:20:
[...]

Err wrong. Alleen bot op de 'Processes' tab. Op de 'Applications' tab gaat het zo hopeloos vriendelijk als mogelijk :)
Klopt. Maar daar staat het programma niet. Het staat alleen onder de processen. Het is verder onzichtbaar.

Verwijderd

Hoe heb je je app 'onzichtbaar gemaakt' ? Als je na het Application.CreateForm event Application.ShowMainForm := False; opgeeft wordt het onclose event gewoon aangeroepen.

Verwijderd

Wat dacht je van een service applicatie?

  • DiGuru
  • Registratie: April 2003
  • Laatst online: 05-09-2008
Dit is onderdeel van een heel beheersysteem, alles is nu client-less (je hoeft niets te installeren of te veranderen aan de werkstations) en je kunt dingen desgewenst op afstand opvragen en af laten gaan. Ik gebruik ook geen database-engine, want dan moet je weer extra dingen installeren. Hoe meer dingen van te voren goed moeten werken, hoe groter de kans op problemen en errors. Het is net de bedoeling dat deze spullen er voor zorgen dat alle werkstations ten alle tijden goed werken, het is niet de bedoeling dat ze eerst goed moeten werken voordat mijn spullen er op draaien!
Pagina: 1