NO MFC - 使用 .log 调试程序

MFC实现log日志信息显示,程序运行状态显示 前言 在界面程序运行过程中,很多时候我们都希望知道程序运行到哪一步,或者程序的中间输出结果希望打印到界面上,这就是log信息显示功能。 控件:Edit Control 控件属性设置 这里使用Edit Control显示log信息。 首先,拖拽一个Edit Control控件以及一个Text Control控件到界面上,对其属性进行一些修改,其中Mutiline是最重要的,否则Edit Control不支持多行,会直接忽视换行符。 为控件添加变量 之后需要为新建的Edit Control控件关联两个变量。 阅读详情


   我一直就想自己开发一个使用 .log 来调试程序的类了,前几天搞了一个出来,该类能够用于 VC 和 BCB 中。
   以下是程序运行的效果,在我调试一个服务程序的时候,生成一个 .log 日志文件, 记录了一些与启动和关闭服务过程相关的信息...

[Source Path & FileName:]  E:/microsoft/桌面/Simple_Service_02/#Simple_Service.log
[9844796] Record Start at  Date: 2003.08.06  &  Time: 16:19:25 .

[9844796] _Simple_Service_07 WinMain start
[9844796] WinNT 系统可用!
[9844796] CommandLine by following.
[9844796] E:/microsoft/桌面/Simple_Service_02/#Simple_Service.exe

[9844796] CurrentDirectory by following.
[9844796] D:/WINNT/system32

[9844796] Current Module FileName by following.
[9844796] E:/microsoft/桌面/Simple_Service_02/#Simple_Service.exe

[9844796] 重新设置了当前目录的位置
[9844796] CurrentDirectory by following.
[9844796] E:/microsoft/桌面/Simple_Service_02

[9844796] NumArgsCount =  0x1 (1)
[9844796] 命令行参数  0x0 (0)
[9844796] E:/microsoft/桌面/Simple_Service_02/#Simple_Service.exe


[9844796] We now Running in service_main.
[9844796] Success to RegisterServiceCtrlHandler
[9844796] 创建了同步对象

[9845000] 等待同步信号超时
[9845000] SetServiceStatus 成功!

[9845500] Progress =  0x1 (1)

[9846000] Progress =  0x15 (21)

[9846500] Progress =  0x29 (41)

[9847000] Progress =  0x3D (61)

[9847500] Progress =  0x51 (81)

[9848000] Progress =  0x65 (101)

[9848500] Progress =  0x79 (121)
[9848500] SetServiceStatus to SERVICE_RUNNING !

[9849500] Doing Something...

[9849609] Doing Something...

[9849703] Doing Something...

[9849812] Doing Something...

[9849906] Doing Something...

[9850015] Doing Something...


[9850062] Go into service_ctrl Function.

[9850062] recive SERVICE_CONTROL_STOP

[9850109] Doing Something...

[9850218] Doing Something...

[9850265] 已经设置 Service 状态为 SERVICE_STOP_PENDING ,并将同步对象设置为激发状态.

[9850312] 同步对象被触发

[9850312] service_mainCleanup!

[9850312] SetServiceStatus to SERVICE_STOPPED 成功!

[9850765] The Service is now Stoped
[9850765] StartServiceCtrlDispatcher Complete.

[9850765] Record  End  at  Date: 2003.08.06  &  Time: 16:19:31 .


   · 基本流程介绍一下:

      首先是在构造函数中,先取得命令行中的执行文件的来源路径和名称,根据该名生成一个对应的 .log 的文件名(如果已存在就扔到回收站去)。 申请内存,创建文件名(如果重复了,末尾追加 .log 重试),设置可使用标记(active=true)。

      然后是在使用过程中,使用 ::write() 的方法,把你要写入的信息写入到缓冲区 (请小于 512 字节,否则开辟更大的缓冲区,缓冲区满了则写入到 .log 文件)。 使用完了后使用 ::last() 方法在 .log 文件末尾(也是强制缓冲写入硬盘)追加时间日期。

      最后在析构函数中。自然就是三部曲,active=false;  CloseHandle();  和 释放缓冲区

 

    若要使用这个类,请在开头包含类的文件,在所有函数以外定义就是了。如下:

 #include "Runtimelog.cpp"
  RunTimeLog  log; 

    以下是在窗口过程中使用的例子:

