simpleipc.inc 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. {
  2. This file is part of the Free Component library.
  3. Copyright (c) 2007 by Tomas Hajny, member of
  4. the Free Pascal development team
  5. OS/2 implementation of one-way IPC between 2 processes
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. uses DosCalls, OS2Def;
  13. ResourceString
  14. SErrFailedToCreatePipe = 'Failed to create named pipe: %s';
  15. SErrFailedToDisconnectPipe = 'Failed to disconnect named pipe: %s';
  16. const
  17. (* Constant used as key identifying a pipe connected to event semaphore. *)
  18. (* 'FP' *)
  19. PipeKey = $4650;
  20. PipeBufSize = 256;
  21. { ---------------------------------------------------------------------
  22. TPipeClientComm
  23. ---------------------------------------------------------------------}
  24. Type
  25. TPipeClientComm = Class(TIPCClientComm)
  26. Private
  27. FFileName: String;
  28. FStream: TFileStream;
  29. Public
  30. Constructor Create(AOWner : TSimpleIPCClient); override;
  31. Procedure Connect; override;
  32. Procedure Disconnect; override;
  33. Procedure SendMessage(MsgType : TMessageType; AStream : TStream); override;
  34. Function ServerRunning : Boolean; override;
  35. Property FileName : String Read FFileName;
  36. Property Stream : TFileStream Read FStream;
  37. end;
  38. constructor TPipeClientComm.Create (AOWner: TSimpleIPCClient);
  39. begin
  40. inherited Create (AOWner);
  41. FFileName:= '\PIPE\' + Owner.ServerID;
  42. If (Owner.ServerInstance <> '') then
  43. FFileName := FFileName + '.' + Owner.ServerInstance;
  44. end;
  45. procedure TPipeClientComm.Connect;
  46. begin
  47. try
  48. FStream := TFileStream.Create (FFileName, fmOpenWrite);
  49. finally
  50. Owner.DoError (SErrServerNotActive, [Owner.ServerID]);
  51. end;
  52. end;
  53. procedure TPipeClientComm.Disconnect;
  54. begin
  55. FreeAndNil (FStream);
  56. end;
  57. procedure TPipeClientComm.SendMessage (MsgType: TMessageType; AStream: TStream);
  58. var
  59. Hdr: TMsgHeader;
  60. begin
  61. Hdr.Version := MsgVersion;
  62. Hdr.MsgType := MsgType;
  63. Hdr.MsgLen := AStream.Size;
  64. FStream.WriteBuffer (Hdr, SizeOf (Hdr));
  65. FStream.CopyFrom (AStream, 0);
  66. end;
  67. function TPipeClientComm.ServerRunning: boolean;
  68. begin
  69. {$WARNING Fake TPipeClientComm.ServerRunning - no safe solution known}
  70. Result := true;
  71. end;
  72. { ---------------------------------------------------------------------
  73. TPipeServerComm
  74. ---------------------------------------------------------------------}
  75. type
  76. TPipeServerComm = class (TIPCServerComm)
  77. private
  78. FFileName: string;
  79. FStream: THandleStream;
  80. EventSem: THandle;
  81. SemName: string;
  82. public
  83. constructor Create (AOWner: TSimpleIPCServer); override;
  84. procedure StartServer; override;
  85. procedure StopServer; override;
  86. function PeekMessage (TimeOut: integer): boolean; override;
  87. procedure ReadMessage; override;
  88. function GetInstanceID: string; override;
  89. property FileName: string read FFileName;
  90. property Stream: THandleStream read FStream;
  91. end;
  92. constructor TPipeServerComm.Create (AOWner: TSimpleIPCServer);
  93. begin
  94. inherited Create (AOWner);
  95. FFileName := '\PIPE\' + Owner.ServerID;
  96. SemName := '\SEM32\PIPE\' + Owner.ServerID;
  97. If not Owner.Global then
  98. FFileName := FFileName + '.' + IntToStr (GetProcessID);
  99. end;
  100. procedure TPipeServerComm.StartServer;
  101. var
  102. H: THandle;
  103. begin
  104. if not (Assigned (FStream)) then
  105. if (DosCreateNPipe (PChar (FFileName), H, np_Access_Inbound,
  106. np_ReadMode_Message or np_WriteMode_Message or 1, PipeBufSize,
  107. PipeBufSize, 0) <> 0) or
  108. (DosCreateEventSem (PChar (SemName), EventSem, 0, 0) <> 0) or
  109. (DosSetNPipeSem (H, EventSem, PipeKey) <> 0) or
  110. (DosConnectNPipe (H) <> 0) then
  111. Owner.DoError (SErrFailedToCreatePipe, [FFileName]);
  112. FStream := THandleStream.Create (H);
  113. end;
  114. procedure TPipeServerComm.StopServer;
  115. begin
  116. if (DosDisconnectNPipe (FStream.Handle) <> 0) or
  117. (DosCloseEventSem (EventSem) <> 0) then
  118. Owner.DoError (SErrFailedToDisconnectPipe, [FFileName]);
  119. FreeAndNil (FStream);
  120. end;
  121. function TPipeServerComm.PeekMessage (TimeOut: integer): boolean;
  122. var
  123. PipeSemState: TPipeSemState;
  124. begin
  125. Result := (DosQueryNPipeSemState (EventSem, PipeSemState,
  126. SizeOf (PipeSemState)) = 0) and (PipeSemState.Status = 1) and
  127. (PipeSemState.Avail <> 0) and (PipeSemState.Key = PipeKey);
  128. if not (Result) then
  129. Result := (DosWaitEventSem (EventSem, TimeOut) = 0) and
  130. (DosQueryNPipeSemState (EventSem, PipeSemState,
  131. SizeOf (PipeSemState)) = 0) and (PipeSemState.Status = 1) and
  132. (PipeSemState.Avail <> 0) and (PipeSemState.Key = PipeKey);
  133. end;
  134. procedure TPipeServerComm.ReadMessage;
  135. var
  136. Hdr: TMsgHeader;
  137. begin
  138. FStream.ReadBuffer (Hdr, SizeOf (Hdr));
  139. Owner.FMsgType := Hdr.MsgType;
  140. if Hdr.MsgLen > 0 then
  141. begin
  142. Owner.FMsgData.Size:=0;
  143. Owner.FMsgData.Seek (0, soFromBeginning);
  144. Owner.FMsgData.CopyFrom (FStream, Hdr.MsgLen);
  145. end
  146. else
  147. Owner.FMsgData.Size := 0;
  148. end;
  149. function TPipeServerComm.GetInstanceID: string;
  150. begin
  151. Result := IntToStr (GetProcessID);
  152. end;
  153. { ---------------------------------------------------------------------
  154. Set TSimpleIPCClient / TSimpleIPCServer defaults.
  155. ---------------------------------------------------------------------}
  156. function TSimpleIPCServer.CommClass: TIPCServerCommClass;
  157. begin
  158. if (DefaultIPCServerClass <> nil) then
  159. Result := DefaultIPCServerClass
  160. else
  161. Result := TPipeServerComm;
  162. end;
  163. function TSimpleIPCClient.CommClass: TIPCClientCommClass;
  164. begin
  165. if (DefaultIPCClientClass <> nil) then
  166. Result := DefaultIPCClientClass
  167. else
  168. Result := TPipeClientComm;
  169. end;