simpleipc.pp 11 KB

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