![]() |
eigenes Event programmieren?
Hi und sorry, dass ich schon wieder einen neuen Thread auf machen...ist erstmal der letzte, versprochen.
Folgendes: Ich habe eine Unit programmiert, welche für mich per Indy Dateien verschickt und empfängt. Hierbei sage ich einfach meiner Unit, welcher filestream verschickt werden soll und an welche IP. Um den rest (Server und Client verwaltung etc) kümmert sich dann die Unit. In dieser Unit benutzte ich den IDTCPServer. Der hat ein Event "OnExecute" das ja genau dann aufgerufen wird, wenn Daten "ankommen" also eine clientverbindung besteht. Jetzt stellt euch folgendes vor: Die Daten werden von der Unit empfangen. D.h. ich jetzt jetzt da in irgendeiner form z.B. in einem Memorystream die Daten vorliegen, will sie jetzt aber von der Unit in mein Hauptprogramm übergeben. Will die Unit selber aber so allgemein halten, dass ich nicht irgendwie das Hauptprogramm damit verwebe... Daher hatte ich mit gedacht, es wäre sinnvoll so eine Art weiteres OnEvent zu haben, sodass man im Hauptprogramm z.B. eine OnDATARECEIVED Procedur schreiben kann, welche als Parameter den Memorystream an das Hauptprogramm übergibt... Ich hoffe ihr wisst, was ich meine?! ;) Habe die Suche bemüht, aber nichts gefunden was wirklich zu diesem Problem passt?! Vorsichtshalber schicke ich euch nochmal den sourcecode mit
Delphi-Quellcode:
unit LANFS_KERNAL; interface uses SysUtils, Classes, IdBaseComponent,IdStreamVCL, IdComponent, IdTCPServer,IdTCPConnection,IdTCPClient,IdContext; type TLANFS_KERNAL = class public procedure ReceiveStream(Acontext:TidContext); procedure Start(port:integer); procedure Stop(); procedure SendStream(Stream: TFilestream;Host:String); end; var LANFS_SYSTEM :TLANFS_KERNAL; TCPClient1: TIdTCPClient; TCPServer1: TIdTCPServer; implementation procedure TLANFS_KERNAL.Start(port:integer); { +Aktiviert TCPClient und TCPServer +Sollte immer am Start des Programms aufgerufen werden. +zuletzt editiert: 24.05.06 } begin TCPClient1:= TIdTCPClient.Create; TCPClient1.Port:=Port; with TCPClient1 do begin ReadTimeout:=5000; ConnectTimeout:=5000; end; TCPServer1:= TIdTCPServer.Create; TCPServer1.OnExecute := LANFS_SYSTEM.ReceiveStream; with TCPServer1 do begin MaxConnections:=1; DefaultPort:=Port; Active:=True; end; end; procedure TLANFS_KERNAL.Stop(); {Stopt Server und Client, gibt Speicher frei. zuletzt editiert: 24.06.05} begin TCPClient1.Free; TCPServer1.Active:=False; TCPServer1.Free; end; procedure TLANFS_KERNAL.SendStream(Stream: TFilestream;Host:String); { +Versendet vom TCPClient an TCPServer einen Filestream +Dieser wird als Parameter übergeben, und muss vorher erzeugt worden sein. +zuletzt editiert: 24.05.06 } var IndyStream: TidStreamVCL; begin TCPClient1.Host:=Host; try IndyStream := TidStreamVCL.Create(Stream); try { Senden } with TCPClient1 do begin Connect; try Socket.Write(IndyStream, 0, true); finally Disconnect; end; end; finally FreeAndNil(IndyStream); end; finally FreeAndNil(Stream); end; end; procedure TLANFS_KERNAL.ReceiveStream(Acontext:TidContext); { +Empfängt vom TCPClient an TCPServer einen Filestream +zuletzt editiert: 25.05.06 } var FSTream: TFileStream; SizeOfIncomingStream: Integer; IDS: TidStreamVCL; begin FStream := TFileStream.Create('C:\test.tmp', fmCreate); //Hier soll der Filestream nicht mehr als try //Datei gespeichert werden, sondern an das IDS := TidStreamVCL.Create(FStream); //Hauptprogramm übergeben werden! try { Empfangen } with AContext.connection do begin try SizeOfIncomingStream := Socket.ReadInteger; Socket.ReadStream(IDS, SizeOfIncomingStream); finally Disconnect; end; end; { Damit der Inhalt von IDS in FStream übertragen wird } IDS.VCLStream.Position := 0; finally FreeAndNil(IDS); end; finally FreeAndNil(FStream); end; end; end. |
Re: eigenes Event programmieren?
ein Event wird wie folgt defniert:
Delphi-Quellcode:
Anstelle eines eigenen EventTypes kannst du natürlich auch bereits vorhandene wie TNotifyEvent etc. nutzen wenn dir diese von den Parametern her zusagen.
type
TNameDeinesEventTypes = procedure(Sender: TObject; AParameterXYZ: String) of Object; TDeineKlasse = class(TIrgendwas) [...] fDeinEvent: TNameDeinesEventTypes; [...] property OnDeinEvent: TNameDeinesEventTypes read fDeinEvent write fDeinEvent; [...] end; implementation [...] procedure TDeineKlasse.LoeseEventAus(MitZuGebenderParameter); begin if Assigned(fDeinEvent) then fDeinEvent(Self, MitZuGebenderParameter); end; |
Re: eigenes Event programmieren?
Vielen Dank, ich habe es mal soweit eingebaut.
Allerdings gibts leider eine exception, wenn ich im Hauptprogramm diese zuweisung mache: (Sorry, da ich mich mit diesem Teil von Delphi nicht auskenne, mute ich euch hier etwas viel zu...)
Delphi-Quellcode:
Das ganze sieht jetzt so aus:
lanfs_system.OnReceivedData:= Form2.test;
Delphi-Quellcode:
Liebe Grüße und VIELEN VIELEN DANK schonmal!!!!!!
unit LANFS_KERNAL;
interface uses SysUtils, Classes, IdBaseComponent,IdStreamVCL, IdComponent, IdTCPServer,IdTCPConnection,IdTCPClient,IdContext; type TRECEIVEDDATA = procedure(Sender: TObject; MemStream: TMemoryStream) of Object; TLANFS_KERNAL = class fReceivedData: TRECEIVEDDATA; public procedure ReceiveStream(Acontext:TidContext); procedure Start(port:integer); procedure Stop(); procedure SendStream(Stream: TFilestream;Host:String); property OnReceivedData: TRECEIVEDDATA read fReceivedData write fReceivedData; end; var LANFS_SYSTEM :TLANFS_KERNAL; TCPClient1: TIdTCPClient; TCPServer1: TIdTCPServer; implementation procedure TLANFS_KERNAL.Start(port:integer); { +Aktiviert TCPClient und TCPServer +Sollte immer am Start des Programms aufgerufen werden. +zuletzt editiert: 24.05.06 } begin TCPClient1:= TIdTCPClient.Create; TCPClient1.Port:=Port; with TCPClient1 do begin ReadTimeout:=5000; ConnectTimeout:=5000; end; TCPServer1:= TIdTCPServer.Create; TCPServer1.OnExecute := LANFS_SYSTEM.ReceiveStream; with TCPServer1 do begin MaxConnections:=1; DefaultPort:=Port; Active:=True; end; end; procedure TLANFS_KERNAL.Stop(); {Stopt Server und Client, gibt Speicher frei. zuletzt editiert: 24.06.05} begin TCPClient1.Free; TCPServer1.Active:=False; TCPServer1.Free; end; procedure TLANFS_KERNAL.SendStream(Stream: TFilestream;Host:String); { +Versendet vom TCPClient an TCPServer einen Filestream +Dieser wird als Parameter übergeben, und muss vorher erzeugt worden sein. +zuletzt editiert: 24.05.06 } var IndyStream: TidStreamVCL; begin TCPClient1.Host:=Host; try IndyStream := TidStreamVCL.Create(Stream); try { Senden } with TCPClient1 do begin Connect; try Socket.Write(IndyStream, 0, true); finally Disconnect; end; end; finally FreeAndNil(IndyStream); end; finally FreeAndNil(Stream); end; end; procedure TLANFS_KERNAL.ReceiveStream(Acontext:TidContext); { +Empfängt vom TCPClient an TCPServer einen Filestream +zuletzt editiert: 25.05.06 } var FSTream: TMemoryStream; SizeOfIncomingStream: Integer; IDS: TidStreamVCL; begin FStream := TMemoryStream.Create; // FStream := TFileStream.Create('C:\test.tmp', fmCreate); try IDS := TidStreamVCL.Create(FStream); try { Empfangen } with AContext.connection do begin try SizeOfIncomingStream := Socket.ReadInteger; Socket.ReadStream(IDS, SizeOfIncomingStream); finally Disconnect; end; end; { Damit der Inhalt von IDS in FStream übertragen wird } IDS.VCLStream.Position := 0; finally FreeAndNil(IDS); end; finally {Event losschicken} if Assigned(fReceivedData) then fReceivedData(Self, FStream); FreeAndNil(FStream); end; end; end. //edit ich den Fehler, den xaromz gefunden hat, mal fix korrigiert, damit er keine Verwirrungen mehr macht! THX to xaromz |
Re: eigenes Event programmieren?
Hallo,
Du zerstörst den Stream (Zeile 130) und schickst dann den nil-Pointer an Deine Event-Methode. Vielleicht ist das das Problem. Ansonsten wäre es hilfreich, zu wissen, welche Exception kommt. Gruß xaromz |
Re: eigenes Event programmieren?
Uuuuuppps...okay, sau dummer Fehler, gebe ich zu....
Allerdings ist das nicht der Fehler den ich meine... Es kommt folgende Exception: EAccessViolation, und zwar genau dann wenn ich im Hauptprogramm dem neuen Event eine Procedur zuweisen will. Die Hauptprocedur sieht so aus:
Delphi-Quellcode:
unit Unit2;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, IdTCPServer; type TForm2 = class(TForm) [...] private { Private-Deklarationen } public procedure test(Sender: TObject; MStream: TMemoryStream); { Public-Deklarationen } end; var Form2: TForm2; implementation uses LANFS_KERNAL; {$R *.dfm} procedure TForm2.test(Sender: TObject; MStream: TMemoryStream); begin MStream.SaveToFile('C:\neuertest.tmp'); end; procedure TForm2.FormCreate(Sender: TObject); begin lanfs_system.OnReceivedData:= Form2.test; //hier passiert der Fehler!!! end; procedure TForm2.Button1Click(Sender: TObject); var stream:TFilestream; begin stream:=TFileStream.Create(edit1.text, fmOpenRead); lanfs_system.SendStream(stream,edit2.text); end; [...] end. |
Re: eigenes Event programmieren?
Zitat:
Gruß Hawkeye |
Re: eigenes Event programmieren?
Zitat:
Jedenfalls kann ich auf lanfs_system zugreifen, *g* oder was meinst du genau mit Instanz ;) Ich muss doch jedenfalls kein .create mehr aufrufen?! |
Re: eigenes Event programmieren?
Das ist nicht ganz richtig, eine Unit wird nicht "erzeugt". Das was du meinst, gilt nur für Formulare. In Beitrag #3 hast du TLANFS_KERNAL als "Class" vereinbart, es handelt sich also nicht um ein Formular. In diesem Falls mußt du das Objekt erzeugen und auch wieder freigeben.
Gruß Hawkeye |
Re: eigenes Event programmieren?
desweiteren solltest du folgende Zeile abändern von:
Delphi-Quellcode:
nach
lanfs_system.OnReceivedData:= Form2.test;
Delphi-Quellcode:
lanfs_system.OnReceivedData:= test;
|
Re: eigenes Event programmieren?
Danke für die kleine Nachhilfekunde in sachen Classen und Units!
Was ich dann nur nicht so ganz verstehe... Im LANFS_KERNAL hab ich doch folgendes deklariert unter VAR: var LANFS_SYSTEM :TLANFS_KERNAL; auf Lanfs_system kann ich ohne create zugreifen, also auch auf die Proceduren in lanfs_system. Das OnReceiveData ist doch genau da deklariert wo auch die Proceduren deklariert sind, die in lanfs_system funktionieren....
Delphi-Quellcode:
Warum kann ich dann also auf die Proceduren Start, ReceiveStream, Stop SendStream zugreifen aber nicht auf das OnReceived Data?
unit LANFS_KERNAL;
interface uses [...] type TRECEIVEDDATA = procedure(Sender: TObject; MemStream: TMemoryStream) of Object; TLANFS_KERNAL = class fReceivedData: TRECEIVEDDATA; public procedure ReceiveStream(Acontext:TidContext); procedure Start(port:integer); procedure Stop(); procedure SendStream(Stream: TFilestream;Host:String); property OnReceivedData: TRECEIVEDDATA read fReceivedData write fReceivedData; //nämlich genau hier end; var LANFS_SYSTEM :TLANFS_KERNAL; TCPClient1: TIdTCPClient; TCPServer1: TIdTCPServer; Würdest du eigentlich generell sagen, dass die Unit so ziemlich unstrukuriert etc ist? //edit: Ich meine wäre es vielleicht sinnvoller einfahch alles in eine Klasse zu schreiben ohne Unit? *keine ahnung hab* |
Re: eigenes Event programmieren?
Luckie hat zum Thema Klassen ein
![]() Gruß Hawkeye |
Re: eigenes Event programmieren?
Hey, danke, jetzt hab ichs hinbekommen ;)
Das einzige, was ich jetzt noch "unschön" finde, ist dass ich überhaupt das LANFS_SYSTEM in LANFS_KERNAL erzeugen muss...somit erzeuge ich ja praktisch in meiner Unit in der ich die Klasse definiert habe schon eine Variable mit dieser Klasse....öhm oder so... aber das geht wohl nicht anders oder? Schließlich muss ich das TCPServer1.OnExecute ereignis zuweisen und das kann ich nur an LANFS_SYSTEM.ReceiveStream zuweisen und eben nicht an "TLANFS_KERNAL"... naja...THX Hawkeye219 du hast mir sehr geholfen soweit //edit...juhu, dafür nochmal zurück zum eigentlichen Problem: Jetzt erzeugt dieser Code hier eine Exception:
Delphi-Quellcode:
(wieder eine AccessViolation)...ich hab das doch richtig verstanden, diese 2 zeilen lösen das Event aus, richtig?
if Assigned(fReceivedData) then
fReceivedData(Self, FStream); |
Re: eigenes Event programmieren?
Kann es sein, dass ich durch das neue Event einen neuen Thread ausführe und der erst synchronisiert werden muss?
|
Re: eigenes Event programmieren?
Ok, hier einige Vorschläge:
Ändere deine Unit LANFS_KERNAL folgendermaßen ab:
Delphi-Quellcode:
Zum Freigeben der Instanz benötigst du noch die Methode FormDestroy, die du auf die gleiche Weise wie FormCreate erstellen kannst. Sie sollte so aussehen:
procedure TForm2.FormCreate(Sender: TObject);
begin lanfs_system := TLANFS_KERNAL.Create; lanfs_system.OnReceivedData := Form2.test; // hier passiert nun kein Fehler mehr :-) end;
Delphi-Quellcode:
Versuche es einmal mit diesen Änderungen. Sollten noch Fehler auftreten, meldest du dich wieder.
procedure TForm2.FormDestroy(Sender: TObject);
begin lanfs_system.Free; end; Gruß Hawkeye |
Re: eigenes Event programmieren?
Juhu, es klappt! 99999999999999999999999999mal dankeschön, Hawkeye219!!!!!!!
Ich werde hier hoch und heilig versprechen, mich mehr mit Classen und Unit Deklarationen zu beschäftigen! Danke, Danke, Danke! Du hast was gut bei mir :D Liebe Grüße, Alleinherrscher |
Alle Zeitangaben in WEZ +1. Es ist jetzt 04:09 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz