Autor Beitrag
tif
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 46
Erhaltene Danke: 1

Winxxx
TP, BP, Delphi 1 - 2009
BeitragVerfasst: Fr 05.03.10 09:23 
Hallo,

ich erzeuge in meiner Anwendung mehrere Threads, die ihrerseits ein Datenmodul beinhalten. In diesem Datenmodul erfolgt eine u.U. längerdauernde Verarbeitung.
Nun möchte ich von der Hauptapplikation aus bei Bedarf diese Verarbeitung(en) abbrechen. Damit das sauber im Datenmodul gehandlet wird, wollte ich nicht die Threads in einer Liste führen und dann per Terminate einzeln abschießen, sondern lieber dem Datenmodul freundlich mitteilen, dass es die Verarbeitung beenden soll.

Dazu möchte ich an alle Datenmodule einer bestimmten Klasse eine - nennen wir sie mal WM_CANCEL - Botschaft schicken.
Ich bekomme es aber nicht hin und frage deshalb hier um Rat.

Das habe ich:

Im Datenmodul

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:
35:
36:
37:
38:
39:
40:
41:
42:
43:
  Tdm_window = class(TDataModule)
    procedure DataModuleCreate(Sender: TObject);
    procedure DataModuleDestroy(Sender: TObject);
  private
    { Private-Deklarationen }
    handle:hwnd;

    procedure CreateCommunicationWindow;
    procedure CM_Cancel(var Msg:TMessage); message WM_CANCEL;
    procedure DestroyCommunicationWindow;

  public
    { Public-Deklarationen }
  end;

implementation

procedure Tdm_window.CreateCommunicationWindow;
var adr:Pointer;
begin
  handle := CreateWindowEx(0'STATIC', PChar(name), 0000000, hinstance, nil);
  adr:=MakeObjectInstance(CM_Cancel);
  SetWindowLong(handle, GWL_WNDPROC, LongInt(adr));
end;

procedure Tdm_window.DestroyCommunicationWindow;
begin
  destroywindow(handle);
end;

procedure Tdm_window.DataModuleCreate(Sender: TObject);
begin
  CreateCommunicationWindow;
end;

procedure Tdm_window.DataModuleDestroy(Sender: TObject);
begin
  DestroyCommunicationWindow;
end;
procedure Tdm_window.CM_Cancel(var Msg: TMessage);
begin
    showmessage('Abbruch');
end;



Und der Aufruf


ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
procedure TForm2.btn_1Click(Sender: TObject);
var hwnd:Integer;
begin
  HWND:=FindWindowEx(Application.Handle,0,'dm_window','');
  PostMessage(HWND,WM_CANCEL,0,0);
end;



Ich habe schon mit FindWindow / FindWindowEx alle möglichen Variationen durchprobiert, aber keine 'trifft' das Datenmodul.

Habt Ihr einen Lösungsansatz?

Danke
Tino


Moderiert von user profile iconNarses: Topic aus Sonstiges (Delphi) verschoben am Fr 05.03.2010 um 11:07
Xion
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
EE-Maler
Beiträge: 1952
Erhaltene Danke: 128

Windows XP
Delphi (2005, SmartInspect), SQL, Lua, Java (Eclipse), C++ (Visual Studio 2010, Qt Creator), Python (Blender), Prolog (SWIProlog), Haskell (ghci)
BeitragVerfasst: Mo 15.03.10 11:13 
user profile icontif hat folgendes geschrieben Zum zitierten Posting springen:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
procedure TForm2.btn_1Click(Sender: TObject);
var hwnd:Integer;
begin
  HWND:=FindWindowEx(Application.Handle,0,'dm_window','');
  PostMessage(HWND,WM_CANCEL,0,0);
end;

