Autor Beitrag
jasocul
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 6395
Erhaltene Danke: 149

Windows 7 + Windows 10
Sydney Prof + CE
BeitragVerfasst: Di 13.01.09 10:51 
Folgende Situation:
Ich habe einen Service, der eine Stapeldatei aufruft.
Diese ruft wiederum eine Anwendung auf, die ein paar Dinge macht. Durch Application.Terminate wird diese Anwendung automatisch beendet.

Zumindest sollte es so sein. :(

Starte ich die Stapeldatei manuell, funktioniert alles, wei gewünscht. Wird aus dem Service heraus gestartet, Wird die Anwendung nicht beendet. Es hat den Eindruck, dass das Appplication.Terminate nicht ausgeführt wird.

Da ich während des Durchlaufs in der Anwendung Protokolle er zeuge, weiß ich genau, dass das Programm bis zum Terminate durchläuft.

Im FormCreate mache ich folgendes:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
procedure TSDIAppForm.FormCreate(Sender: TObject);
begin
  if ParamCount > 0 then
  begin
    Automatiklauf := True;
    SetzeFelder(ParamStr(1)); // Hier nimmt die Anwendung Einstellungen für den Ablauf vor
    btnKomplett.Click; // Das Programm kann auch manuell gesteuert werden. Deswegen dieses Ereignis für den automatischen Lauf
  end
  else
  begin
    Automatiklauf := False;
  end;
end;

Wenn der Anwendung also ein Parameter übergeben wird, läuft es automatisch:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
procedure TSDIAppForm.btnKomplettClick(Sender: TObject);
begin
  btnKomplett.Tag := 1// Wird die 1 gesetzt, gibt es keine Fertig-Meldung im Programm
  // START: Aufruf der einzelnen Methoden für den automatischen Ablauf
  btnCommand.Click;
  btnSourceEinlesen.Click;
  btnTargetEinlesen.Click;
  btnDatensicherung.Click;
  // ENDE 
  btnKomplett.Tag := 0// AufStandard zurück setzen
  if Automatiklauf then // Sollte eigentlich gesetzt sein, da das Programm sonst gar nichts machen würde.
    Application.Terminate; // Tja, und das wird offensichtlich nicht gemacht.
end;


Das Programm ist bis auf die Fertig-Meldung ohne Dialoge.
Hat jemand eine Idee, was falsch sein könnte?

Ergänzung:
Das ist der Source, der am Schluss in btnDatensicherung.Click ausgeführt wird:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
  if not Automatiklauf then
  begin
    frmProtokoll.ListBox1.Clear;
    frmProtokoll.ListBox1.Items.AddStrings(Protokoll);
    frmProtokoll.show;
  end
  else
  begin
    tmp := DateTimeToStr(now);
    tmp := StringReplace(tmp, '.''-', [rfReplaceAll]);
    tmp := StringReplace(tmp, ':''-', [rfReplaceAll]);
    Protokoll.SaveToFile(ExtractFilePath(ParamStr(0)) + tmp + '.pkl');
  end;

Das Protokoll wird definitiv erzeugt und ist wirklich der letzte Schritt vor dem Terminate.
Boldar
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 1555
Erhaltene Danke: 70

Win7 Enterprise 64bit, Win XP SP2
Turbo Delphi
BeitragVerfasst: Di 13.01.09 15:06 
Lass dir mal Automatiklauf ausgeben: Ist das wirklich auch wenn es vom Service gestartet wird, true?
Villeicht stimmt etwas mit den von der Batch übergebenen Parametern nicht, sodass es hier:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
  if ParamCount > 0 then
  begin
    Automatiklauf := True;
    SetzeFelder(ParamStr(1)); // Hier nimmt die Anwendung Einstellungen für den Ablauf vor
    btnKomplett.Click; // Das Programm kann auch manuell gesteuert werden. Deswegen dieses Ereignis für den automatischen Lauf
  end

sofort in den else-Zweig springt??
jasocul Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 6395
Erhaltene Danke: 149

Windows 7 + Windows 10
Sydney Prof + CE
BeitragVerfasst: Di 13.01.09 15:11 
Wäre es so, würde kein Protokoll erstellt werden.
Eigentlich würde dann gar nichts passieren, weil das Programm von sich aus nichts macht.
wdbee
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 628
Erhaltene Danke: 1



BeitragVerfasst: Di 13.01.09 16:02 
Hallo jasocul,

was mir auffällt:

Die ganze Verarbeitung inkl. Terminate erfolgt in .CreateForm.

Mach als schnellen Test mal folgendes:

Verschiebe die Verarbeitung in eine Funktion, die du verzögert starten kannst, indem du in CreateForm einen Timer mit kurzem Intervall startest (nicht vergessen, den Timer dass sofort wieder zu stoppen).

Dann bist du sicher, dass die gesamte Initialisierung auch wirklich abgeschlossen ist, wenn die Verarbeitung anläuft und Application.Terminate aufgerufen wird. Wenn ich das richtig verstanden habe, ist das ja genau der Unterschied zum manuellen Aufruf.

Gruß

wdbee
jasocul Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 6395
Erhaltene Danke: 149

Windows 7 + Windows 10
Sydney Prof + CE
BeitragVerfasst: Di 13.01.09 16:10 
Verdammt, du könntest Recht haben.
Danke für deinen Hinweis.
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10184
Erhaltene Danke: 1259

W11x64
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: Di 13.01.09 16:14 
Moin Peter!

Aber (sollte es damit zu tun haben) lass das mit dem Timer und schick dir eine Nachricht, in deren Handler du die Aktionen ausführst. :idea: ;)

