06. januar 2010 - 12:19Der er
2 kommentarer og 1 løsning
Named pipes mellem Delphi Win32 og C# managed code
jeg har brug for at sende ret store mængder data mellem et Delphi program og et C# program. Jeg har valgt at forsøge at benytte named pipes. Jeg kan få det til at virke mellem C# og C#, både .Net 3.5 (med indbygget pipes) og før version 3.5 (med en class, se nedenstående link), og mellem Delphi og Delphi. Men mellem C# og Delphi virker det ikke.
Er der nogen der har erfaringer med problematikken?
Hej! Jeg får ingen fejl, min server crasher og windows giver dialogne "xxx has stopped working...Check online, close, debug"
Jeg kan connecte, og serveren reagerer, men længden på message er altid zero, og når jeg trykker OK i showmessage('com') så crasher Delphi exe'en.
Client.cs:
using System; using System.Collections.Generic; using System.Text; using System.Runtime.InteropServices; using Microsoft.Win32.SafeHandles; using System.Threading; using System.IO;
public bool Connected { get { return this.connected; } }
public string PipeName { get { return this.pipeName; } set { this.pipeName = value; } }
/// <summary> /// Connects to the server /// </summary> public void Connect() { this.handle = CreateFile( this.pipeName, GENERIC_READ | GENERIC_WRITE, 0, IntPtr.Zero, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, IntPtr.Zero);
//could not create handle - server probably not running if (this.handle.IsInvalid) return;
this.connected = true;
//start listening for messages this.readThread = new Thread(new ThreadStart(Read)); this.readThread.Start(); }
/// <summary> /// Reads data from the server /// </summary> public void Read() { this.stream = new FileStream(this.handle, FileAccess.ReadWrite, BUFFER_SIZE, true); byte[] readBuffer = new byte[BUFFER_SIZE]; ASCIIEncoding encoder = new ASCIIEncoding(); while (true) { int bytesRead = 0;
//server has disconnected if (bytesRead == 0) break;
//fire message received event if (this.MessageReceived != null) this.MessageReceived(encoder.GetString(readBuffer, 0, bytesRead)); }
//clean up resource this.stream.Close(); this.handle.Close(); }
/// <summary> /// Sends a message to the server /// </summary> /// <param name="message"></param> public void SendMessage(string message) { ASCIIEncoding encoder = new ASCIIEncoding(); byte[] messageBuffer = encoder.GetBytes(message);
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms;
namespace PipeClient { public partial class Form1 : Form { private Client pipeClient;
public Form1() { InitializeComponent(); this.pipeClient = new Client(); this.pipeClient.MessageReceived += new Client.MessageReceivedHandler(pipeClient_MessageReceived); }
constructor TPipeServer.CreatePipeServer( aServer, aPipe: String; StartServer: Boolean ); begin if aServer = '' then FPipeName := Format(cPipeFormat, ['.', aPipe]) else FPipeName := Format(cPipeFormat, [aServer, aPipe]); // clear server handle FHandle := INVALID_HANDLE_VALUE; if StartServer then StartUpServer; // create the class Create(not StartServer); end;
destructor TPipeServer.Destroy; begin if FHandle <> INVALID_HANDLE_VALUE then // must shut down the server first ShutDownServer; inherited Destroy; end;
procedure TPipeServer.Execute; var I, Written: Cardinal; InMsg, OutMsg: RPIPEMessage; begin while not Terminated do begin if FHandle = INVALID_HANDLE_VALUE then begin // suspend thread for 250 milliseconds and try again Sleep(250); end else begin if ConnectNamedPipe(FHandle, nil) then try // read data from pipe InMsg.Size := SizeOf(InMsg); ReadFile(FHandle, InMsg, InMsg.Size, InMsg.Size, nil); if (InMsg.Kind = 0) and (StrPas(InMsg.Data) = cShutDownMsg + FPipeName) then begin // process shut down OutMsg.Kind := 0; OutMsg.Count := 3; OutMsg.Data := 'OK'#0; Terminate; end else begin // data send to pipe should be processed here OutMsg := InMsg; frmNamedPipe_server.Memo1.Lines.Add('Command: '+{StrPas(InMsg.Data)+}' length: '+intToStr(InMsg.Count)); // we'll just reverse the data sent, byte-by-byte for I := 0 to Pred(InMsg.Count) do OutMsg.Data[Pred(InMsg.Count) - I] := InMsg.Data[I]; end; showmessage('COM'); CalcMsgSize(OutMsg); WriteFile(FHandle, OutMsg, OutMsg.Size, Written, nil); frmNamedPipe_server.Memo1.Lines.Add('Result: '+StrPas(OutMsg.Data)); finally DisconnectNamedPipe(FHandle); end; end; end; end;
procedure TPipeServer.ShutDownServer; var BytesRead: Cardinal; OutMsg, InMsg: RPIPEMessage; ShutDownMsg: String; begin if FHandle <> INVALID_HANDLE_VALUE then begin // server still has pipe opened OutMsg.Size := SizeOf(OutMsg); // prepare shut down message with InMsg do begin Kind := 0; ShutDownMsg := cShutDownMsg + FPipeName; Count := Succ(Length(ShutDownMsg)); StrPCopy(Data, ShutDownMsg); end; CalcMsgSize(InMsg); // send shut down message CallNamedPipe( PChar(FPipeName), @InMsg, InMsg.Size, @OutMsg, OutMsg.Size, BytesRead, 100 ); // close pipe on server CloseHandle(FHandle); // clear handle FHandle := INVALID_HANDLE_VALUE; end; end;
procedure TPipeServer.StartUpServer; begin // check whether pipe does exist if WaitNamedPipe(PChar(FPipeName), 100 {ms}) then raise Exception.Create('Requested PIPE exists already.'); // create the pipe FHandle := CreateNamedPipe( PChar(FPipeName), PIPE_ACCESS_DUPLEX, {PIPE_TYPE_MESSAGE or PIPE_READMODE_MESSAGE or PIPE_WAIT} 0, PIPE_UNLIMITED_INSTANCES, SizeOf(RPIPEMessage), SizeOf(RPIPEMessage), NMPWAIT_USE_DEFAULT_WAIT, nil ); // check if pipe was created if FHandle = INVALID_HANDLE_VALUE then raise Exception.Create('Could not create PIPE.'); end;
procedure TfrmNamedPipe_server.FormCreate(Sender: TObject); begin try FServer:=TPipeServer.CreatePipeServer('', 'testpipe', True); except on E: Exception do begin ShowMessage(E.Message); end; end end;
Fandt en løsning ved i et andet eksempel. Det var FILE_FLAG_OVERLAPPED der manglede i createNamedPipe. Lukker.
Synes godt om
Ny brugerNybegynder
Din løsning...
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.