Probiers mal mit Tdm_window. Du musst dann aber in dem Stück, wo die arbeit gemacht wird, mit Application.ProcessMessages prüfen, ob messages da sind, das bremst die Arbeit durchaus, du kannst natürlich nur jede Sekunde prüfen, dann braucht das Programm ne Sekunde zum abbrechen, wäre wohl der beste Kompromiss.

Warum machst du nicht einfach ein array, wo du die Dinger rein"constructest":

ausblenden Delphi-Quelltext
1:
DataModules[0]:=Tdm_Window.DataModuleCreate(...);					

Den DataModuleCreate dann als Constructor deklarieren.

Dann kannst du einfach mit DataModules[0].CM_Cancel das gleiche erreichen wie so über die messages. (Oder nicht? :gruebel: )

_________________
a broken heart is like a broken window - it'll never heal
In einem gut regierten Land ist Armut eine Schande, in einem schlecht regierten Reichtum. (Konfuzius)
tif Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 46
Erhaltene Danke: 1

Winxxx
TP, BP, Delphi 1 - 2009
BeitragVerfasst: Mo 15.03.10 11:56 
Hallo,

vielen Dank für die Antwort!

Ja, dass bei FindWindow der Klassenname stehen muss, das hab' ich dann auch gemerkt, trotzdem danke für den Hinweis.
Trotzdem findet er das Fenster nicht - und schon gar nicht 'alle aktiven', wenn es mehrere Treads gibt.
Irgendwie kam ich mit FindWindow / FindWindowEX nicht weiter.

Ich habe es dann doch - wie vorgeschlagen - über eine globale Thread - Liste gemacht, war gar nicht so schlimm wie ich erst vermutet hatte:

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:
35:
36:
37:
38:
39:
40:
41:
interface

ThreadList : TThreadList;  // meine Liste   TThreadlist, damit Thread - sicher
Function ClearThreads : Boolean;  // alle Threads beenden


implementation

Function ClearThreads : Boolean;
var al: TList;
    i,cnt : Integer;
begin
  cnt:=0;

  while cnt < 10 do begin  // gib jedem 10 Sekunden zum sanften Beenden
    al:=ThreadList.LockList;
    try
      if al.Count = 0 then begin
        cnt:=11;        // keine mehr da, weg
        Result:=True;
      end else begin
        Inc(cnt);       // alle, die noch da sind, beenden
        for i := 0 to al.Count - 1 do
          if Assigned(al[i]) then
            TThread(al[i]).Terminate;
      end;
    finally
      ThreadList.UnlockList;
    end;
    if cnt < 11 then
      Sleep(1000);     // noch welche aktiv später nochmal probieren
  end;

end;

Initialization
  ThreadList:=TThreadList.Create; 
finalization
  ClearThreads;  // spätestens hier, kann natürlich auch woanders aufgeruden werden
  ThreadList.Free;
end.


Und im Thread / Datenmodul:

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:
35:
36:
37:
38:
39:
40:
type TExportThread = class(TThread)
     private
// ...
     protected

       procedure Execute; override;
     public
       constructor Create(Params:TExportParams); virtual;
       destructor Destroy; override;
     end;

Implementation

constructor TExportThread.Create(Params: TExportParams);
begin
// exportparams behandeln ....

  FreeOnTerminate:=True;
  with ThreadList.LockList do
  try
    add(self);
  finally
    ThreadList.UnlockList;
  end;

  inherited Create(false);
end;

destructor TExportThread.destroy;
begin

  with ThreadList.LockList do
  try
    remove(self);
  finally
    ThreadList.UnlockList;
  end;

  inherited;
end;


Schließlich bei der Verarbeitung im Thread terminated abfragen, wenn true -> Abruch

Also, Danke, viele Grüße und sorry, dass ich dies nicht schon längst gepostet habe!
Ich war ein wenig traurig, weil solang keine Reaktion erfolgt ist.

Tino
HelgeLange
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 735
Erhaltene Danke: 6

