simpleipc.pp 12 KB

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