dbugintf.pp 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  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. unit dbugintf;
  15. interface
  16. uses dbugmsg;
  17. Type
  18. TDebugLevel = (dlInformation,dlWarning,dlError);
  19. TErrorLevel = Array[TDebugLevel] of integer;
  20. procedure SendBoolean(const Identifier: string; const Value: Boolean);
  21. procedure SendDateTime(const Identifier: string; const Value: TDateTime);
  22. procedure SendInteger(const Identifier: string; const Value: Integer; HexNotation: Boolean = False);
  23. procedure SendPointer(const Identifier: string; const Value: Pointer);
  24. procedure SendDebugEx(const Msg: string; MType: TDebugLevel);
  25. procedure SendDebug(const Msg: string);
  26. procedure SendMethodEnter(const MethodName: string);
  27. procedure SendMethodExit(const MethodName: string);
  28. procedure SendSeparator;
  29. procedure SendDebugFmt(const Msg: string; const Args: array of const);
  30. procedure SendDebugFmtEx(const Msg: string; const Args: array of const; MType: TDebugLevel);
  31. procedure SetDebuggingEnabled(const AValue : boolean);
  32. function GetDebuggingEnabled : Boolean;
  33. { low-level routines }
  34. Function StartDebugServer(const aLogFilename : String = '') : integer;
  35. Function InitDebugClient : Boolean;
  36. function InitDebugClient(const ShowPID: Boolean; const ServerLogFilename: String = ''): Boolean;
  37. procedure FreeDebugClient;
  38. ResourceString
  39. SProcessID = '%d Process %s (PID=%d)';
  40. SEntering = '> Entering ';
  41. SExiting = '< Exiting ';
  42. SSeparator = '>-=-=-=-=-=-=-=-=-=-=-=-=-=-=-<';
  43. SServerStartFailed = 'Failed to start debugserver. (%s)';
  44. Var
  45. DebugServerExe : String = ''; { We can override this global var. in our compiled IPC client, with DefaultDebugServer a.k.a. dbugmsg.DebugServerID, or something else }
  46. 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" }
  47. SendError : String = '';
  48. implementation
  49. Uses
  50. SysUtils, classes, process, simpleipc, strutils;
  51. Const
  52. DmtInformation = lctInformation;
  53. DmtWarning = lctWarning;
  54. DmtError = lctError;
  55. ErrorLevel : TErrorLevel
  56. = (dmtInformation,dmtWarning,dmtError);
  57. IndentChars = 2;
  58. var
  59. DebugClient : TSimpleIPCClient = nil;
  60. MsgBuffer : TMemoryStream = Nil;
  61. AlwaysDisplayPID : Boolean = False;
  62. ServerID : Integer;
  63. DebugDisabled : Boolean = False;
  64. Indent : Integer = 0;
  65. Procedure WriteMessage(Const Msg : TDebugMessage);
  66. begin
  67. MsgBuffer.Seek(0,soFrombeginning);
  68. WriteDebugMessageToStream(MsgBuffer,Msg);
  69. DebugClient.SendMessage(mtUnknown,MsgBuffer);
  70. end;
  71. procedure SendDebugMessage(Var Msg : TDebugMessage);
  72. begin
  73. if DebugDisabled then exit;
  74. try
  75. If (DebugClient=Nil) then
  76. if InitDebugClient = false then exit;
  77. if (Indent>0) then
  78. Msg.Msg:=StringOfChar(' ',Indent)+Msg.Msg;
  79. WriteMessage(Msg);
  80. except
  81. On E : Exception do
  82. SendError:=E.Message;
  83. end;
  84. end;
  85. procedure SendBoolean(const Identifier: string; const Value: Boolean);
  86. Const
  87. Booleans : Array[Boolean] of string = ('False','True');
  88. begin
  89. SendDebugFmt('%s = %s',[Identifier,Booleans[value]]);
  90. end;
  91. procedure SendDateTime(const Identifier: string; const Value: TDateTime);
  92. begin
  93. SendDebugFmt('%s = %s',[Identifier,DateTimeToStr(Value)]);
  94. end;
  95. procedure SendInteger(const Identifier: string; const Value: Integer; HexNotation: Boolean = False);
  96. Const
  97. Msgs : Array[Boolean] of string = ('%s = %d','%s = %x');
  98. begin
  99. SendDebugFmt(Msgs[HexNotation],[Identifier,Value]);
  100. end;
  101. procedure SendPointer(const Identifier: string; const Value: Pointer);
  102. begin
  103. SendDebugFmt('%s = %p',[Identifier,Value]);
  104. end;
  105. procedure SendDebugEx(const Msg: string; MType: TDebugLevel);
  106. Var
  107. Mesg : TDebugMessage;
  108. begin
  109. Mesg.MsgTimeStamp:=Now;
  110. Mesg.MsgType:=ErrorLevel[MTYpe];
  111. if AlwaysDisplayPID then
  112. Mesg.Msg:=IntToStr(GetProcessID)+' '+Msg
  113. else
  114. Mesg.Msg:=Msg;
  115. SendDebugMessage(Mesg);
  116. end;
  117. procedure SendDebug(const Msg: string);
  118. Var
  119. Mesg : TDebugMessage;
  120. begin
  121. Mesg.MsgTimeStamp:=Now;
  122. Mesg.MsgType:=dmtInformation;
  123. if AlwaysDisplayPID then
  124. Mesg.Msg:=IntToStr(GetProcessID)+' '+Msg
  125. else
  126. Mesg.Msg:=Msg;
  127. SendDebugMessage(Mesg);
  128. end;
  129. procedure SendMethodEnter(const MethodName: string);
  130. begin
  131. SendDebug(SEntering+MethodName);
  132. inc(Indent,IndentChars);
  133. end;
  134. procedure SendMethodExit(const MethodName: string);
  135. begin
  136. Dec(Indent,IndentChars);
  137. If (Indent<0) then
  138. Indent:=0;
  139. SendDebug(SExiting+MethodName);
  140. end;
  141. procedure SendSeparator;
  142. begin
  143. SendDebug(SSeparator);
  144. end;
  145. procedure SendDebugFmt(const Msg: string; const Args: array of const);
  146. Var
  147. Mesg : TDebugMessage;
  148. begin
  149. Mesg.MsgTimeStamp:=Now;
  150. Mesg.MsgType:=dmtInformation;
  151. if AlwaysDisplayPID then
  152. Mesg.Msg:=IntToStr(GetProcessID)+' '+Format(Msg,Args)
  153. else
  154. Mesg.Msg:=Format(Msg,Args);
  155. SendDebugMessage(Mesg);
  156. end;
  157. procedure SendDebugFmtEx(const Msg: string; const Args: array of const; MType: TDebugLevel);
  158. Var
  159. Mesg : TDebugMessage;
  160. begin
  161. Mesg.MsgTimeStamp:=Now;
  162. Mesg.MsgType:=ErrorLevel[mType];
  163. if AlwaysDisplayPID then
  164. Mesg.Msg:=IntToStr(GetProcessID)+' '+Format(Msg,Args)
  165. else
  166. Mesg.Msg:=Format(Msg,Args);
  167. SendDebugMessage(Mesg);
  168. end;
  169. procedure SetDebuggingEnabled(const AValue: boolean);
  170. begin
  171. DebugDisabled := not AValue;
  172. end;
  173. function GetDebuggingEnabled: Boolean;
  174. begin
  175. Result := not DebugDisabled;
  176. end;
  177. function StartDebugServer(Const aLogFileName : string = '') : Integer;
  178. Var
  179. Cmd : string;
  180. begin
  181. Cmd := DebugServerExe;
  182. if Cmd='' then
  183. Cmd := DefaultDebugServer;
  184. With TProcess.Create(Nil) do
  185. begin
  186. Try
  187. Executable := Cmd;
  188. If aLogFileName<>'' Then
  189. Parameters.Add(aLogFileName);
  190. Execute;
  191. Result := ProcessID;
  192. Except On E: Exception do
  193. begin
  194. SendError := Format(SServerStartFailed,[E.Message]);
  195. Result := 0;
  196. end;
  197. end;
  198. Free;
  199. end;
  200. end;
  201. procedure FreeDebugClient;
  202. Var
  203. msg : TDebugMessage;
  204. begin
  205. try
  206. If (DebugClient<>Nil) and
  207. (DebugClient.ServerRunning) then
  208. begin
  209. Msg.MsgType:=lctStop;
  210. Msg.MsgTimeStamp:=Now;
  211. Msg.Msg:=Format(SProcessID,[GetProcessID, ApplicationName, GetProcessID]);
  212. WriteMessage(Msg);
  213. end;
  214. if assigned(MsgBuffer) then FreeAndNil(MsgBuffer);
  215. if assigned(DebugClient) then FreeAndNil(DebugClient);
  216. except
  217. end;
  218. end;
  219. Function InitDebugClient : Boolean;
  220. begin
  221. InitDebugClient(False,'');
  222. end;
  223. function InitDebugClient(const ShowPID: Boolean; const ServerLogFilename: String = ''): Boolean;
  224. Var
  225. msg : TDebugMessage;
  226. I : Integer;
  227. begin
  228. Result := False;
  229. AlwaysDisplayPID:= ShowPID;
  230. DebugClient:=TSimpleIPCClient.Create(Nil);
  231. DebugClient.ServerID:=DebugServerID;
  232. If not DebugClient.ServerRunning then
  233. begin
  234. ServerID:=StartDebugServer(ServerLogFileName);
  235. if ServerID = 0 then
  236. begin
  237. DebugDisabled := True;
  238. FreeAndNil(DebugClient);
  239. Exit;
  240. end
  241. else
  242. DebugDisabled := False;
  243. I:=0;
  244. While (I<10) and not DebugClient.ServerRunning do
  245. begin
  246. Inc(I);
  247. Sleep(100);
  248. end;
  249. end;
  250. try
  251. DebugClient.Connect;
  252. except
  253. FreeAndNil(DebugClient);
  254. DebugDisabled:=True;
  255. Raise;
  256. end;
  257. MsgBuffer:=TMemoryStream.Create;
  258. Msg.MsgType:=lctIdentify;
  259. Msg.MsgTimeStamp:=Now;
  260. Msg.Msg:=Format(SProcessID,[GetProcessID, ApplicationName, GetProcessID]);
  261. WriteMessage(Msg);
  262. Result := True;
  263. end;
  264. Finalization
  265. FreeDebugClient;
  266. end.