LRESULT CALLBACK
    WinProc(HWND hWnd, UINT uMsg,
            WPARAM wParam, LPARAM lParam  )
 {
   char  String[128] = "";
   wsprintf( String, "WinProc with uMst = 0x%x", uMsg );
   log.write(String);

   ····

    最后请记得要调用  ::last() 方法。否则,如果使用 ExitProcess(); 来退出程序的话,我定义的析构函数就不起作用了。

 

    该类在 Bland C++ Builder 中的使用方法大致相同,经我测试通过... 并且 Win98 和 Win2K 也基本可用 (WinXP中未知)。

 

  (声明:该文件可以随便修改、使用 或 转载,但本人不对使用该类造成的任何后果负责):

   不多说了,下面是类的源文件: (全文完 - 2003年03月16日_am: 11时16分)

 

 

// ****************************************************************************
// *******   FileName: RunTimeLog.h   ***************************************
// ****************************************************************************

#ifndef __RunTimeLogInclude
#define __RunTimeLogInclude
//Include Something here

 

 // *******************  Start of include  *****************************
#include <shellapi.h>

typedef class RunTimeLog
{

public:

   RunTimeLog();
   ~RunTimeLog();  // 析构函数
   void last(bool show);
   void last();
   int  showResult(DWORD delay);

   bool  group , nobuff, Lastshow;  // 用于使信息按时间分组

 

private:
  // 关于函数指针的类型声明
 typedef  WINSHELLAPI int  (WINAPI  SHELLFILE) ( LPSHFILEOPSTRUCT );

   bool  active, dolog, nosystime;
   DWORD offset;        // 指出内存使用偏移
   DWORD BuffSize;
   DWORD NumToWrite;
   LPSTR SysTick;
   HANDLE  FileHandle;
   char  * lpBuff;      // 用于申请内存
   char  logfile[512];


  LPSTR  dwNum2Str(DWORD val);

public:

   DWORD  hlstrcpy(LPSTR  Str1, LPSTR Str2, DWORD Len );
   DWORD  hlstrcat(LPSTR  Str, LPSTR Plus, DWORD StrLen, DWORD PlusLen );
   LPSTR  GetDate();
   LPSTR  GetTime();
   LPSTR  GetSysTick(DWORD * len );
   int    write(LPSTR lpStr);
   int    numberwrite(LPSTR lpStr, DWORD val);
   int    WriteLog(void);
   void   msg(LPSTR Str);

 

} RunTimeLog,*PRunTimeLog;
// End of  class  RunTimeLog

//at Include last
#endif //#ifndef __RunTimeLogInclude
// *********************  End of include  ***************************
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////

 

 

 // ****************************************************************************
 // *******   FileName: RunTimeLog.cpp   ***************************************
 // ******************   Version: 1.12   ***************************************
 // ****************************************************************************
 // 声明:该文件可以随便修改、使用 或 转载,但本人不对使用该类造成的任何后果负责
 // 作者:`海风   ************  E-mail:  free77@163.net************************
 // ****************************************************************************
 //  可以在函数内部定义你的类,如下的使用 new 的定义方法。 *********************
 //  RunTimeLog * rtlog = new RunTimeLog;   然后在最后  delete rtlog;  *********
 //  也能使用如下方法定义: RunTimeLog  log;  并最好显式调用 析构函数  *********
 // ****************************************************************************

 // 对外提供的接口 主要是 ::write(""); 用于写入信息到缓冲内存中,
 // 以及 ::last(); 用于最后结束部分,可以向 .log 文件写入缓冲内容
 // 也可以直接调用 ::WriteLog(); 来向 .log 文件写入缓冲内容(如果有的话)。
 // Ver 1.02 新增信息按时间分组功能,使用 group 可以控制是否分组
 // 已修正自动写缓冲到磁盘错误...  ,缓冲换成2048

#include <windows.h>
 #include "RunTimeLog.h"


   // 构造函数和析构函数
  RunTimeLog::RunTimeLog()  // 不带参数构造函数
  {
    nobuff=false;  Lastshow=false;   dolog=false;
    active=false;  nosystime=false;  group = true;

    offset=NULL;    NumToWrite=NULL;
    SysTick=NULL;   FileHandle=NULL;
    lpBuff=NULL;    BuffSize = 2048; // 设置 BuffSize 的大小

    bool   DelOld = false;        // 设定是否要扔掉旧日志
    DWORD  OverWrite = true;     // 设定是否要覆盖旧日志,如果上面没有丢的话
    WORD   ToRecyclebin = false;  // 设定是否把旧日志放到回收站

    OverWrite = OverWrite? CREATE_ALWAYS : CREATE_NEW; // 一个宏定义
    ToRecyclebin = ToRecyclebin ? FOF_ALLOWUNDO | FOF_SILENT | FOF_NOCONFIRMATION : FOF_SILENT | FOF_NOCONFIRMATION;

 

    //·申请可用的内存作缓冲空间,指向 lpBuff, 大小为 BuffSize

    // lpBuff = (char*)HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, BuffSize);
     lpBuff = new char[BuffSize];
    // lpBuff = Buffer;

    if ( lpBuff != NULL )
    {
     //·取得进程文件名,变化成 .log 文件名,查找是否重复了,是则送到回收站
      GetModuleFileName( NULL,lpBuff,BuffSize);
      hlstrcpy(logfile, lpBuff, NULL);
      GetLongPathName( logfile, logfile, 512);  // 如果你在 Win98 中调用该函数,可能会给出短文件名格式
      UINT len = strlen(logfile);
      UINT i = 0;
      // 然后从后面去掉扩展名
      for ( i=len; i>0; i-- )
      { if (logfile[i]=='.') { hlstrcat(logfile, ".log", i, 4); len = len + 3; break; } }

 


     
    // 首先判断文件是否存在
    Loop: // 如果不能一次创建文件成功时用。
    if (( GetFileAttributes( logfile ) == -1 )||(GetLastError()==ERROR_FILE_NOT_FOUND))
       ;// msg("文件不存在");

    else if(DelOld)  // 该处设成 true 则要删除原文件

    {  // 发现文件已经存在了,需要扔到回收站里面去
    SHFILEOPSTRUCTA Fileop;
    LPSHFILEOPSTRUCT lpFileOp = &Fileop;
    memset( lpFileOp, NULL, sizeof(Fileop) );

 

    Fileop.fFlags = ToRecyclebin;
    Fileop.wFunc = FO_DELETE ;
    Fileop.pFrom = logfile;
    lpFileOp->hwnd = NULL;

    //*
    // 关于运行时连接的文件操作方式,定义了 函数的指针
    SHELLFILE * lpSHFileOperation = NULL;  // 函数指针定义
    HMODULE hlib = LoadLibrary( "shell32.dll" );
     if (hlib)
     {  
       lpSHFileOperation = (SHELLFILE *) GetProcAddress( hlib, "SHFileOperation" );
       if ( lpSHFileOperation )
       {
         /*if (*/ lpSHFileOperation(lpFileOp); //msg( "SHFileOperation 执行过程中出现了问题");
       }
       else msg("shell32.dll 中没有这个函数");
       if (! FreeLibrary( hlib )) msg("释放DLL失败");
     }
    else msg("没有 shell32.dll"); //*/

    }  // 扔垃圾完成


    //·创建一个新文件,写入开始记录的时间
     FileHandle = CreateFile( logfile, GENERIC_WRITE, FILE_SHARE_READ, NULL, OverWrite, FILE_ATTRIBUTE_NORMAL, NULL);
    if (FileHandle == INVALID_HANDLE_VALUE)
    {  // 当不能创建新文件的时候尝试增加文件后缀
       if (hlstrcat( logfile, ".log", NULL, 4) < 125)  goto Loop;
       else { msg("CreateFile 执行过程中出现了问题,放弃重试。" ); /*ExitProcess(0);*/}
    }
    else {  // 句柄有效的时候才执行
      SetFilePointer(FileHandle, GetFileSize(FileHandle,NULL), NULL, FILE_BEGIN);  // 设置原始大小

        WriteFile(FileHandle, "[Source Path & FileName:]  ", strlen("[Source Path & FileName:]  "), &NumToWrite, NULL);
        WriteFile(FileHandle, logfile, strlen(logfile), &NumToWrite, NULL);
        /*用于分行*/ WriteFile(FileHandle, "/x0d/x0a", strlen("/x0d/x0a"), &NumToWrite, NULL);

        wsprintf( lpBuff, "Record Start at  Date: %s  &  Time: %s .", GetDate(), GetTime() );

        SysTick = GetSysTick(&NumToWrite);  // 取得系统时间
        WriteFile(FileHandle, SysTick, NumToWrite, &NumToWrite, NULL);

        WriteFile(FileHandle, lpBuff, strlen(lpBuff), &NumToWrite, NULL);

        /*用于分行*/ WriteFile(FileHandle, "/x0d/x0a", strlen("/x0d/x0a"), &NumToWrite, NULL);

      if (!SetEndOfFile(FileHandle)) MessageBox(NULL, "设置结尾不成功", "??", MB_OK|MB_TOPMOST); // 写完数据置尾

      // CloseHandle( FileHandle );    FileHandle = INVALID_HANDLE_VALUE; // 收尾关闭句柄
       lpBuff[0] = NULL;
       } // 完成句柄有效时的执行
       active = true; dolog = true;
       }
     else active = false;
     nosystime = false;
     write("");

    return;
   }

  // ******************************************************************
    void RunTimeLog::last() { last(0); }
    void RunTimeLog::last(bool show)
   {
     group = false;

    // 写入结束记录的时间
     if (active)
     {
       WriteLog();
     if (lpBuff != NULL)
     {
     if (FileHandle == INVALID_HANDLE_VALUE) { msg("最后 WriteLog 过程中出现了问题"); ExitProcess(0);}
     else 
     {  // 句柄有效的时候才执行

     /*用于分行*/ WriteFile(FileHandle, "/x0d/x0a", strlen("/x0d/x0a"), &NumToWrite, NULL);
     SysTick = GetSysTick(&NumToWrite);  // 取得系统时间
     WriteFile(FileHandle, SysTick, NumToWrite, &NumToWrite, NULL);

     wsprintf( lpBuff, "Record  End  at  Date: %s  &  Time: %s .", GetDate(), GetTime() );
     WriteFile(FileHandle, lpBuff, strlen(lpBuff), &NumToWrite, NULL);

     /*用于分行*/ WriteFile(FileHandle, "/x0d/x0a", strlen("/x0d/x0a"), &NumToWrite, NULL);

     if (!SetEndOfFile(FileHandle)) msg( "设置结尾不成功"); // 写完数据置尾

     CloseHandle( FileHandle );    FileHandle = INVALID_HANDLE_VALUE; // 收尾关闭句柄
     lpBuff[0] = NULL;
      if (show) showResult(0);
     } // 完成句柄有效时的执行
     } // End of if (lpBuff != NULL)
      active = false; // dolog = false;
     } // End of if (active)      
     return ;
   }
  // ******************************************************************
   RunTimeLog::~RunTimeLog()  // 析构函数
      {
    //  msg("析构中...");

      last(Lastshow);
      // msg("准备释放内存");
      // HeapFree( GetProcessHeap(), NULL, lpBuff); lpBuff = NULL;
      dolog = false;  Sleep(100);
      delete lpBuff; lpBuff = NULL; dolog = false;

      return; 
      }  // End of ~RunTimeLog()
   // End of  构造函数和析构函数

 //***************************************************************

   // 数字 到 字符串 的输出,返回值是一个字符串的指针
  // 不存在不成功的情况,亦不处理负数
  // 第一个参数是你要转换的数字,第二个参数是指定转换的最小长度
  // 第三个参数是字符串,把第一个字符作为占位符,可以为NULL,则采用默认

  LPSTR  RunTimeLog::dwNum2Str(DWORD val)
  {
    static char NumStr[18]="";
//    _ultoa( val, NumStr, 10 );
    wsprintf( NumStr, "%lu", val );
    return NumStr;
  }
  /*/
  LPSTR  dwNum2Str(DWORD val, DWORD width, LPSTR lpstr)
     {
       // 以下是数字到 ascii 对照表
       static char num[11]={48,49,50,51,52,53,54,55,56,57,48};
       static DWORD base[11]=   // 以下是构建一个基数表
          { 0, 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
       static char array[16];  // 用来装载字符串的
       // array[0]=0;  //截断字符串
       DWORD index, i, st;
       index=0; st = 0;

       if (width>10) width=10; //  width 不能大于 10

       // 根据第三个参数来改变占位符的值
       if (lpstr&&lstrlen(lpstr))
          num[10]=lpstr[0];
         else num[10]=num[0];

       // 为了防止零作为被除数
       if (val==0)
          {
            for ( i=width; i>1; i-- )  // 完成占位
               { array[index]=num[10];  index++; }
            array[index]=num[0]; array[index+1]=0; return array;
          } // End of if (val==0)

       // 正常操作的开始
       for ( i=10; i>0; i--)  // 这是有占位要求的循环
          {
           if (!st)
              {
               if (val>=base[i])
                  { st=1; i++; continue; }
                else if (!(i>width))  // 准备填写占位符
                   { array[index]=num[10];  index++; }
              }
          else
             { // { array[index]=num[val/base[i]];  val = val % base[i];  index++; msg(array); }
              _asm {
                mov  eax,  val      // 这是被除数
                mov  edx,  i      // 注意,数组下标一定要是寄存器
                sal  edx,  2      // 右移两位等于 i*4
                mov  ebx,  base[edx]
                xor  edx,  edx      // 做除法前一定要清空 edx
                div  ebx      // 做除法: 现在 dx 里面有余数,ax 里面则是商
                mov  val,  edx      // 保存余数
                add  eax,  30h      // 调整为 ASCii 码
                mov  ecx,  index
                mov  byte  ptr array[ecx], al    // 保存最后字符结果到数组
                add  index, 1       // 相当于 index ++
                 }  // End of _asm {
             }
          }  //End of for (DWORD i=...
       array[index]=0; // 最后截断字符串
       return array;
     }  // */
   // ******************************************************************

  //***** 自定义函数 ***********************************
  DWORD  RunTimeLog::hlstrcpy(LPSTR  Str1, LPSTR Str2, DWORD Len )
     {
       DWORD ii = 0;
       if (Len == 0)   // 如果没有给出长度,则自动算出长度
          { while(!(Str2[Len] == 0)) Len++; }
       if (! Len)        return 0;
       if (Str1==Str2)   return Len;
       if (Str1<Str2)
          { ii = 0;
            for ( ii; ii<Len; ii++ ) { Str1[ii] = Str2[ii]; } // 复制字符串
          }
       else{ ii = Len - 1;
             for ( ii; ii>0; ii-- )
                { Str1[ii] = Str2[ii]; }
                  Str1[0] = Str2[0];  // 补做一个循环
          }
       Str1[Len] = 0;  // 设置新字符串结尾
       return Len;
     }
   //******************************************************************
  DWORD  RunTimeLog::hlstrcat(LPSTR  Str, LPSTR Plus, DWORD StrLen, DWORD PlusLen )
     {
       if (StrLen == 0)   // 如果没有给出长度,则自动算出长度
       {   while(!(Str[StrLen] == 0)) StrLen++;   }
       if (PlusLen == 0)   // 如果没有给出长度,则自动算出长度
       {   while(!(Plus[PlusLen] == 0)) PlusLen++;   }
       DWORD ii = 0;  // 定义复制 plus 索引为 0
       for ( ii; ii < PlusLen; ii++ )  // 复制字符串
       {  Str[StrLen] = Plus[ii];   StrLen++;  }
          Str[StrLen] = 0;  // 设置新字符串结尾
       return StrLen;
     }

  //*******************************************************************
   LPSTR RunTimeLog::GetDate()
      {
        static char Date[15]; Date[0]=NULL;
        SYSTEMTIME SystemTime;
        GetLocalTime( &SystemTime );
        wsprintf(Date, "%d.%d.%d", SystemTime.wYear, SystemTime.wMonth, SystemTime.wDay);
        return Date;
      }
  //*******************************************************************
   LPSTR RunTimeLog::GetTime()
      {
        static char Time[15]; Time[0]=NULL;
        SYSTEMTIME SystemTime;
        GetLocalTime( &SystemTime );
        wsprintf(Time, "%d:%d:%d", SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond);
        return Time;
      }
  //*******************************************************************
  LPSTR RunTimeLog::GetSysTick(DWORD * len )
  {    //『御风而行』
       static char tick[20]="";
       static DWORD dwPasTick=GetTickCount(), dwCurTick=GetTickCount();
       dwPasTick = dwCurTick;
       dwCurTick = GetTickCount();
       tick[0]=NULL;  // 清除原来的字符串
       if ((dwPasTick != dwCurTick) && group ) lstrcat( tick, "/x0d/x0a" ); // 如果前后时间不一致,则插入分行
        lstrcat( tick, "[" ); // 预插入行首
       // lstrcat( tick, dwNum2Str(dwCurTick, NULL, NULL) );
        lstrcat( tick, dwNum2Str(dwCurTick) );
       *len = hlstrcat( tick, "] ", NULL, 2 );  // 补上结尾
       return tick;
     }
   // ******************************************************************

   int RunTimeLog::write(LPSTR lpStr)  // 重载为一个参数的函数
   {   DWORD len,lenth,TickLen;
       LPSTR temp = NULL;
       len = strlen(lpStr);
       if (len&&(!nosystime)) { temp = GetSysTick(&NumToWrite);  TickLen = NumToWrite; }
       else { TickLen = 0; }
       lenth = len + TickLen + 2;


       if ( lenth > BuffSize )
       { // msg("长度太大,无法写入缓冲");
          if (FileHandle != INVALID_HANDLE_VALUE)
          { 
             WriteFile(FileHandle, temp, TickLen, &NumToWrite, NULL); // 写入系统时间
             WriteFile(FileHandle, lpStr, len, &NumToWrite, NULL);    // 写入字符串内容
             /*用于分行*/ WriteFile(FileHandle, "/x0d/x0a", strlen("/x0d/x0a"), &NumToWrite, NULL);
             SetEndOfFile(FileHandle);
             return 1;
          } 
          return 0; // len 大于 BuffSize 而且文件句柄不可用
       } // End of if ( len > BuffSize )

       if (  (offset + lenth) > BuffSize) WriteLog();

       if (active) // 如果是活跃的才提供写入
       {   while (!dolog);   dolog = false;

           if (TickLen) offset = hlstrcat( lpBuff, temp, offset, TickLen );     // 写系统时间

           if (len) offset = hlstrcat( lpBuff, lpStr, offset, len );        // 写入字符串
           offset = hlstrcat( lpBuff, "/x0d/x0a", offset, NULL );  // 追加分行
           dolog = true;
           if (nobuff) WriteLog();
           return 1;
       }

       return 0;
   }
  // ******************************************************************
   int RunTimeLog::WriteLog(void)
   {
       if (active && offset)
       {
       while (!dolog);
       dolog = false;


       if (FileHandle == INVALID_HANDLE_VALUE) { msg("最后 写入 LogFile 过程中出现问题" ); return 0;}
       else
       {  // 句柄有效的时候才执行
         WriteFile(FileHandle, lpBuff, offset, &NumToWrite, NULL);
         offset = 0; // 写入完以后记得要置 0
         lpBuff[0]=NULL; // lpBuff[1]=NULL;

         if (!SetEndOfFile(FileHandle)) msg( "设置结尾不成功"); // 写完数据置尾

       } // 完成句柄有效时的执行
        dolog = true;
           return 1;
       }
       else return 0;
   }
  // ******************************************************************
   void   RunTimeLog::msg(LPSTR Str) { MessageBox( NULL, Str, "??", MB_OK|MB_TOPMOST|MB_SETFOREGROUND );  return; }

  // ******************************************************************
   int   RunTimeLog::numberwrite(LPSTR lpStr, DWORD val)
   {
       char Temp[30];
       wsprintf( Temp, " 0x%X (%lu)", val, val );
       write(lpStr);
       if (offset) offset = offset -2;
       else { SetEndOfFile(FileHandle); SetFilePointer(FileHandle, GetFileSize(FileHandle,NULL)-2, NULL, FILE_BEGIN); }
       nosystime = true;
       write(Temp);
       nosystime = false;
       return 1L;
   }
   // ******************************************************************
   int   RunTimeLog::showResult(DWORD delay)
   {
      if (active)
      {
      WriteLog();
      while (!dolog);  dolog = false;

      GetWindowsDirectory( lpBuff, BuffSize);
      DWORD ExecLen = hlstrcat( lpBuff, "//notepad.exe /"", NULL, NULL );
      ExecLen = hlstrcat( lpBuff, logfile, ExecLen, NULL );
      ExecLen = hlstrcat( lpBuff, "/"", NULL, NULL );


      PROCESS_INFORMATION pi;
      STARTUPINFO         si;
      memset(&si, 0, sizeof(si));
      si.cb           = sizeof(si);
      si.dwFlags      = STARTF_USESHOWWINDOW;
      si.wShowWindow  = SW_MAXIMIZE; // SW_SHOW;

      CreateProcess( NULL, lpBuff, NULL, NULL, false, 0, NULL, NULL, &si, &pi);


      lpBuff[0] = NULL;
      if(delay>100000) delay = 150;
      if (delay) Sleep(delay);
      dolog = true;
      return 1L;
      }  else return 0L;
   }


 // *************************** End of File *****************************

 

MFC 打印日志 阅读详情

相关推荐

MFC CEdit打印日志

void CLOG_DEBUG(char *str, ...) { CEdit *e = s_log_handle; CString strTxt; char szLog[4096 * 100] = { 0 }; if (e == NULL) return; if (g_enable_pci_server_log < 0) return; va_list arg_ptr = NULL; va_start(arg_ptr, str); vsprintf(szLog, str

我不是码农的博客~~~ 700

用MFC的Edit控件显示日志

1、添加控件,设置控件属性:勾选Multiline、Want return 、Read-only 2、class wizard 添加控件成员变量 CEdit m_logctrl 3、添加日志:添加CString成员 CString m_Log 在事件响应函数中,添加日志的代码,并将添加到日志末尾最新的内容在控件的底部更新显示: UpdateData(TRUE); m_log +=

lonelyrains的专栏 1万+

C++日志记录实践:VC6 MFC环境下CLog类设计

本文还有配套的精品资源,点击获取 简介:本文深入探讨了在VC++和VC6 MFC框架下,如何实现一个C++的日志记录类。日志类的核心功能包括设置不同的日志等级、添加时间戳、格式化输出以及输出到多种目标。通过创建一个名为 CLog 的类,并详细描述了其成员函数的设计与实现。例如, WriteLog 函数负责将日志等级和消息格式化后写入到文件,而 ...

weixin_36197669的博客 1684

NO MFC - 使用 .log 调试程序 (转)

NO MFC - 使用 .log 调试程序 (转)[@more@] 我一直就想自己开发一个使用 .log 来调试程序的类了,前几天搞了一个出来,该类能够用于 vc 和 BCB 中。 以下是程序运行的效果,在我调试一个服务程序...

cuiji1279的博客 106

log打印代码,直接打印log到文件中。非常灵活好用

log打印代码,直接打印log到文件中。非常灵活好用,对于调试代码非常有用

自己写的MFC程序用到的LOG类

一个写Log日志的类,简单高效,多线程,有临界区保护,支持按日期,时间写日志,对新手

MFC中调试过程中查看输出信息

在调试MFC程序时,我们经常需要查看特定位置变量的输出值。或者在某特定条件执行时,给出一个输出标识。 一般来说,有3种方法: 1) 调用TRACE(LPCTSTR lpszFormat, ...)函数     在MFC中使用TRACE函数来打印输出结果却是非常方便,和在控制台程序中使用printf函数的使用方法和效果类似。不过有几点       需要注意:一,TRACE函数的输出是在Out

BruceZong的专栏 7025

ProgramLog记录日志类,每天生成一个记事本

ProgramLog记录日志类,每天生成一个记事本

MFC程序如何使用printf输出调试信息

设想一下,我们在win32控制台下写了个在命令行运行的程序库,图方便直接用printf输出log来进行调试,但后来集成库时使用了MFC之类的窗体程序,于是原先用printf输出的log信息都看不到了,但是我们又需要查看这些log信息,甚至最好能输出到文件来方便进行分析,如何处理? 首先,我们考虑将log信息输出到控制台上,按照以下步骤操作。 1,添加头文件 #include

xhhjin的专栏 2万+

c++打包上传log文件

c++打包上传log文件,已表单形式上传服务器,用到zlib库,学习

MFC工程项目中打印log日志

在一个MFC小项目中,展示了如何打印log日志的方法,主要是为了方便刚接触MFC项目的人学习参考

MFC 自己写的写日志文件功能

实现功能:每次写入内容到log文件中,且都是从后面追加的,如果文件大小超过500k,则清空内容重新写入 1.新建MFC工程 1)添加互斥文件 添加semaphoreclass.h文件 里面加入: #ifndef _SEMAPHORECLASS_H_ #define _SEMAPHORECLASS_H_ class CSemaphoreClass { public: CSema

kevin的博客 6204

2022-2028年中国美容仪行业发展战略规划及投资机会预测报告

报告类型:产业研究 报告格式:电子版、纸介版 出品单位:智研咨询-产业信息网 美容仪是一种根据人体生理机能进行调节改善身体和面部的机器,它按照功能来说有美白、嫩肤、祛斑、祛皱、脱毛、减肥等多种,按照名称来说有超声波导入、光子嫩肤、高周波电疗、RF 电波拉皮、电子祛斑点痣、E 光永久脱毛嫩肤、贾法尼营养导入导出等。 智研咨询发布的《2022-2028年中国美容仪行业发展战略规划及投资机会预测报告》共十七章。首先介绍了中国美容仪行业市场发展环境、美容仪整体运行态势等,接着分析了中...

kt346的博客 468

No MFC (我) 的自白

      请不要误会,我的名字不叫 "No MFC" 。     写这 "自白" 缘于昨日一网友 chinaeagle 问我,写 No MFC 系列的目的何在?  我竟一时间答不上来,我后来想了很多。     起初写作的时候,因为我所举的源程序在开头都会预先定义  #define WIN32_LEAN_AND_MEAN  。使不包含和 MFC 有关的预编译,所以取名 No MFC 编

1058

WPS Office 2019 For Linux二次开发全流程:从源码下载到Demo运行

本文详细介绍了在Linux环境下进行WPS Office 2019 C++二次开发的全流程,涵盖从开发环境准备、源码获取、核心依赖(Qt与WPS)安装配置,到最终编译运行官方Demo的完整步骤。文章重点解析了环境搭建中的常见问题与解决方案,旨在帮助开发者快速上手WPS二次开发。

weixin_29001423的博客 388

深入浅出ISP:用RKISP2.x Tuner工具理解AWB、AE、HDR等核心模块的实战调参

本文深入解析RKISP2.x Tuner工具在ISP图像处理中的实战应用,重点探讨AWB、AE、HDR等核心模块的调参技巧。通过环境搭建、调试工具使用和实际案例,帮助开发者掌握如何在不同光照条件下优化图像质量,实现精准的白平衡、曝光控制和动态范围处理。

weixin_26802933的博客 487

巧用log调试程序

<!--google_ad_client = "pub-2947489232296736";/* 728x15, 创建于 08-4-23MSDN */google_ad_slot = "3624277373";google_ad_width = 728;google_ad_height = 15;//--><script type="text/javascript"

zgqtxwd的专栏 558

爬虫实战:抖音视频搜索数据爬虫开发实战(附完整Python源码)

【代码】抖音视频搜索数据爬虫开发实战(附完整Python源码)

weixin_61226361的博客 3596
上一篇: 关于 Service 设计初步(MSDN节选翻译)
下一篇: Win2K 服务程序的源码(框架而已)
temp77
博客等级 码龄24年 21粉丝 21原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值