cu
Narses

_________________
There are 10 types of people - those who understand binary and those who don´t.
jasocul Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 6395
Erhaltene Danke: 149

Windows 7 + Windows 10
Sydney Prof + CE
BeitragVerfasst: Di 13.01.09 16:20 
Habe ich auch vor.
Zum Testen komme ich aber erst morgen. Das Ergebnis wird natürlich geliefert.
jasocul Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 6395
Erhaltene Danke: 149

Windows 7 + Windows 10
Sydney Prof + CE
BeitragVerfasst: Mi 14.01.09 08:34 
Das war es nicht.
Jetzt weiß ich auch wieder, warum ich ein Terminate verwendet habe. Ein Close funktioniert nicht immer im FormCreate.

Alles sehr merkwürdig.
Bin für jede weitere Idee offen.
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10184
Erhaltene Danke: 1259

W11x64
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: Mi 14.01.09 11:44 
Moin!

user profile iconjasocul hat folgendes geschrieben Zum zitierten Posting springen:
Das war es nicht.
Jetzt weiß ich auch wieder, warum ich ein Terminate verwendet habe. Ein Close funktioniert nicht immer im FormCreate.
Poste dir doch mal ein WM_CLOSE, testweise. :nixweiss:

cu
Narses

_________________
There are 10 types of people - those who understand binary and those who don´t.
jasocul Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 6395
Erhaltene Danke: 149

Windows 7 + Windows 10
Sydney Prof + CE
BeitragVerfasst: Mi 14.01.09 12:29 
Ich lasse jetzt erstmal für jeden Schritt einen Protokoll-Eintrag erstellen.
Die Anwendung macht sogar noch NACH dem Application.Terminate im Testlauf (ohne Service) einen entsprechenden Eintrag ins Protokoll. Jetzt will ich das nochmal mit einem Application.ProcessMessages nach dem Terminate versuchen.

Sieht schon ziemlich verzweifelt aus. :?
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10184
Erhaltene Danke: 1259

W11x64
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: Mi 14.01.09 14:17 
Moin!

Ich erinnere mich düster, dass ich dabei auch schonmal Probleme hatte... :gruebel:

Setz mal hinter das APM ein Exit; Nutzt das was?

