Entwickler-Ecke
Windows API - Windows Botschaft an ein Datenmodul senden
tif - Fr 05.03.10 09:23
Titel: Windows Botschaft an ein Datenmodul senden
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
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 handle:hwnd;
procedure CreateCommunicationWindow; procedure CM_Cancel(var Msg:TMessage); message WM_CANCEL; procedure DestroyCommunicationWindow;
public end;
implementation
procedure Tdm_window.CreateCommunicationWindow; var adr:Pointer; begin handle := CreateWindowEx(0, 'STATIC', PChar(name), 0, 0, 0, 0, 0, 0, 0, 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
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
Narses: Topic aus Sonstiges (Delphi) verschoben am Fr 05.03.2010 um 11:07
Xion - Mo 15.03.10 11:13
tif hat folgendes geschrieben : |
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":
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: )
tif - 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:
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; Function ClearThreads : Boolean;
implementation
Function ClearThreads : Boolean; var al: TList; i,cnt : Integer; begin cnt:=0;
while cnt < 10 do begin al:=ThreadList.LockList; try if al.Count = 0 then begin cnt:=11; Result:=True; end else begin Inc(cnt); 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); end;
end;
Initialization ThreadList:=TThreadList.Create; finalization ClearThreads; ThreadList.Free; end. |
Und im Thread / Datenmodul:
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
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 - 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.
tif - 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 - 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.
tif - 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 - 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.
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!