dbugintf.pp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  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. MsgBuffer.Seek(0,soFrombeginning);
  103. WriteDebugMessageToStream(MsgBuffer,Msg);
  104. DebugClient.SendMessage(mtUnknown,MsgBuffer);
  105. end;
  106. function SendDebugMessage(Var Msg : TDebugMessage) : Boolean;
  107. begin
  108. Result:=False;
  109. if DebugDisabled then exit(True);
  110. try
  111. If (DebugClient=Nil) then
  112. if InitDebugClient = false then exit;
  113. If (Indent>0) then
  114. Msg.Msg:=StringOfChar(' ',Indent)+Msg.Msg;
  115. WriteMessage(Msg);
  116. Result:=True;
  117. except
  118. On E : Exception do
  119. begin
  120. SendError:=E.Message;
  121. if RaiseExceptionOnSendError then
  122. raise;
  123. end;
  124. end;
  125. end;
  126. function SendBoolean(const Identifier: string; const Value: Boolean) : Boolean;
  127. Const
  128. Booleans : Array[Boolean] of string = ('False','True');
  129. begin
  130. Result:=SendDebugFmt('%s = %s',[Identifier,Booleans[value]]);
  131. end;
  132. function SendDateTime(const Identifier: string; const Value: TDateTime) : Boolean;
  133. begin
  134. Result:=SendDebugFmt('%s = %s',[Identifier,DateTimeToStr(Value)]);
  135. end;
  136. function SendInteger(const Identifier: string; const Value: Integer;
  137. HexNotation: Boolean = False) : Boolean;
  138. Const
  139. Msgs : Array[Boolean] of string = ('%s = %d','%s = %x');
  140. begin
  141. Result:=SendDebugFmt(Msgs[HexNotation],[Identifier,Value]);
  142. end;
  143. function SendPointer(const Identifier: string; const Value: Pointer) : Boolean;
  144. begin
  145. Result:=SendDebugFmt('%s = %p',[Identifier,Value]);
  146. end;
  147. function SendDebugEx(const Msg: string; MType: TDebugLevel) : Boolean;
  148. Var
  149. Mesg : TDebugMessage;
  150. begin
  151. Mesg.MsgTimeStamp:=Now;
  152. Mesg.MsgType:=ErrorLevel[MTYpe];
  153. if AlwaysDisplayPID then
  154. Mesg.Msg:=IntToStr(GetProcessID)+' '+Msg
  155. else
  156. Mesg.Msg:=Msg;
  157. Result:=SendDebugMessage(Mesg);
  158. end;
  159. function SendDebug(const Msg: string) : Boolean;
  160. Var
  161. Mesg : TDebugMessage;
  162. begin
  163. Mesg.MsgTimeStamp:=Now;
  164. Mesg.MsgType:=dmtInformation;
  165. if AlwaysDisplayPID then
  166. Mesg.Msg:=IntToStr(GetProcessID)+' '+Msg
  167. else
  168. Mesg.Msg:=Msg;
  169. Result:=SendDebugMessage(Mesg);
  170. end;
  171. function SendMethodEnter(const MethodName: string) : Boolean;
  172. begin
  173. Result:=SendDebug(SEntering+MethodName);
  174. inc(Indent,IndentChars);
  175. end;
  176. function SendMethodExit(const MethodName: string) : Boolean;
  177. begin
  178. Dec(Indent,IndentChars);
  179. If (Indent<0) then
  180. Indent:=0;
  181. Result:=SendDebug(SExiting+MethodName);
  182. end;
  183. function SendSeparator: Boolean;
  184. begin
  185. Result:=SendDebug(SSeparator);
  186. end;
  187. function SendDebugFmt(const Msg: string; const Args: array of const) : Boolean;
  188. Var
  189. Mesg : TDebugMessage;
  190. begin
  191. Mesg.MsgTimeStamp:=Now;
  192. Mesg.MsgType:=dmtInformation;
  193. if AlwaysDisplayPID then
  194. Mesg.Msg:=IntToStr(GetProcessID)+' '+Format(Msg,Args)
  195. else
  196. Mesg.Msg:=Format(Msg,Args);
  197. Result:=SendDebugMessage(Mesg);
  198. end;
  199. function SendDebugFmtEx(const Msg: string; const Args: array of const;
  200. MType: TDebugLevel) : Boolean;
  201. Var
  202. Mesg : TDebugMessage;
  203. begin
  204. Mesg.MsgTimeStamp:=Now;
  205. Mesg.MsgType:=ErrorLevel[mType];
  206. if AlwaysDisplayPID then
  207. Mesg.Msg:=IntToStr(GetProcessID)+' '+Format(Msg,Args)
  208. else
  209. Mesg.Msg:=Format(Msg,Args);
  210. Result:=SendDebugMessage(Mesg);
  211. end;
  212. procedure SetDebuggingEnabled(const AValue: boolean);
  213. begin
  214. DebugDisabled := not AValue;
  215. end;
  216. function GetDebuggingEnabled: Boolean;
  217. begin
  218. Result := not DebugDisabled;
  219. end;
  220. function StartDebugServer(const ADebugServerExe : String = '';
  221. const ARaiseExceptionOnSendError : Boolean = False;
  222. Const aLogFileName : string = '') : Integer;
  223. Var
  224. Cmd : string;
  225. begin
  226. Result := 0;
  227. if ADebugServerExe<>'' then
  228. DebugServerExe:=ADebugServerExe;
  229. RaiseExceptionOnSendError:=ARaiseExceptionOnSendError;
  230. Cmd := DebugServerExe;
  231. if Cmd='' then
  232. Cmd := DefaultDebugServer;
  233. With TProcess.Create(Nil) do
  234. begin
  235. Try
  236. Executable := Cmd;
  237. If aLogFileName<>'' Then
  238. Parameters.Add(aLogFileName);
  239. Execute;
  240. Result := ProcessID;
  241. Except On E: Exception do
  242. begin
  243. E.Message:=Format(SServerStartFailed,[cmd,E.Message]);
  244. Free;
  245. raise;
  246. end;
  247. end;
  248. Free;
  249. end;
  250. end;
  251. procedure FreeDebugClient;
  252. Var
  253. msg : TDebugMessage;
  254. begin
  255. try
  256. If (DebugClient<>Nil) and
  257. (DebugClient.ServerRunning) then
  258. begin
  259. Msg.MsgType:=lctStop;
  260. Msg.MsgTimeStamp:=Now;
  261. Msg.Msg:=Format(SProcessID,[GetProcessID, ApplicationName, GetProcessID]);
  262. WriteMessage(Msg);
  263. end;
  264. if assigned(MsgBuffer) then FreeAndNil(MsgBuffer);
  265. if assigned(DebugClient) then FreeAndNil(DebugClient);
  266. except
  267. end;
  268. end;
  269. Function InitDebugClient : Boolean;
  270. begin
  271. Result:=InitDebugClient(False,'',RaiseExceptionOnSendError,'');
  272. end;
  273. function InitDebugClient(const ShowPID: Boolean;
  274. const ADebugServerExe : String = ''; // Start the debug server and return its ProcessID.
  275. const ARaiseExceptionOnSendError : Boolean = False;
  276. const ServerLogFilename: String = ''): Boolean;
  277. Var
  278. msg : TDebugMessage;
  279. I : Integer;
  280. begin
  281. Result := False;
  282. AlwaysDisplayPID:= ShowPID;
  283. DebugClient:=TSimpleIPCClient.Create(Nil);
  284. DebugClient.ServerID:=DebugServerID;
  285. If not DebugClient.ServerRunning then
  286. begin
  287. ServerID:=StartDebugServer(ADebugServerExe,ARaiseExceptionOnSendError,ServerLogFileName);
  288. if ServerID = 0 then
  289. begin
  290. DebugDisabled := True;
  291. FreeAndNil(DebugClient);
  292. Exit;
  293. end
  294. else
  295. DebugDisabled := False;
  296. I:=0;
  297. While (I<100) and not DebugClient.ServerRunning do
  298. begin
  299. Inc(I);
  300. Sleep(100);
  301. end;
  302. end;
  303. try
  304. DebugClient.Connect;
  305. except
  306. FreeAndNil(DebugClient);
  307. DebugDisabled:=True;
  308. Raise;
  309. end;
  310. MsgBuffer:=TMemoryStream.Create;
  311. Msg.MsgType:=lctIdentify;
  312. Msg.MsgTimeStamp:=Now;
  313. Msg.Msg:=Format(SProcessID,[GetProcessID, ApplicationName, GetProcessID]);
  314. WriteMessage(Msg);
  315. Result := True;
  316. end;
  317. Finalization
  318. FreeDebugClient;
  319. end.