Bzw. hier eigentlich (also in der ersten Methode, die aus dem MessageLoop heraus aufgerufen wird:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
procedure TSDIAppForm.FormCreate(Sender: TObject);  
begin  
  if ParamCount > 0 then  
  begin  
    Automatiklauf := True;  
    SetzeFelder(ParamStr(1)); // Hier nimmt die Anwendung Einstellungen für den Ablauf vor  
    btnKomplett.Click; // Das Programm kann auch manuell gesteuert werden. Deswegen dieses Ereignis für den automatischen Lauf  
    Exit;
  end  
  else  
  begin  
    Automatiklauf := False;  
  end;  
end;

cu
Narses

_________________
There are 10 types of people - those who understand binary and those who don´t.
wdbee
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 628
Erhaltene Danke: 1



BeitragVerfasst: Mi 14.01.09 14:23 
Hallo jasocul,

ich weiß nicht genau, wie du dein Programm als Service startest, aber wenn du dein Formular direkt aus einem TService heraus verwendest klappt das so:

ausblenden volle Höhe Delphi-Quelltext
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:
procedure TServiceCloseDemo.ServiceCreate(Sender: TObject);
begin
  AddToLogfile('TServiceCloseDemo.ServiceCreate');
end;

procedure TServiceCloseDemo.ServiceDestroy(Sender: TObject);
begin
  AddToLogfile('TServiceCloseDemo.ServiceDestroy');
end;

// Working loop
procedure TServiceCloseDemo.ServiceExecute(Sender: TService);
begin
  AddToLogfile('>TServiceCloseDemo.ServiceExecute ...');

  if FormMain <> nil then
    FormMain.OnTerminateService := DoTerminateService;
    
  while not (Terminated or oTerminate) do
  begin
    AddToLogfile('> ... TServiceCloseDemo.ServiceExecute ...');
    Sleep(1000);
    ServiceThread.ProcessRequests(False);
  end;
  AddToLogfile('<... TServiceCloseDemo.ServiceExecute');
end;

// Terminate by Formular
procedure TServiceCloseDemo.DoTerminateService(Sender: TObject);
begin
  AddToLogfile('>TServiceCloseDemo.DoTerminateService ...');
  oTerminate := True;
  AddToLogfile('<... TServiceCloseDemo.DoTerminateService');
end;


Im Formular:

ausblenden Delphi-Quelltext
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:
procedure TFormMain.FormCreate(Sender: TObject);
begin
  AddToLocalLogfile('>FormCreate ...');

  // ...

  AddToLocalLogfile('>Timer started ...');
  TimerClose.Enabled := True;
  AddToLocalLogfile('<... Timer started');
  AddToLocalLogfile('<... FormCreate');
end;

procedure TFormMain.TimerCloseTimer(Sender: TObject);
begin
  TimerClose.Enabled := False;
  AddToLocalLogfile('>Timer ...');
  Close;
  AddToLocalLogfile('<... Timer');
end;

procedure TFormMain.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  AddToLocalLogfile('>FormClose ...');

  if Assigned(OnTerminateService) then
    OnTerminateService(self);

  AddToLocalLogfile('<... FormClose');
end;


Dabei kannst du Close per Timer (Bequem) oder per Message (umständlicher, da du dennoch für eine geeignete Verzögerung sorgen musst) aufrufen.
Als Ergebnis bekomme ich:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
2009.01.14 13:03:09:716 >TServiceCloseDemo.ServiceCreate<
2009.01.14 13:03:09:716 >>FormCreate ...<
2009.01.14 13:03:09:716 >>Timer started ...<
2009.01.14 13:03:09:716 ><... Timer started<
2009.01.14 13:03:09:732 ><... FormCreate<
2009.01.14 13:03:09:732 >TServiceCloseDemo.ServiceStart<
2009.01.14 13:03:09:732 >>TServiceCloseDemo.ServiceExecute ...<
2009.01.14 13:03:09:732 >> ... TServiceCloseDemo.ServiceExecute ...<
2009.01.14 13:03:10:732 >> ... TServiceCloseDemo.ServiceExecute ...<
2009.01.14 13:03:11:732 >> ... TServiceCloseDemo.ServiceExecute ...<
2009.01.14 13:03:12:716 >>Timer ...<
2009.01.14 13:03:12:716 >>FormClose ...<
2009.01.14 13:03:12:716 >>TServiceCloseDemo.DoTerminateService ...<
2009.01.14 13:03:12:716 ><... TServiceCloseDemo.DoTerminateService<
2009.01.14 13:03:12:716 ><... FormClose<
2009.01.14 13:03:12:716 ><... Timer<
2009.01.14 13:03:12:732 ><... TServiceCloseDemo.ServiceExecute<
2009.01.14 13:03:12:732 >TServiceCloseDemo.ServiceDestroy<


Ich mache das immer etwas anders:

1. Service.exe verwendet ServiceModul und das DataModulGlobal
2. Programm.exe verwendet TFormMain und das DataModulGlobal

Der servicespezifische (nicht interaktive) Teil ist im ServiceModul, der programmspezifische (interaktive) Teil im FormMain.
Alles was beide machen/verwenden sollen ist im DataModul. Damit bin ich auch sehr komplizierten Fällen immer gut gefahren.

Gruß

wdbee
jasocul Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 6395
Erhaltene Danke: 149

Windows 7 + Windows 10
Sydney Prof + CE
BeitragVerfasst: Mi 14.01.09 15:41 
Danke für eure Tipps.
Da habe ich ja erstmal was zu tun. Ich melde mich, sobald ich mit den Tests durch bin.
jasocul Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 6395
Erhaltene Danke: 149

Windows 7 + Windows 10
Sydney Prof + CE
BeitragVerfasst: Do 15.01.09 16:37 
Ich werde aaaaalt
:bawling:

Der Dienst lief mit dem System-Konto. Dieses hat aber auf anderen Servern (in diesem Fall ein NAS) keine passenden Rechte. Dadurch hat es wohl eine Exception gegeben und das Terminate wurde gar nicht erst aufgerufen. :roll:

Deswegen funktioniert es auch, wenn ich manuell starte. Dann bin ich Domänen-Admin.

:autsch: :autsch: :autsch: