simpleipc.pp 11 KB

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