我处对TCnDebugger.InternalOutputMsg做以下调整,这样可以在没有安装查看器的情况下,输入到文件,这样可以在普通用户使用时,作为跟踪器使用,强烈希望管理员能调整。

或者有更好方法也行。。。
procedure TCnDebugger.InternalOutputMsg(const AMsg: AnsiString; Size: Integer;
  const ATag: AnsiString; ALevel, AIndent: Integer; AType: TCnMsgType;
  ThreadID: DWORD; CPUPeriod: Int64);
var
  TagLen, MsgLen: Integer;
  MsgDesc: TCnMsgDesc;
  FChannelReady: Boolean;
  procedure GenerateMsgDesc;
  begin
    // 进行具体的组装工作
    MsgLen := Size;
    if MsgLen > CnMaxMsgLength then
      MsgLen := CnMaxMsgLength;
    TagLen := Length(ATag);
    if TagLen > CnMaxTagLength then
      TagLen := CnMaxTagLength;
    FillChar(MsgDesc, SizeOf(MsgDesc), 0);
    MsgDesc.Annex.Level := ALevel;
    MsgDesc.Annex.Indent := AIndent;
    MsgDesc.Annex.ProcessId := GetCurrentProcessId;
    MsgDesc.Annex.ThreadId := ThreadID;
    MsgDesc.Annex.MsgType := Ord(AType);
    MsgDesc.Annex.TimeStampType := Ord(TimeStampType);
    case TimeStampType of
      ttDateTime: MsgDesc.Annex.MsgDateTime := Date + Time;
      ttTickCount: MsgDesc.Annex.MsgTickCount := GetTickCount;
      ttCPUPeriod: MsgDesc.Annex.MsgCPUPeriod := GetCPUPeriod;
    else
      MsgDesc.Annex.MsgCPUPeriod := 0; // 设为全 0
    end;
    // TimeMarkStop 时所耗 CPU 时钟周期数
    MsgDesc.Annex.MsgCPInterval := CPUPeriod;
    CopyMemory(@(MsgDesc.Annex.Tag), Pointer(ATag), TagLen);
    CopyMemory(@(MsgDesc.Msg), Pointer(AMsg), MsgLen);
    MsgLen := MsgLen + SizeOf(MsgDesc.Annex) + SizeOf(DWORD);
    MsgDesc.Length := MsgLen;
  end;
begin
  if FAutoStart and not FIgnoreViewer and not FViewerAutoStartCalled then
  begin
    StartDebugViewer;
    FViewerAutoStartCalled := True;
  end;
  Inc(FMessageCount);
  if not CheckEnabled then Exit;
  FChannelReady := FChannel.CheckReady;
  if (not FChannelReady) and (not FDumpToFile) then Exit;
  GenerateMsgDesc;
  if FChannelReady then
  begin
    if FChannel.CheckFilterChanged then
      FChannel.RefreshFilter(FFilter);
    if CheckFiltered(string(ATag), ALevel, AType) then
      InternalOutput(MsgDesc, MsgLen);
  end;
  // 同时 DumpToFile
  if FDumpToFile and not FIgnoreViewer and (FDumpFile <> nil) then
  begin
    if not FAfterFirstWrite then // 第一回写时需要判断是否重写
    begin
      if FUseAppend then
        FDumpFile.Seek(0, soFromEnd)
      else
      begin
        FDumpFile.Size := 0;
        FDumpFile.Seek(0, soFromBeginning);
      end;
      FAfterFirstWrite := True; // 后续写就无需判断了
    end;
   
    FDumpFile.Write(MsgDesc, MsgLen);
  end;
end;
[
 本帖最后由 jAmEs_ 于 2009-12-24 16:30 编辑 ]