Windows 7
Delphi7 - Delphi XE
BeitragVerfasst: Mo 15.03.10 15:24 
wenn ich mich recht entsinne, haben zwar TForm und TDataModule gemeinsame Vorfahren, aber den Datenmodule fehlt wohl das Fensterhandle, da es ein unsichtbares Container-Module ist. Wahrscheinlich kriegt es nur im design-Mode ein Handle zugewiesen, damit man Komponenten reinlegen kann.

Hab leider aber gerade keine Zeit, da im Forms-code rumzusuchen.

_________________
"Ich bin bekannt für meine Ironie. Aber auf den Gedanken, im Hafen von New York eine Freiheitsstatue zu errichten, wäre selbst ich nicht gekommen." - George Bernhard Shaw
tif Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 46
Erhaltene Danke: 1

Winxxx
TP, BP, Delphi 1 - 2009
BeitragVerfasst: Mo 15.03.10 15:37 
Ja, das ist ein Teil ursprünglichen Problems.

Genau das soll das CreateCommunicationsWindow() aus meinem ersten Post für's Datenmodul 'nachrüsten'.
Der Code stammt sinngemäß aus der (VCL) Forms.pas.

Es wäre interessant zu wissen, ob das so richtig ist oder ob bereits hier der Fehler liegt, dass das Fenster per Findindow() nicht zu finden ist.

Danke
Tino
HelgeLange
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 735
Erhaltene Danke: 6

Windows 7
Delphi7 - Delphi XE
BeitragVerfasst: Di 16.03.10 16:00 
Dann nimm doch einfach ein Formular, statt eines Datenmodules. Das ist ja der unterschied. Oder richte Dir ein kleines fenster ein, hab leider keinen Beispiel code zur Hand, da ich meinen "richtigen" Delphi-Rechner noch in Caracas hab, ich aber jetzt in Kolumbien wohne... Falls Du bis ende April Zeit hast, kann ich dann ja mal schaun...

Ich weiss, dass ich es früher mal so gemacht hatte und es ging gut.

_________________
"Ich bin bekannt für meine Ironie. Aber auf den Gedanken, im Hafen von New York eine Freiheitsstatue zu errichten, wäre selbst ich nicht gekommen." - George Bernhard Shaw
tif Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 46
Erhaltene Danke: 1

Winxxx
TP, BP, Delphi 1 - 2009
BeitragVerfasst: Di 16.03.10 16:32 
Hallo,

danke für deine Antwort!

Bitte mach dir erstmal keine Mühe mehr, ich hab's inzwischen über eine Liste gelöst.

Ich möchte kein Formular verwenden, da diese Anwendung später auch als Dienst laufen soll - und ich damit die unit Forms nicht einbinden darf.

Wahrscheinlich ist bei mir aber schon das Konzept falsch: An einen Dienst Windows- Fensterbotschaften schicken zu wollen ist eventuell widersinnig.

Abgesehen davon, dass ich HIER eine Lösung habe, wäre es natürlich interessant, wie man ein unsichtbares Fenster erzeugt, findet und dann auch benachrichtigt.
Hier gibt es aber im www viele Beispiele, die ich erstmal anschauen muss. Dann gibt's ggf. noch konkretere Fragen.


Also, Danke und viele Grüße nach Übersee!

Tino
HelgeLange
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 735
Erhaltene Danke: 6

Windows 7
Delphi7 - Delphi XE
BeitragVerfasst: Mi 17.03.10 15:50 
Schau mal bei den ICS Komponenten (sind kostenlos und mit vollem Source), dort hab ich mal gesehen, dass die sich ein Fenster erzeugen, um sich selbst Nachrichten zu senden wegen irgendwelchen asynchronen Sachen.

_________________
"Ich bin bekannt für meine Ironie. Aber auf den Gedanken, im Hafen von New York eine Freiheitsstatue zu errichten, wäre selbst ich nicht gekommen." - George Bernhard Shaw