dbugintf.pp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  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. Debugserver client interface, based on SimpleIPC
  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. {$mode objfpc}
  13. {$h+}
  14. {$IFNDEF FPC_DOTTEDUNITS}
  15. unit dbugintf;
  16. {$ENDIF FPC_DOTTEDUNITS}
  17. interface
  18. {$IFDEF FPC_DOTTEDUNITS}
  19. uses System.Dbugmsg;
  20. {$ELSE FPC_DOTTEDUNITS}
  21. uses dbugmsg;
  22. {$ENDIF FPC_DOTTEDUNITS}
  23. Type
  24. TDebugLevel = (dlInformation,dlWarning,dlError);
  25. TErrorLevel = Array[TDebugLevel] of integer;
  26. //Result is true on success. See RaiseExceptionOnSendError.
  27. function SendBoolean (const Identifier: string; const Value: Boolean) : Boolean;
  28. //Result is true on success. See RaiseExceptionOnSendError.
  29. function SendDateTime (const Identifier: string; const Value: TDateTime) : Boolean;
  30. //Result is true on success. See RaiseExceptionOnSendError.
  31. function SendInteger (const Identifier: string; const Value: Integer;
  32. HexNotation: Boolean = False) : Boolean;
  33. //Result is true on success. See RaiseExceptionOnSendError.
  34. function SendPointer (const Identifier: string; const Value: Pointer) : Boolean;
  35. //Result is true on success. See RaiseExceptionOnSendError.
  36. function SendDebugEx (const Msg: string; MType: TDebugLevel) : Boolean;
  37. //Result is true on success. See RaiseExceptionOnSendError.
  38. function SendDebug (const Msg: string) : Boolean;
  39. //Result is true on success. See RaiseExceptionOnSendError.
  40. function SendMethodEnter(const MethodName: string) : Boolean;
  41. //Result is true on success. See RaiseExceptionOnSendError.
  42. function SendMethodExit (const MethodName: string) : Boolean;
  43. //Result is true on success. See RaiseExceptionOnSendError.
  44. function SendSeparator : Boolean;
  45. //Result is true on success. See RaiseExceptionOnSendError.
  46. function SendDebugFmt (const Msg: string; const Args: array of const) : Boolean;
  47. //Result is true on success. See RaiseExceptionOnSendError.
  48. function SendDebugFmtEx (const Msg: string; const Args: array of const;
  49. MType: TDebugLevel) : Boolean;
  50. procedure SetDebuggingEnabled(const AValue : boolean);
  51. function GetDebuggingEnabled : Boolean;
  52. { low-level routines }
  53. //Start the debug server and return its ProcessID.
  54. function StartDebugServer(const ADebugServerExe : String = '';
  55. const ARaiseExceptionOnSendError : Boolean = False;
  56. const aLogFilename : String = '') : integer;
  57. //Initialize the debug client and start the server.
  58. function InitDebugClient : Boolean;
  59. //Initialize the debug client and start the server.
  60. function InitDebugClient(const ShowPID: Boolean; const ADebugServerExe : String = '';
  61. const ARaiseExceptionOnSendError : Boolean = False;
  62. const ServerLogFilename: String = ''): Boolean;
  63. procedure FreeDebugClient;
  64. ResourceString
  65. SProcessID = '%d Process %s (PID=%d)';
  66. SEntering = '> Entering ';
  67. SExiting = '< Exiting ';
  68. SSeparator = '>-=-=-=-=-=-=-=-=-=-=-=-=-=-=-<';
  69. SServerStartFailed = 'Failed to start debugserver (%s). (%s)';
  70. Var
  71. DebugServerExe : String = ''; { We can override this global var. in our compiled IPC client, with DefaultDebugServer a.k.a. dbugmsg.DebugServerID, or something else }
  72. DefaultDebugServer : String = DebugServerID ; { A "last ressort" simplier compiled IPC server's name, called in command line by your client a.k.a. the compiler's target file "-o" }
  73. //Last error message of a Send... function. Not cleared on a new call!
  74. SendError : String = '';
  75. //Raise an exception if a Send... function fails.
  76. //Otherwise the Send... functions will return false without an exception in case of an error.
  77. RaiseExceptionOnSendError : Boolean = false;
  78. implementation
  79. {$IFDEF FPC_DOTTEDUNITS}
  80. Uses
  81. System.SysUtils, System.Classes, System.Process, System.Simpleipc;
  82. {$ELSE FPC_DOTTEDUNITS}
  83. Uses
  84. SysUtils, classes, process, simpleipc;
  85. {$ENDIF FPC_DOTTEDUNITS}
  86. Const
  87. DmtInformation = lctInformation;
  88. DmtWarning = lctWarning;
  89. DmtError = lctError;
  90. ErrorLevel : TErrorLevel
  91. = (dmtInformation,dmtWarning,dmtError);
  92. IndentChars = 2;
  93. var
  94. DebugClient : TSimpleIPCClient = nil;
  95. MsgBuffer : TMemoryStream = Nil;
  96. AlwaysDisplayPID : Boolean = False;
  97. ServerID : Integer;
  98. DebugDisabled : Boolean = False;
  99. Indent : Integer = 0;
  100. Procedure WriteMessage(Const Msg : TDebugMessage);
  101. begin
  102. if not Assigned(MsgBuffer) then
  103. exit;
  104. MsgBuffer.Seek(0,soFrombeginning);
  105. WriteDebugMessageToStream(MsgBuffer,Msg);
  106. DebugClient.SendMessage(mtUnknown,MsgBuffer);
  107. end;
  108. function SendDebugMessage(Var Msg : TDebugMessage) : Boolean;
  109. begin
  110. Result:=False;
  111. if DebugDisabled then exit(True);
  112. try
  113. If (DebugClient=Nil) then
  114. if InitDebugClient = false then exit;
  115. If (Indent>0) then
  116. Msg.Msg:=StringOfChar(' ',Indent)+Msg.Msg;
  117. WriteMessage(Msg);
  118. Result:=True;
  119. except
  120. On E : Exception do
  121. begin
  122. SendError:=E.Message;
  123. if RaiseExceptionOnSendError then
  124. raise;
  125. end;
  126. end;
  127. end;
  128. function SendBoolean(const Identifier: string; const Value: Boolean) : Boolean;
  129. Const
  130. Booleans : Array[Boolean] of string = ('False','True');
  131. begin
  132. Result:=SendDebugFmt('%s = %s',[Identifier,Booleans[value]]);
  133. end;
  134. function SendDateTime(const Identifier: string; const Value: TDateTime) : Boolean;
  135. begin
  136. Result:=SendDebugFmt('%s = %s',[Identifier,DateTimeToStr(Value)]);
  137. end;
  138. function SendInteger(const Identifier: string; const Value: Integer;
  139. HexNotation: Boolean = False) : Boolean;
  140. Const
  141. Msgs : Array[Boolean] of string = ('%s = %d','%s = %x');
  142. begin
  143. Result:=SendDebugFmt(Msgs[HexNotation],[Identifier,Value]);
  144. end;
  145. function SendPointer(const Identifier: string; const Value: Pointer) : Boolean;
  146. begin
  147. Result:=SendDebugFmt('%s = %p',[Identifier,Value]);
  148. end;
  149. function SendDebugEx(const Msg: string; MType: TDebugLevel) : Boolean;
  150. Var
  151. Mesg : TDebugMessage;
  152. begin
  153. Mesg.MsgTimeStamp:=Now;
  154. Mesg.MsgType:=ErrorLevel[MTYpe];
  155. if AlwaysDisplayPID then
  156. Mesg.Msg:=IntToStr(GetProcessID)+' '+Msg
  157. else
  158. Mesg.Msg:=Msg;
  159. Result:=SendDebugMessage(Mesg);
  160. end;
  161. function SendDebug(const Msg: string) : Boolean;
  162. Var
  163. Mesg : TDebugMessage;
  164. begin
  165. Mesg.MsgTimeStamp:=Now;
  166. Mesg.MsgType:=dmtInformation;
  167. if AlwaysDisplayPID then
  168. Mesg.Msg:=IntToStr(GetProcessID)+' '+Msg
  169. else
  170. Mesg.Msg:=Msg;
  171. Result:=SendDebugMessage(Mesg);
  172. end;
  173. function SendMethodEnter(const MethodName: string) : Boolean;
  174. begin
  175. Result:=SendDebug(SEntering+MethodName);
  176. inc(Indent,IndentChars);
  177. end;
  178. function SendMethodExit(const MethodName: string) : Boolean;
  179. begin
  180. Dec(Indent,IndentChars);
  181. If (Indent<0) then
  182. Indent:=0;
  183. Result:=SendDebug(SExiting+MethodName);
  184. end;
  185. function SendSeparator: Boolean;
  186. begin
  187. Result:=SendDebug(SSeparator);
  188. end;
  189. function SendDebugFmt(const Msg: string; const Args: array of const) : Boolean;
  190. Var
  191. Mesg : TDebugMessage;
  192. begin
  193. Mesg.MsgTimeStamp:=Now;
  194. Mesg.MsgType:=dmtInformation;
  195. if AlwaysDisplayPID then
  196. Mesg.Msg:=IntToStr(GetProcessID)+' '+Format(Msg,Args)
  197. else
  198. Mesg.Msg:=Format(Msg,Args);
  199. Result:=SendDebugMessage(Mesg);
  200. end;
  201. function SendDebugFmtEx(const Msg: string; const Args: array of const;
  202. MType: TDebugLevel) : Boolean;
  203. Var
  204. Mesg : TDebugMessage;
  205. begin
  206. Mesg.MsgTimeStamp:=Now;
  207. Mesg.MsgType:=ErrorLevel[mType];
  208. if AlwaysDisplayPID then
  209. Mesg.Msg:=IntToStr(GetProcessID)+' '+Format(Msg,Args)
  210. else
  211. Mesg.Msg:=Format(Msg,Args);
  212. Result:=SendDebugMessage(Mesg);
  213. end;
  214. procedure SetDebuggingEnabled(const AValue: boolean);
  215. begin
  216. DebugDisabled := not AValue;
  217. end;
  218. function GetDebuggingEnabled: Boolean;
  219. begin
  220. Result := not DebugDisabled;
  221. end;
  222. function StartDebugServer(const ADebugServerExe : String = '';
  223. const ARaiseExceptionOnSendError : Boolean = False;
  224. Const aLogFileName : string = '') : Integer;
  225. Var
  226. Cmd : string;
  227. begin
  228. Result := 0;
  229. if ADebugServerExe<>'' then
  230. DebugServerExe:=ADebugServerExe;
  231. RaiseExceptionOnSendError:=ARaiseExceptionOnSendError;
  232. Cmd := DebugServerExe;
  233. if Cmd='' then
  234. Cmd := DefaultDebugServer;
  235. With TProcess.Create(Nil) do
  236. begin
  237. Try
  238. Executable := Cmd;
  239. If aLogFileName<>'' Then
  240. Parameters.Add(aLogFileName);
  241. Execute;
  242. Result := ProcessID;
  243. Except On E: Exception do
  244. begin
  245. E.Message:=Format(SServerStartFailed,[cmd,E.Message]);
  246. Free;
  247. raise;
  248. end;
  249. end;
  250. Free;
  251. end;
  252. end;
  253. procedure FreeDebugClient;
  254. Var
  255. msg : TDebugMessage;
  256. begin
  257. try
  258. If (DebugClient<>Nil) and
  259. (DebugClient.ServerRunning) then
  260. begin
  261. Msg.MsgType:=lctStop;
  262. Msg.MsgTimeStamp:=Now;
  263. Msg.Msg:=Format(SProcessID,[GetProcessID, ApplicationName, GetProcessID]);
  264. WriteMessage(Msg);
  265. end;
  266. if assigned(MsgBuffer) then FreeAndNil(MsgBuffer);
  267. if assigned(DebugClient) then FreeAndNil(DebugClient);
  268. except
  269. end;
  270. end;
  271. Function InitDebugClient : Boolean;
  272. begin
  273. Result:=InitDebugClient(False,'',RaiseExceptionOnSendError,'');
  274. end;
  275. function InitDebugClient(const ShowPID: Boolean;
  276. const ADebugServerExe : String = ''; // Start the debug server and return its ProcessID.
  277. const ARaiseExceptionOnSendError : Boolean = False;
  278. const ServerLogFilename: String = ''): Boolean;
  279. Var
  280. msg : TDebugMessage;
  281. I : Integer;
  282. begin
  283. Result := False;
  284. AlwaysDisplayPID:= ShowPID;
  285. DebugClient:=TSimpleIPCClient.Create(Nil);
  286. DebugClient.ServerID:=DebugServerID;
  287. try
  288. If not DebugClient.ServerRunning then
  289. begin
  290. ServerID:=StartDebugServer(ADebugServerExe,ARaiseExceptionOnSendError,ServerLogFileName);
  291. if ServerID = 0 then
  292. begin
  293. DebugDisabled := True;
  294. FreeAndNil(DebugClient);
  295. Exit;
  296. end
  297. else
  298. DebugDisabled := False;
  299. I:=0;
  300. While (I<100) and not DebugClient.ServerRunning do
  301. begin
  302. Inc(I);
  303. Sleep(100);
  304. end;
  305. end;
  306. DebugClient.Connect;
  307. except
  308. FreeAndNil(DebugClient);
  309. DebugDisabled:=True;
  310. Raise;
  311. end;
  312. MsgBuffer:=TMemoryStream.Create;
  313. Msg.MsgType:=lctIdentify;
  314. Msg.MsgTimeStamp:=Now;
  315. Msg.Msg:=Format(SProcessID,[GetProcessID, ApplicationName, GetProcessID]);
  316. WriteMessage(Msg);
  317. Result := True;
  318. end;
  319. Finalization
  320. FreeDebugClient;
  321. end.