simpleipc.inc 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  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. Windows 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 Windows,messages;
  13. Const
  14. MsgWndClassName : pchar = 'FPCMsgWindowCls';
  15. Resourcestring
  16. SErrFailedToRegisterWindowClass = 'Failed to register message window class';
  17. SErrFailedToCreateWindow = 'Failed to create message window %s';
  18. var
  19. MsgWindowClass: TWndClass = (
  20. style: 0;
  21. lpfnWndProc: Nil;
  22. cbClsExtra: 0;
  23. cbWndExtra: 0;
  24. hInstance: 0;
  25. hIcon: 0;
  26. hCursor: 0;
  27. hbrBackground: 0;
  28. lpszMenuName: nil;
  29. lpszClassName: Nil);
  30. { ---------------------------------------------------------------------
  31. TWinMsgServerComm
  32. ---------------------------------------------------------------------}
  33. Type
  34. TWinMsgServerComm = Class(TIPCServerComm)
  35. Private
  36. FHWND : HWND;
  37. FWindowName : String;
  38. FDataPushed : Boolean;
  39. FUnction AllocateHWnd(Const aWindowName : String) : HWND;
  40. Public
  41. Constructor Create(AOWner : TSimpleIPCServer); override;
  42. procedure ReadMsgData(var Msg: TMsg);
  43. Procedure StartServer; override;
  44. Procedure StopServer; override;
  45. Function PeekMessage(TimeOut : Integer) : Boolean; override;
  46. Procedure ReadMessage ; override;
  47. Function GetInstanceID : String;override;
  48. Property WindowName : String Read FWindowName;
  49. end;
  50. function MsgWndProc(HWindow: HWnd; Message, WParam, LParam: Longint): Longint;stdcall;
  51. Var
  52. I : TWinMsgServerComm;
  53. Msg : TMsg;
  54. begin
  55. Result:=0;
  56. If (Message=WM_COPYDATA) then
  57. begin
  58. I:=TWinMsgServerComm(GetWindowLongPtr(HWindow,GWL_USERDATA));
  59. If (I<>NIl) then
  60. begin
  61. Msg.Message:=Message;
  62. Msg.WParam:=WParam;
  63. Msg.LParam:=LParam;
  64. I.ReadMsgData(Msg);
  65. I.FDataPushed:=True;
  66. If Assigned(I.Owner.OnMessage) then
  67. I.Owner.ReadMessage;
  68. Result:=1;
  69. end
  70. end
  71. else
  72. Result:=DefWindowProc(HWindow,Message,WParam,LParam);
  73. end;
  74. function TWinMsgServerComm.AllocateHWnd(const aWindowName: String): HWND;
  75. var
  76. cls: TWndClass;
  77. isreg : Boolean;
  78. begin
  79. Pointer(MsgWindowClass.lpfnWndProc):=@MsgWndProc;
  80. MsgWindowClass.hInstance := HInstance;
  81. MsgWindowClass.lpszClassName:=MsgWndClassName;
  82. isreg:=GetClassInfo(HInstance,MsgWndClassName,cls);
  83. if not isreg then
  84. if (Windows.RegisterClass(MsgWindowClass)=0) then
  85. Owner.DoError(SErrFailedToRegisterWindowClass,[]);
  86. Result:=CreateWindowEx(WS_EX_TOOLWINDOW, MsgWndClassName,
  87. PChar(aWindowName), WS_POPUP {!0}, 0, 0, 0, 0, 0, 0, HInstance, nil);
  88. if (Result=0) then
  89. Owner.DoError(SErrFailedToCreateWindow,[aWindowName]);
  90. SetWindowLongPtr(Result,GWL_USERDATA,PtrInt(Self));
  91. end;
  92. constructor TWinMsgServerComm.Create(AOWner: TSimpleIPCServer);
  93. begin
  94. inherited Create(AOWner);
  95. FWindowName:=Owner.ServerID;
  96. If not Owner.Global then
  97. FWindowName:=FWindowName+'_'+InstanceID;
  98. end;
  99. procedure TWinMsgServerComm.StartServer;
  100. begin
  101. FHWND:=AllocateHWND(FWindowName);
  102. end;
  103. procedure TWinMsgServerComm.StopServer;
  104. begin
  105. DestroyWindow(FHWND);
  106. FHWND:=0;
  107. end;
  108. function TWinMsgServerComm.PeekMessage(TimeOut: Integer): Boolean;
  109. Var
  110. Msg : Tmsg;
  111. B : Boolean;
  112. R : DWORD;
  113. begin
  114. Result:=FDataPushed;
  115. If Result then
  116. Exit;
  117. B:=Windows.PeekMessage(Msg, FHWND, 0, 0, PM_NOREMOVE);
  118. If not B then
  119. // No message yet. Wait for a message to arrive available within specified time.
  120. begin
  121. if (TimeOut=0) then
  122. TimeOut:=Integer(INFINITE);
  123. R:=MsgWaitForMultipleObjects(1,FHWND,False,TimeOut,QS_SENDMESSAGE);
  124. B:=(R<>WAIT_TIMEOUT);
  125. end;
  126. If B then
  127. Repeat
  128. B:=Windows.PeekMessage(Msg, FHWND, 0, 0, PM_NOREMOVE);
  129. if B then
  130. begin
  131. Result:=(Msg.Message=WM_COPYDATA);
  132. // Remove non WM_COPY messages from Queue
  133. if not Result then
  134. GetMessage(Msg,FHWND,0,0);
  135. end;
  136. Until Result or (not B);
  137. end;
  138. procedure TWinMsgServerComm.ReadMsgData(var Msg: TMsg);
  139. Var
  140. CDS : PCopyDataStruct;
  141. begin
  142. CDS:=PCopyDataStruct(Msg.Lparam);
  143. Owner.FMsgData.Seek(0,soFrombeginning);
  144. Owner.FMsgData.WriteBuffer(CDS^.lpData^,CDS^.cbData);
  145. end;
  146. procedure TWinMsgServerComm.ReadMessage;
  147. Var
  148. Msg : TMsg;
  149. begin
  150. If FDataPushed then
  151. FDataPushed:=False
  152. else
  153. If Windows.PeekMessage(Msg, FHWND, 0, 0, PM_REMOVE) then
  154. if (Msg.Message=WM_COPYDATA) then
  155. ReadMsgData(Msg);
  156. end;
  157. function TWinMsgServerComm.GetInstanceID: String;
  158. begin
  159. Result:=IntToStr(HInstance);
  160. end;
  161. { ---------------------------------------------------------------------
  162. TWinMsgClientComm
  163. ---------------------------------------------------------------------}
  164. Type
  165. TWinMsgClientComm = Class(TIPCClientComm)
  166. Private
  167. FWindowName: String;
  168. FHWND : HWnd;
  169. Public
  170. Constructor Create(AOWner : TSimpleIPCClient); override;
  171. Procedure Connect; override;
  172. Procedure Disconnect; override;
  173. Procedure SendMessage(MsgType : TMessageType; Stream : TStream); override;
  174. Function ServerRunning : Boolean; override;
  175. Property WindowName : String Read FWindowName;
  176. end;
  177. constructor TWinMsgClientComm.Create(AOWner: TSimpleIPCClient);
  178. begin
  179. inherited Create(AOWner);
  180. FWindowName:=Owner.ServerID;
  181. If (Owner.ServerInstance<>'') then
  182. FWindowName:=FWindowName+'_'+Owner.ServerInstance;
  183. end;
  184. procedure TWinMsgClientComm.Connect;
  185. begin
  186. FHWND:=FindWindow(MsgWndClassName,PChar(FWindowName));
  187. If (FHWND=0) then
  188. Owner.DoError(SErrServerNotActive,[Owner.ServerID]);
  189. end;
  190. procedure TWinMsgClientComm.Disconnect;
  191. begin
  192. FHWND:=0;
  193. end;
  194. procedure TWinMsgClientComm.SendMessage(MsgType: TMessageType; Stream: TStream
  195. );
  196. Var
  197. CDS : TCopyDataStruct;
  198. Data,FMemstr : TMemorySTream;
  199. begin
  200. If Stream is TMemoryStream then
  201. begin
  202. Data:=TMemoryStream(Stream);
  203. FMemStr:=Nil
  204. end
  205. else
  206. begin
  207. FMemStr:=TMemoryStream.Create;
  208. Data:=FMemstr;
  209. end;
  210. Try
  211. If Assigned(FMemStr) then
  212. begin
  213. FMemStr.CopyFrom(Stream,0);
  214. FMemStr.Seek(0,soFromBeginning);
  215. end;
  216. CDS.lpData:=Data.Memory;
  217. CDS.cbData:=Data.Size;
  218. Windows.SendMessage(FHWnd,WM_COPYDATA,0,Integer(@CDS));
  219. Finally
  220. FreeAndNil(FMemStr);
  221. end;
  222. end;
  223. function TWinMsgClientComm.ServerRunning: Boolean;
  224. begin
  225. Result:=FindWindow(MsgWndClassName,PChar(FWindowName))<>0;
  226. end;
  227. { ---------------------------------------------------------------------
  228. Set TSimpleIPCClient / TSimpleIPCServer defaults.
  229. ---------------------------------------------------------------------}
  230. Function TSimpleIPCServer.CommClass : TIPCServerCommClass;
  231. begin
  232. if (DefaultIPCServerClass<>Nil) then
  233. Result:=DefaultIPCServerClass
  234. else
  235. Result:=TWinMsgServerComm;
  236. end;
  237. Function TSimpleIPCClient.CommClass : TIPCClientCommClass;
  238. begin
  239. if (DefaultIPCClientClass<>Nil) then
  240. Result:=DefaultIPCClientClass
  241. else
  242. Result:=TWinMsgClientComm;
  243. end;