simpleipc.pp 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. {
  2. This file is part of the Free Component library.
  3. Copyright (c) 2005 by Michael Van Canneyt, member of
  4. the Free Pascal development team
  5. Unit implementing 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. unit simpleipc;
  13. {$mode objfpc}{$H+}
  14. interface
  15. uses
  16. Classes, SysUtils;
  17. Const
  18. MsgVersion = 1;
  19. Type
  20. TMessageType = (mtUnknown,mtString); // For now
  21. TMsgHeader = Packed record
  22. Version : Byte;
  23. msgType : TMessageType;
  24. MsgLen : Integer;
  25. end;
  26. TSimpleIPCServer = class;
  27. TSimpleIPCClient = class;
  28. { TIPCServerComm }
  29. TIPCServerComm = Class(TObject)
  30. Private
  31. FOwner : TSimpleIPCServer;
  32. Public
  33. Constructor Create(AOwner : TSimpleIPCServer); virtual;
  34. Property Owner : TSimpleIPCServer read FOwner;
  35. Procedure StartServer; virtual; Abstract;
  36. Procedure StopServer;virtual; Abstract;
  37. Function PeekMessage(TimeOut : Integer) : Boolean;virtual; Abstract;
  38. Function GetInstanceID : String; virtual; abstract;
  39. Procedure ReadMessage ;virtual; Abstract;
  40. Property InstanceID : String read GetInstanceID;
  41. end;
  42. TIPCServerCommClass = Class of TIPCServerComm;
  43. { TSimpleIPC }
  44. TSimpleIPC = Class(TComponent)
  45. Private
  46. procedure SetActive(const AValue: Boolean);
  47. procedure SetServerID(const AValue: String);
  48. Protected
  49. FBusy: Boolean;
  50. FActive : Boolean;
  51. FServerID : String;
  52. Procedure DoError(Msg : String; Args : Array of const);
  53. Procedure CheckInactive;
  54. Procedure CheckActive;
  55. Procedure Activate; virtual; abstract;
  56. Procedure Deactivate; virtual; abstract;
  57. Property Busy : Boolean Read FBusy;
  58. Published
  59. Property Active : Boolean Read FActive Write SetActive;
  60. Property ServerID : String Read FServerID Write SetServerID;
  61. end;
  62. { TSimpleIPCServer }
  63. TSimpleIPCServer = Class(TSimpleIPC)
  64. private
  65. FGlobal: Boolean;
  66. FOnMessage: TNotifyEvent;
  67. FMsgData : TStream;
  68. function GetInstanceID: String;
  69. function GetStringMessage: String;
  70. procedure SetGlobal(const AValue: Boolean);
  71. Protected
  72. FIPCComm: TIPCServerComm;
  73. Function CommClass : TIPCServerCommClass; virtual;
  74. Procedure Activate; override;
  75. Procedure Deactivate; override;
  76. Procedure ReadMessage;
  77. Public
  78. Constructor Create(AOwner : TComponent); override;
  79. Destructor destroy; override;
  80. Procedure StartServer;
  81. Procedure StopServer;
  82. Function PeekMessage(TimeOut : Integer; DoReadMessage : Boolean): Boolean;
  83. Property StringMessage : String Read GetStringMessage;
  84. Procedure GetMessageData(Stream : TStream);
  85. Property MsgData : TStream Read FMsgData;
  86. Property InstanceID : String Read GetInstanceID;
  87. Published
  88. Property Global : Boolean Read FGlobal Write SetGlobal;
  89. Property OnMessage : TNotifyEvent Read FOnMessage Write FOnMessage;
  90. end;
  91. { TIPCClientComm}
  92. TIPCClientComm = Class(TObject)
  93. private
  94. FOwner: TSimpleIPCClient;
  95. Public
  96. Constructor Create(AOwner : TSimpleIPCClient); virtual;
  97. Property Owner : TSimpleIPCClient read FOwner;
  98. Procedure Connect; virtual; abstract;
  99. Procedure Disconnect; virtual; abstract;
  100. Function ServerRunning : Boolean; virtual; abstract;
  101. Procedure SendMessage(MsgType : TMessageType; Stream : TStream);virtual;Abstract;
  102. end;
  103. TIPCClientCommClass = Class of TIPCClientComm;
  104. { TSimpleIPCClient }
  105. TSimpleIPCClient = Class(TSimpleIPC)
  106. Private
  107. FServerInstance: String;
  108. procedure SetServerInstance(const AValue: String);
  109. Protected
  110. FIPCComm : TIPCClientComm;
  111. Procedure Activate; override;
  112. Procedure Deactivate; override;
  113. Function CommClass : TIPCClientCommClass; virtual;
  114. Public
  115. Constructor Create(AOwner : TComponent); override;
  116. Destructor destroy; override;
  117. Procedure Connect;
  118. Procedure Disconnect;
  119. Function ServerRunning : Boolean;
  120. Procedure SendMessage(MsgType : TMessageType; Stream: TStream);
  121. Procedure SendStringMessage(Msg : String);
  122. Procedure SendStringmessageFmt(Msg : String; Args : Array of const);
  123. Property ServerInstance : String Read FServerInstance Write SetServerInstance;
  124. end;
  125. EIPCError = Class(Exception);
  126. Var
  127. DefaultIPCServerClass : TIPCServerCommClass = Nil;
  128. DefaultIPCClientClass : TIPCClientCommClass = Nil;
  129. resourcestring
  130. SErrServerNotActive = 'Server with ID %s is not active.';
  131. SErrActive = 'This operation is illegal when the server is active.';
  132. SErrInActive = 'This operation is illegal when the server is inactive.';
  133. implementation
  134. { ---------------------------------------------------------------------
  135. Include platform specific implementation.
  136. Should implement the CommClass method of both server and client component,
  137. as well as the communication class itself.
  138. This comes first, to allow the uses clause to be set.
  139. --------------------------------------------------------------------- }
  140. {$i simpleipc.inc}
  141. { ---------------------------------------------------------------------
  142. TIPCServerComm
  143. ---------------------------------------------------------------------}
  144. constructor TIPCServerComm.Create(AOwner: TSimpleIPCServer);
  145. begin
  146. FOwner:=AOWner;
  147. end;
  148. { ---------------------------------------------------------------------
  149. TIPCClientComm
  150. ---------------------------------------------------------------------}
  151. constructor TIPCClientComm.Create(AOwner: TSimpleIPCClient);
  152. begin
  153. FOwner:=AOwner;
  154. end;
  155. { ---------------------------------------------------------------------
  156. TSimpleIPC
  157. ---------------------------------------------------------------------}
  158. procedure TSimpleIPC.DoError(Msg: String; Args: array of const);
  159. begin
  160. Raise EIPCError.Create(Name+': '+Format(Msg,Args));
  161. end;
  162. procedure TSimpleIPC.CheckInactive;
  163. begin
  164. If Active then
  165. DoError(SErrActive,[]);
  166. end;
  167. procedure TSimpleIPC.CheckActive;
  168. begin
  169. If Not Active then
  170. DoError(SErrInActive,[]);
  171. end;
  172. procedure TSimpleIPC.SetActive(const AValue: Boolean);
  173. begin
  174. if (FActive<>AValue) then
  175. begin
  176. If AValue then
  177. Activate
  178. else
  179. Deactivate;
  180. end;
  181. end;
  182. procedure TSimpleIPC.SetServerID(const AValue: String);
  183. begin
  184. if (FServerID<>AValue) then
  185. begin
  186. CheckInactive;
  187. FServerID:=AValue
  188. end;
  189. end;
  190. { ---------------------------------------------------------------------
  191. TSimpleIPCServer
  192. ---------------------------------------------------------------------}
  193. constructor TSimpleIPCServer.Create(AOwner: TComponent);
  194. begin
  195. inherited Create(AOwner);
  196. FGlobal:=False;
  197. FActive:=False;
  198. FBusy:=False;
  199. FMsgData:=TStringStream.Create('');
  200. end;
  201. destructor TSimpleIPCServer.destroy;
  202. begin
  203. Active:=False;
  204. FreeAndNil(FMsgData);
  205. inherited destroy;
  206. end;
  207. procedure TSimpleIPCServer.SetGlobal(const AValue: Boolean);
  208. begin
  209. if (FGlobal<>AValue) then
  210. begin
  211. CheckInactive;
  212. FGlobal:=AValue;
  213. end;
  214. end;
  215. function TSimpleIPCServer.GetInstanceID: String;
  216. begin
  217. Result:=FIPCComm.InstanceID;
  218. end;
  219. function TSimpleIPCServer.GetStringMessage: String;
  220. begin
  221. Result:=TStringStream(FMsgData).DataString;
  222. end;
  223. procedure TSimpleIPCServer.StartServer;
  224. begin
  225. if Not Assigned(FIPCComm) then
  226. begin
  227. If (FServerID='') then
  228. FServerID:=ApplicationName;
  229. FIPCComm:=CommClass.Create(Self);
  230. FIPCComm.StartServer;
  231. end;
  232. FActive:=True;
  233. end;
  234. procedure TSimpleIPCServer.StopServer;
  235. begin
  236. If Assigned(FIPCComm) then
  237. begin
  238. FIPCComm.StopServer;
  239. FreeAndNil(FIPCComm);
  240. end;
  241. FActive:=False;
  242. end;
  243. function TSimpleIPCServer.PeekMessage(TimeOut: Integer; DoReadMessage: Boolean
  244. ): Boolean;
  245. begin
  246. CheckActive;
  247. FBusy:=True;
  248. Try
  249. Result:=FIPCComm.PeekMessage(Timeout);
  250. Finally
  251. FBusy:=False;
  252. end;
  253. If Result then
  254. If DoReadMessage then
  255. Readmessage;
  256. end;
  257. procedure TSimpleIPCServer.ReadMessage;
  258. begin
  259. CheckActive;
  260. FBusy:=True;
  261. Try
  262. FIPCComm.ReadMessage;
  263. If Assigned(FOnMessage) then
  264. FOnMessage(Self);
  265. Finally
  266. FBusy:=False;
  267. end;
  268. end;
  269. procedure TSimpleIPCServer.GetMessageData(Stream: TStream);
  270. begin
  271. Stream.CopyFrom(FMsgData,0);
  272. end;
  273. procedure TSimpleIPCServer.Activate;
  274. begin
  275. StartServer;
  276. end;
  277. procedure TSimpleIPCServer.Deactivate;
  278. begin
  279. StopServer;
  280. end;
  281. { ---------------------------------------------------------------------
  282. TSimpleIPCClient
  283. ---------------------------------------------------------------------}
  284. procedure TSimpleIPCClient.SetServerInstance(const AValue: String);
  285. begin
  286. CheckInactive;
  287. FServerInstance:=AVAlue;
  288. end;
  289. procedure TSimpleIPCClient.Activate;
  290. begin
  291. Connect;
  292. end;
  293. procedure TSimpleIPCClient.Deactivate;
  294. begin
  295. DisConnect;
  296. end;
  297. constructor TSimpleIPCClient.Create(AOwner: TComponent);
  298. begin
  299. inherited Create(AOwner);
  300. end;
  301. destructor TSimpleIPCClient.destroy;
  302. begin
  303. Active:=False;
  304. Inherited;
  305. end;
  306. procedure TSimpleIPCClient.Connect;
  307. begin
  308. FIPCComm:=CommClass.Create(Self);
  309. FIPCComm.Connect;
  310. FActive:=True;
  311. end;
  312. procedure TSimpleIPCClient.Disconnect;
  313. begin
  314. FIPCComm.DisConnect;
  315. FreeAndNil(FIPCComm);
  316. FActive:=False;
  317. end;
  318. function TSimpleIPCClient.ServerRunning: Boolean;
  319. begin
  320. If Assigned(FIPCComm) then
  321. Result:=FIPCComm.ServerRunning
  322. else
  323. With CommClass.Create(Self) do
  324. Try
  325. Result:=ServerRunning;
  326. finally
  327. Free;
  328. end;
  329. end;
  330. procedure TSimpleIPCClient.SendMessage(MsgType : TMessageType; Stream: TStream);
  331. begin
  332. CheckActive;
  333. FBusy:=True;
  334. Try
  335. FIPCComm.SendMessage(MsgType,Stream);
  336. Finally
  337. FBusy:=False;
  338. end;
  339. end;
  340. procedure TSimpleIPCClient.SendStringMessage(Msg: String);
  341. Var
  342. S : TStringStream;
  343. begin
  344. S:=TStringStream.Create(Msg);
  345. try
  346. SendMessage(mtString,S);
  347. finally
  348. s.free;
  349. end;
  350. end;
  351. procedure TSimpleIPCClient.SendStringmessageFmt(Msg: String;
  352. Args: array of const);
  353. begin
  354. SendStringmessage(Format(Msg,Args));
  355. end;
  356. end.