![]() |
Warum kann ich keine Form im Execute-Rutine des TCP Createn
Hallo ich habe ein ProblemIch Will schreibe gerade ein Programm mit dem man Dateien über das Internet schicken kann doch sollen die dateien nicht sofort losgeschickt werden sondern der Benutzer soll bestätigen können ob er die Datei annehmen oder verweigern will.
Also ich schicke über Die Indy TCP einige Daten wie die IP , den UserNamen, Eine identifikationsNummer, die Dateinamen und die Gesammtgrösse der Dateien. Der TCP Server bekommt die Sachen und soll dann eine Form erstellen in die er dann alles einträgt und wo der Benutzer dann bestätigen kann. So hier der Quellcode der Procedure die der TCP Server Aufruft wenn er Eine Anfrage bekommt.
Code:
Rufe ich die Procedure mit einen Button auf funktionirt die wird die Procedure im Execute-Ereigniss des TCP Servers aufgerufen bekomme ich die Meldung "Leinwand/Bild erlaubt kein zeichnen".
procedure TfrmMain.GetFileFrom(User, IP, DMIN, Description, FileSize: String; Files: TStringList);
var TfGF: TfrmGetFile; begin If Application.FindComponent('GF' + DMIN) = Nil Then begin Application.CreateForm(TfrmGetFile, TfGF); TfGF.Name:='GF' + DMIN; TfGF.lblUserName.Caption := User; TfGF.TCP.Host := IP; TfGF.SetStatus('Online'); TfGF.lstboxFiles.Items.Assign(Files); TfGF.memDescription.Text:=Description; TfGF.lblFileSize.Caption:=FileSize; end else begin TfGF:=(Application.FindComponent('GF' + DMIN) As TfrmGetFile); TfGF.TCP.Host := IP; TfGF.SetStatus('Online'); TfGF.lstboxFiles.Items.Assign(Files); TfGF.memDescription.Text:=Description; TfGF.lblFileSize.Caption:=FileSize; TfGF.SetFocus; end; end; Was kann das Sein? Wie kann ich es machen das es funktioniert? |
Re: Warum kann ich keine Form im Execute-Rutine des TCP Crea
Hat denn keiner ne Idee? :cry: :?: :cry:
|
Re: Warum kann ich keine Form im Execute-Rutine des TCP Crea
Diese "wunderschöne Meldung" kenne ich auch ganz gut *g
Die tritt immer auf, wenn Dein OnExecute Code des Server's nicht Threads sicher ist. Also : Alles was VCL betrifft und nicht thread sicher ist mit syncronize aufrufen ! Ich habe gesehen das Du eine Form erzeugst, diese solltest Du nicht Modal machen. Ich hoffe das hat Dir schon mal geholfen, oder brauchst Du noch mehr Details ? Gruß Data |
Re: Warum kann ich keine Form im Execute-Rutine des TCP Crea
Also ich öffne die nicht modal.
Was ist denn zum Beispiel nicht Thread Sicher? :gruebel: Ein paar Details währen schon hilfreich. |
Re: Warum kann ich keine Form im Execute-Rutine des TCP Crea
Hi,
poste bitte mal Dein OnExecute des Servers !! Den von dort wirst Du doch GetFileFrom(User, IP, DMIN, Description, FileSize: String; Files: TStringList); aufrufen, oder ? Und da dieser Aufruf mit Parametern geschiet gehe ich davon aus das Du den Aufrug nicht syncronisierst. Gruß Data |
Re: Warum kann ich keine Form im Execute-Rutine des TCP Crea
So hier ist die OnExecute:
Code:
procedure TfrmMain.TCPServerExecute(AThread: TIdPeerThread);
var SessionID: Integer; procedure DoLog(const Msg: String); var S: String; I: Integer; begin S := Format('%s-%0.6d: %s', [FormatDateTime('YYMMDD HHNNSS ZZZ', Now), SessionID, Msg]); for I := 1 to Length(S) do if S[I] in [#10,#13] then S[I] := ' '; // da Memo1.Lines.Add() intern über SendMessage() arbeitet sollte dies Threadsafe sein. // Memo1.Lines.Add(S); end; function ReadByte: Byte; begin AThread.Connection.ReadBuffer(Result, SizeOf(Result)); end; function ReadLong: Cardinal; function SwapLong(Value: Cardinal): Cardinal; // konvertiert Big Endian zu Little Endian // im INet ist es üblich ALLE Daten in Big Endian zu übertragen asm BSWAP EAX end; begin AThread.Connection.ReadBuffer(Result, SizeOf(Result)); Result := SwapLong(Result); end; function ReadString: String; begin SetLength(Result, ReadByte); AThread.Connection.ReadBuffer(Result[1], Length(Result)); end; procedure WriteByte(Value: Byte); begin AThread.Connection.WriteBuffer(Value, SizeOf(Value)); end; procedure WriteString(const Value: ShortString); begin WriteByte(Length(Value)); AThread.Connection.WriteBuffer(Value[1], Length(Value)); end; var FileName: String; FileSize, MSGSize: Cardinal; FileStream: TStream; MSGStream: TStream; I, Accept: Integer; User, DMIN, IP: String; Files: TStringList; Description, SizeOfFiles: String; GetMSG, GetFileRequest, GetAnswerOfFileRequest, GetURL: Boolean; begin SessionID := LastSessionID; Inc(LastSessionID); GetMSG:=False; GetFileRequest:=False; GetAnswerOfFileRequest:=False; GetURL:=False; Accept:=0; try DoLog(Format('Client connect at IP ', [AThread.Connection.Socket.Binding.PeerIP])); if (ReadByte = 1) and (ReadString = 'MyUpload 1.0') then // LOGIN begin // Client hat sich korrekt identifiziert sende Bestätigung und warte auf Kommandos WriteByte(1); while True do case ReadByte of 0: begin // NULL WriteByte(0); end; 2: begin // LOGOUT DoLog('Client logout'); Break; end; 3: begin // ERROR DoLog(Format('Client error %d, %s', [ReadByte, ReadString])); Break; // Fehler fürht IMMER zum Abbau der Verbindung end; 4: begin // UPLOAD DMIN:=ReadString; User:=ReadString; IP:=ReadString; FileName := ExtractFilePath(ParamStr(0)) + 'Upload\' + ReadString; FileSize := ReadLong; DoLog(Format('Client upload %5d, %s', [FileSize, FileName])); try FileStream := TFileStream.Create(FileName, fmCreate); try AThread.Connection.ReadStream(FileStream, FileSize); finally FileStream.Free; end; WriteByte(4); except on E: Exception do begin WriteByte(3); // ERROR WriteByte(1); WriteString(E.Message); Break; end; end; end; 5: begin // MESSAGE DMIN:=ReadString; User:=ReadString; IP:=ReadString; MSGSize := ReadLong; try MSGStream := TMemoryStream.Create; try AThread.Connection.ReadStream(MSGStream, MSGSize); finally GetMSG:=True; end; WriteByte(5); except on E: Exception do begin WriteByte(3); // ERROR WriteByte(1); WriteString(E.Message); Break; end; end; end; 6: begin // URL DMIN:=ReadString; User:=ReadString; IP:=ReadString; ReadString; ReadString; GetURL:=True; WriteByte(6); end; 7: begin // ASK FOR UPLOAD DMIN:=ReadString; User:=ReadString; IP:=ReadString; try Files:=TStringList.Create; Files.Clear; try For I:=0 To ReadLong - 1 Do begin Files.Add(ReadString); end; Description:=ReadString; SizeOfFiles:=ReadString; finally GetFileRequest:=True; end; WriteByte(7); except on E: Exception do begin WriteByte(3); // ERROR WriteByte(1); WriteString(E.Message); Break; end; end; end; 8: begin // ACCEPT OR DISACCEPT THE UPLOAD DMIN:=ReadString; User:=ReadString; IP:=ReadString; Accept:=ReadByte; WriteByte(8); GetAnswerOfFileRequest:=True; end; 9: begin // STATUSCHECK DMIN:=ReadString; User:=ReadString; IP:=ReadString; WriteString(sStatus); WriteByte(9); end; else begin // Invalid Code; DoLog('Client sends unknown command, terminate'); WriteByte(3); WriteByte(0); // Errorcode WriteString('unknown kommand'); Sleep(1); Break; end; end; end; // falsches/fehlendens Client-Login, trenne einfach die Verbindung, Server ist im Stealth mode finally DoLog('Client terminated'); try Sleep(1); AThread.Connection.Disconnect; except end; end; If GetMSG Then begin ShowMessage(User, DMIN, IP, MSGStream); MSGStream.Free; end else If GetFileRequest Then begin GetFileFrom(User, IP, DMIN, Description, SizeOfFiles, Files); Files.Free; end else If GetAnswerOfFileRequest Then begin AcceptSendFile(User, DMIN, IP, Accept); end else If GetURL Then begin // end; end; |
Re: Warum kann ich keine Form im Execute-Rutine des TCP Crea
Hey DataCool hast du mich etwa vegessen? :( :cry: :cry: :cry:
|
Re: Warum kann ich keine Form im Execute-Rutine des TCP Crea
@Jonny:
Ja hab ich :oops: ! Viel Stress hier in der Firma, da bekommt man einen Tunnelblick :twisted: Dein Problem ist etwas schwierig zu erklären, es liegt auf jeden Fall am Multi-Threading !!! D.H. das jeder Befehlsaufruf der mit der VCL zu tun hat, syncronisiert aufgerufen werden muss !! Bsp.:
Code:
Wie Du sicherlich festgestellt hast, hat die Procedure updateMyForm keine Parameter und diese benötigst Du ja, deshalb kommt gleich noch ein zweites posting, mit der Lösung !
procedure updateMyForm;
begin form1.caption := 'Ich wurde syncronisiert ;-)'; end; // Im OnExecute des Servers folgendes begin // ... Dein Code ATHread.syncronize(updatemyForm); // ... Nochmehr Code :wink: end; Oder Du meldest Dich bei mir : TelWell-Nr.: 1011 oder icq : 23764631 Gruß Data |
Re: Warum kann ich keine Form im Execute-Rutine des TCP Crea
Hi John,
hier ist jetzt die Lösung, sorry nochmal für's warten. Ich habe jetzt eine Klasse zur Syncronisation erstellt, das ist meiner Meinung nach der einfachste Weg. Bei Fragen einfach melden :wink:
Code:
type
TSyncGetFileFrom = Class private fUser, fIP, fDMIN, fDescription, fFileSize: String; fFiles: TStringList; protected {} public Constructor Create; override; Destructor Destroy; override; property User : String read fUser write fUser; property IP : String read fIP write fIP; property DMin : String read fDMin write fDMin; property Description : String read fDescription write fDescription; property FileSize : String read fFileSize write fFileSize; property Files : TStringList read fFiles write fFiles; // call showForm with syncronize from a Thread procedure showForm; end; implementation // uses Unit wo TfrmGetFile definiert ist { TSyncGetFileFrom } constructor TSyncGetFileFrom.Create; begin inherited; fFiles := TSTringList.Create; end; destructor TSyncGetFileFrom.Destroy; begin FreeAndNil(fFiles); inherited; end; // look is extactly your code, but knoe syncronized procedure TSyncGetFileFrom.showForm; begin If Application.FindComponent('GF' + DMIN) = Nil Then begin Application.CreateForm(TfrmGetFile, TfGF); TfGF.Name:='GF' + DMIN; TfGF.lblUserName.Caption := User; TfGF.TCP.Host := IP; TfGF.SetStatus('Online'); TfGF.lstboxFiles.Items.Assign(Files); TfGF.memDescription.Text:=Description; TfGF.lblFileSize.Caption:=FileSize; end else begin TfGF:=(Application.FindComponent('GF' + DMIN) As TfrmGetFile); TfGF.TCP.Host := IP; TfGF.SetStatus('Online'); TfGF.lstboxFiles.Items.Assign(Files); TfGF.memDescription.Text:=Description; TfGF.lblFileSize.Caption:=FileSize; TfGF.SetFocus; end; end; // So und im OnExecute des Server rufst Du jetzt folgendes auf : Var mySyncForm : TSyncGetFileForm; begin // ... Code mySyncForm := TSyncGetFileForm.Create; mySyncForm.User := User; mySyncForm.IP := IP; mySyncForm.DMin := DMin; mySyncForm.DEscription := Description; mySyncForm.FileSize := SizeOfFiles; mySyncForm.Files.assign(Files); // use syncronize now aThread.syncronize(mySyncForm.showForm); // That's it end; |
Re: Warum kann ich keine Form im Execute-Rutine des TCP Crea
Das sieht ja kompeziert aus!
!!!!!!!!!!!!!Danke!!!!!!!!!!!!!!!!! werde es gleich mal ausprobieren. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 14:41 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