通常在排错的时候都是采用跟踪的方式,大部分情况下是可行的。但是对于多线程程序跟踪的方式是不好用的。这时候采用日志方式是首选。这种方式我从1999年大量设计多线程程序的时候就是我的标准方式。当我把这个方法介绍给一个好友的时候,他居然如获至宝。
本文附件中的logs.pas可以作为一个很好的单元直接引用,然后就可以在程序中的任何地方加上Log.Write(Format(\'%d, %d\', [X, Y])这样的语句来输出日志了。日志在运行文件所在的路径下,直接在运行文件的文件名后面加上.log扩展名。可以用普通的记事本打开看。
不能上传附件
unit Logs;
interface
uses Classes;
type
TLog = class
private
FFileName: string;
function OpenSyncObject: THandle;
public
constructor Create(const AFileName: string);
procedure Write(const Msg: string);
end;
function Log: TLog;
implementation
uses SysUtils, Windows;
{ TLog }
constructor TLog.Create(const AFileName: string);
begin
FFileName := AFIleName;
end;
function TLog.OpenSyncObject: THandle;
var
P, P1: PChar;
begin
P := StrAlloc(Length(FFileName) + 1);
try
StrPCopy(P, FFileName);
P1 := P;
while P1[0] <> #0 do
begin
if P1[0] = \'\\\' then
P1[0] := \'_\';
Inc(P1);
end;
Result := OpenMutex(MUTEX_ALL_ACCESS or SYNCHRONIZE, False, P);
if Result = 0 then
Result := CreateMutex(nil, True, P)
else
WaitForSingleObject(Result, INFINITE);
finally
StrDispose(P);
end;
end;
procedure TLog.Write(const Msg: string);
var
Mutex: THandle;
S: string;
P: PChar;
Stream: TStream;
begin
Mutex := OpenSyncObject;
if FileExists(FFileName) then
Stream := TFileStream.Create(FFileName, fmOpenReadWrite)
else
Stream := TFileStream.Create(FFileName, fmCreate);
S := Format(\'%s:[ProcessID:%d]%s\'#13#10,
[FormatDateTime(\'yyyy-mm-dd hh:nn:ss zzz\', Now),
GetCurrentProcessId, Msg]);
P := StrAlloc(Length(S) + 1);
try
StrPCopy(P, S);
Stream.Seek(0, soFromEnd);
Stream.Write(P^, Length(S));
finally
StrDispose(P);
Stream.Free;
ReleaseMutex(Mutex);
CloseHandle(Mutex);
end;
end;
var
CommonLog: TLog = nil;
function Log: TLog;
begin
if CommonLog = nil then
CommonLog := TLog.Create(Format(\'%s.log\', [ParamStr(0)]));
Result := CommonLog;
end;
initialization
finalization
if CommonLog <> nil then
FreeAndNil(CommonLog);
end.
责任编辑:小草