{ This file is part of the Free Component library. Copyright (c) 2007 by Tomas Hajny, member of the Free Pascal development team OS/2 implementation of one-way IPC between 2 processes See the file COPYING.FPC, included in this distribution, for details about the copyright. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. **********************************************************************} uses DosCalls, OS2Def; ResourceString SErrFailedToCreatePipe = 'Failed to create named pipe: %s'; SErrFailedToDisconnectPipe = 'Failed to disconnect named pipe: %s'; const (* Constant used as key identifying a pipe connected to event semaphore. *) (* 'FP' *) PipeKey = $4650; PipeBufSize = 256; { --------------------------------------------------------------------- TPipeClientComm ---------------------------------------------------------------------} Type TPipeClientComm = Class(TIPCClientComm) Private FFileName: String; FStream: TFileStream; Public Constructor Create(AOWner : TSimpleIPCClient); override; Procedure Connect; override; Procedure Disconnect; override; Procedure SendMessage(MsgType : TMessageType; AStream : TStream); override; Function ServerRunning : Boolean; override; Property FileName : String Read FFileName; Property Stream : TFileStream Read FStream; end; constructor TPipeClientComm.Create (AOWner: TSimpleIPCClient); begin inherited Create (AOWner); FFileName:= '\PIPE\' + Owner.ServerID; If (Owner.ServerInstance <> '') then FFileName := FFileName + '.' + Owner.ServerInstance; end; procedure TPipeClientComm.Connect; begin try FStream := TFileStream.Create (FFileName, fmOpenWrite); finally Owner.DoError (SErrServerNotActive, [Owner.ServerID]); end; end; procedure TPipeClientComm.Disconnect; begin FreeAndNil (FStream); end; procedure TPipeClientComm.SendMessage (MsgType: TMessageType; AStream: TStream); var Hdr: TMsgHeader; begin Hdr.Version := MsgVersion; Hdr.MsgType := MsgType; Hdr.MsgLen := AStream.Size; FStream.WriteBuffer (Hdr, SizeOf (Hdr)); FStream.CopyFrom (AStream, 0); end; function TPipeClientComm.ServerRunning: boolean; begin {$WARNING Fake TPipeClientComm.ServerRunning - no safe solution known} Result := true; end; { --------------------------------------------------------------------- TPipeServerComm ---------------------------------------------------------------------} type TPipeServerComm = class (TIPCServerComm) private FFileName: string; FStream: THandleStream; EventSem: THandle; SemName: string; public constructor Create (AOWner: TSimpleIPCServer); override; procedure StartServer; override; procedure StopServer; override; function PeekMessage (TimeOut: integer): boolean; override; procedure ReadMessage; override; function GetInstanceID: string; override; property FileName: string read FFileName; property Stream: THandleStream read FStream; end; constructor TPipeServerComm.Create (AOWner: TSimpleIPCServer); begin inherited Create (AOWner); FFileName := '\PIPE\' + Owner.ServerID; SemName := '\SEM32\PIPE\' + Owner.ServerID; If not Owner.Global then FFileName := FFileName + '.' + IntToStr (GetProcessID); end; procedure TPipeServerComm.StartServer; var H: THandle; begin if not (Assigned (FStream)) then if (DosCreateNPipe (PChar (FFileName), H, np_Access_Inbound, np_ReadMode_Message or np_WriteMode_Message or 1, PipeBufSize, PipeBufSize, 0) <> 0) or (DosCreateEventSem (PChar (SemName), EventSem, 0, 0) <> 0) or (DosSetNPipeSem (H, EventSem, PipeKey) <> 0) or (DosConnectNPipe (H) <> 0) then Owner.DoError (SErrFailedToCreatePipe, [FFileName]); FStream := THandleStream.Create (H); end; procedure TPipeServerComm.StopServer; begin if (DosDisconnectNPipe (FStream.Handle) <> 0) or (DosCloseEventSem (EventSem) <> 0) then Owner.DoError (SErrFailedToDisconnectPipe, [FFileName]); FreeAndNil (FStream); end; function TPipeServerComm.PeekMessage (TimeOut: integer): boolean; var PipeSemState: TPipeSemState; begin Result := (DosQueryNPipeSemState (EventSem, PipeSemState, SizeOf (PipeSemState)) = 0) and (PipeSemState.Status = 1) and (PipeSemState.Avail <> 0) and (PipeSemState.Key = PipeKey); if not (Result) then Result := (DosWaitEventSem (EventSem, TimeOut) = 0) and (DosQueryNPipeSemState (EventSem, PipeSemState, SizeOf (PipeSemState)) = 0) and (PipeSemState.Status = 1) and (PipeSemState.Avail <> 0) and (PipeSemState.Key = PipeKey); end; procedure TPipeServerComm.ReadMessage; var Hdr: TMsgHeader; begin FStream.ReadBuffer (Hdr, SizeOf (Hdr)); Owner.FMsgType := Hdr.MsgType; if Hdr.MsgLen > 0 then begin Owner.FMsgData.Seek (0, soFromBeginning); Owner.FMsgData.CopyFrom (FStream, Hdr.MsgLen); end else Owner.FMsgData.Size := 0; end; function TPipeServerComm.GetInstanceID: string; begin Result := IntToStr (GetProcessID); end; { --------------------------------------------------------------------- Set TSimpleIPCClient / TSimpleIPCServer defaults. ---------------------------------------------------------------------} function TSimpleIPCServer.CommClass: TIPCServerCommClass; begin if (DefaultIPCServerClass <> nil) then Result := DefaultIPCServerClass else Result := TPipeServerComm; end; function TSimpleIPCClient.CommClass: TIPCClientCommClass; begin if (DefaultIPCClientClass <> nil) then Result := DefaultIPCClientClass else Result := TPipeClientComm; end;