VC日志类log调试信息输出

功能:输出日志信息logfile.h VC日志类调试信息输出,是编程调试跟踪流程的日志输出好帮手,很有助于程序的排错调试.

1,使用简单方便。只有一个头文件logfile.h include后,直接调用函数即可

2,兼容VC6,VC7(VS系列,VS2008)。 兼容所有VC版本

3,支持源代码文件名及行号的输出。输出日志所在的源文件名和行数。

4,支持多线程应用。CriticalSection控制线程对日志文件的有序访问读写。

5,支持Debug版本输出,Release版本不输出。有效控制调式版本和发布版本的日志输出。

6,支持设置控制台。在MFC程序中,可以增加打开控制台方便查看日志log信息。

7,支持设置文件名。默认文件名为同目录下的log(xxx)YYYY-MM-DD.txt,可以自定义日志文件名。

8,支持设置等级。可以设置需求查看的最小和最大等级。当相等时,查看某一级别的日志。

9,支持按天轮询写日志。默认为一天一个日志文件。

 

以下为代码:

 

/******************************************************************************
//功能: 输出日志信息  logfile.h
// 
//版本号: 3.
//
//作者: 王小丁hixi@21cn.com
//时间: 2013/5/16
******************************************************************************/

/******************************************************************************
 1, 使用简单方便.只有一个头文件logfile.h include后,直接调用函数即可
 2, VC6,VC7(VS2008) 兼容VC版本
 3, 可输出文件名及行号
 4, 支持多线程应用

  例如:
  在cpp源代码文件中只要#include "logfile.h"后,就可以直接调用以下函数输出日志信息

 Logout("I am Logout \r\n");
 Logflout(AT"I am LogfloutAT \r\n");
 Loglevelout(3,"I am Loglevelout");

 CString test = " i am  wangxiaoding!";
 int n = 8;
 Logout("CString = %s \r\n",test);
 Logout("Intnumber = %d \r\n",n);


******************************************************************************/
//防止多次include头文件
#if !defined(AFX_LOGFILE_H__EF4BC4B2_3BB6_46E8_B936_0F3A61E20BF0__INCLUDED_)
#define AFX_LOGFILE_H__EF4BC4B2_3BB6_46E8_B936_0F3A61E20BF0__INCLUDED_

#pragma once

//-----------------------------------------------------------------------------

// Debug版本宏1
#if _DEBUG
#ifndef _FLAG_OUTLOG_ENABLE
#define _FLAG_OUTLOG_ENABLE TRUE
#endif // _FLAG_OUTLOG_ENABLE
#endif // _DEBUG

// 设置控制台宏2
#define  _DEBUGCONSOLE

// 设置文件名宏3
//#define  _SETFILENAME
#ifdef _SETFILENAME
#define  FILENAME "log.txt"
#endif //_SETFILENAME

// 设置等级宏4
#define  _LOGLEVEL
#ifdef _LOGLEVEL
#define MIN_LEVEL 1
#define MAX_LEVEL 5
#endif // _LOGLEVEL


//-----------------------------------------------------------------------------

#include <windows.h>
#include <stdio.h>
#include <stdarg.h>

// 日志输出类,静态版
struct CLog
{   
   
 // 取进程执行文件名称
    static void GetProcessFileName(char* lpName)
    {
        if ( ::GetModuleFileNameA(NULL, lpName, MAX_PATH) > 0)
        {
            char* pBegin = lpName;
            char* pTemp  = lpName;
            while ( *pTemp != 0 )
            {
                if ( *pTemp == '\\' )
                {
                    pBegin = pTemp + 1;
                }
                pTemp++;
            }

            memcpy(lpName, pBegin, strlen(pBegin)+1);
        }

    }

 // 输出到文件
    // lpFile   : 源文件名
    // nLine    : 源文件行号
    // lpFormat : 输出的内容
    static void logout(LPCSTR lpFile, int nLine,LPCSTR lpFormat, ...)
    {
  static CRITICAL_SECTION  m_crit;
  if (m_crit.DebugInfo==NULL)
  ::InitializeCriticalSection(&m_crit);
  /*-----------------------进入临界区(输出信息)------------------------------*/  
  ::EnterCriticalSection(&m_crit);  

        if ( NULL == lpFormat )
            return;

        //当前时间
        SYSTEMTIME st;
        ::GetLocalTime(&st);

        //设置消息头
        const DWORD BufSize = 2048;
        char szMsg[BufSize];

  if (nLine==0)
  { 
   //当nLine==0 时,即Logout("xxx")只打印信息
   sprintf(szMsg, "[%02d:%02d:%02d.%03d]:",
    st.wHour, st.wMinute, st.wSecond,
         st.wMilliseconds);
  }
  else
  {
   //当nLine不等于0 时,即Logflout(AT"xxx")打印文件名行号及信息
   sprintf(szMsg, "[%02d:%02d:%02d.%03d]文件%s第%04d行:",
    st.wHour, st.wMinute, st.wSecond,
           st.wMilliseconds, lpFile, nLine);

  }

  //格式化消息,并完善整条消息
        char* pTemp = szMsg;
        pTemp += strlen(szMsg);
        va_list args;
        va_start(args, lpFormat);   
        wvsprintfA(pTemp,  lpFormat, args);  //vsprintf_s BufSize - strlen(szMsg),
        va_end(args); 

        DWORD dwMsgLen = (DWORD)strlen(szMsg);

        //获取日志文件名
  char szFileName[MAX_PATH];
        char szExeName[MAX_PATH];
        GetProcessFileName(szExeName);
        sprintf(szFileName, "Log(%s)%d-%d-%d.txt", szExeName, //sprintf_s MAX_PATH
                                        st.wYear, st.wMonth, st.wDay);

        // 判断文件名称是否相同,句柄是否有效.
        // 如果不同或无效,则关闭当前文件,创建新文件
        static char   s_szFileName[MAX_PATH] = {0};
        static HANDLE s_hFile = INVALID_HANDLE_VALUE;

  //设置自定义日志文件名
#ifdef _SETFILENAME
  strcpy(szFileName,FILENAME);
#endif //_SETFILENAME

        BOOL bNew = ((strcmp(s_szFileName, szFileName) != 0) || (s_hFile == INVALID_HANDLE_VALUE));
       

#ifdef _DEBUGCONSOLE //控制台输出
  static BOOL bOpenConsole = FALSE;

  if (!bOpenConsole)
  {
   bOpenConsole = ::AllocConsole();
   if (bOpenConsole)
   {
    freopen("CONOUT$","w+t",stdout); 
    freopen("CONIN$","r+t",stdin);
    freopen("CONERR", "w", stderr);
    
    HANDLE handle= GetStdHandle(STD_OUTPUT_HANDLE); 
    SetConsoleTitle("DebugCosole");
    SetConsoleTextAttribute((HANDLE)handle, FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
    
    HWND hwnd=NULL;
    while(NULL==hwnd)
     hwnd=::FindWindow(NULL,(LPCTSTR)"DebugCosole");
    
    HMENU hmenu = ::GetSystemMenu ( hwnd, FALSE );
    DeleteMenu ( hmenu, SC_CLOSE, MF_BYCOMMAND );
   }
  }
#endif //_DEBUGCONSOLE

        printf("%s", szMsg);

        if ( bNew ) // 关闭旧文件,创建新文件
        {
            if ( s_hFile != INVALID_HANDLE_VALUE)
            {
                ::CloseHandle(s_hFile);
                s_hFile = INVALID_HANDLE_VALUE;
            }
   
   //创建日志文件. 有文件时追加方式打开,没有时创建.
            s_hFile = ::CreateFileA( szFileName,
                                     GENERIC_WRITE,
                                     FILE_SHARE_WRITE | FILE_SHARE_READ,
                                     0,
                                     OPEN_ALWAYS,
                                     FILE_ATTRIBUTE_NORMAL,
                                     0);

            if ( s_hFile == INVALID_HANDLE_VALUE)
            {
                printf("::CreateFile Error: %d", ::GetLastError());
                return;
            }
        }

 

        //把消息写到文件
        if ( s_hFile != INVALID_HANDLE_VALUE)
        {
            DWORD dwWrite = 0;
            ::SetFilePointer(s_hFile, 0, NULL, FILE_END);
            ::WriteFile(s_hFile, szMsg, dwMsgLen, &dwWrite, NULL);
           
   //备份创建成功的新文件名
   strcpy(s_szFileName,szFileName);
        }

  ::LeaveCriticalSection(&m_crit);   
  /*----------------------------退出临界区---------------------------------*/
    }

}; // CLog


//宏定义文件名和行号
#define AT __FILE__, __LINE__,

 

#if (_FLAG_OUTLOG_ENABLE)

//日志输出接口函数1
static void Logout(LPCSTR lpFormat, ...)
{
 const DWORD BufSize = 2048;
    char szMsg[BufSize];
 
 va_list args;  //格式化消息

 va_start(args, lpFormat);   
 wvsprintfA(szMsg,  lpFormat, args);  //vsprintf_s BufSize - strlen(szMsg),
 va_end(args); 
  
 //输出信息
 CLog::logout("0",0,szMsg);
}

//日志输出接口函数2  使用于logflout(AT"xxxx")形式
//(LPCSTR lpFile, int nLine)有时适配这个函数名,所以修改函数名 fl = file and line
static void Logflout(LPCSTR lpFile, int nLine,LPCSTR lpFormat, ...)
{
 const DWORD BufSize = 2048;
    char szMsg[BufSize];
 
 char* pTemp = szMsg;
 
 va_list args; //格式化消息
 
 va_start(args, lpFormat);   
 wvsprintfA(szMsg,  lpFormat, args);  //vsprintf_s BufSize - strlen(szMsg),
 va_end(args); 
 
 //输出有文件名及行号的消息
 CLog::logout(lpFile, nLine,szMsg);
}

#ifdef _LOGLEVEL
//日志输出接口函数3
static void Loglevelout(int nshowlevel,LPCSTR lpFormat, ...)
{

#ifdef _SETFILENAME
 if (MIN_LEVEL<=nshowlevel && nshowlevel<= MAX_LEVEL)
#endif
 {
  const DWORD BufSize = 2048;
  char szMsg[BufSize];
  
  va_list args;  //格式化消息
  
  va_start(args, lpFormat);   
  wvsprintfA(szMsg,  lpFormat, args);  //vsprintf_s BufSize - strlen(szMsg),
  va_end(args); 
  
  char buffer[20];
     _itoa(nshowlevel, buffer, 10 );
  strcat(szMsg,"......Level=");
        strcat(szMsg,buffer);
  strcat(szMsg,"\r\n");

  //输出信息
  CLog::logout("0",0,szMsg);
 }

}
#endif //_LOGLEVEL

#ifdef _DEBUGCONSOLE
//关闭控制台接口函数4
static void Logconsole_close()
{
 FreeConsole();
}

//隐藏或显示控制台接口函数5
static void Logcconsole_win(BOOL pSHWinConsole = FALSE)
{
 static BOOL bGetWinConsole = FALSE;
 HWND wincmd = NULL;

 if (!bGetWinConsole)
  {
   typedef HWND (WINAPI *PROCGETCONSOLEWINDOW)();
   PROCGETCONSOLEWINDOW GetConsoleWindow;
   
   HMODULE hKernel32 = GetModuleHandle("kernel32");
   GetConsoleWindow = (PROCGETCONSOLEWINDOW)GetProcAddress(hKernel32,"GetConsoleWindow");

   wincmd=GetConsoleWindow();
  }
 if (pSHWinConsole)
 {
  ShowWindowAsync(wincmd, SW_SHOWNORMAL);
 }
 else
 {
  ShowWindowAsync(wincmd, SW_HIDE );
 }
}
#endif //_DEBUGCONSOLE

#else  //_FLAG_OUTLOG_ENABLE

//日志输出接口函数1 空 用于Release版本
static void Logout(LPCSTR lpFormat, ...)
{
}
//日志输出接口函数2 空 用于Release版本
static void Logflout(LPCSTR lpFile, int nLine,LPCSTR lpFormat, ...)
{
}

#ifdef _LOGLEVEL
//日志输出接口函数3 空 用于Release版本
static void Loglevelout(int nshowlevel,LPCSTR lpFormat, ...)
{
}
#endif //_LOGLEVEL

#ifdef _DEBUGCONSOLE
//关闭控制台接口函数4 空 用于Release版本
static void Logconsole_close()
{
}
//隐藏或显示控制台接口函数5 空 用于Release版本
static void Logcconsole_win(BOOL pSHWinConsole = FALSE)
{
}
#endif //_DEBUGCONSOLE

#endif //_FLAG_OUTLOG_ENABLE

#endif //!defined(AFX_LOGFILE_H__EF4BC4B2_3BB6_46E8_B936_0F3A61E20BF0__INCLUDED_)

/******************************************************************************
版本号: 3.
时间: 2013/5/16
为更方便书写,将函数名的首字母C去掉。如CLogout 更改为 Logout等
-----------------------------------------------------------------------------
版本号: 2.
时间: 2013/5/15
由于参数匹配有时混乱问题,所以修改函数名CLogout(LPCSTR lpFile, int nLine,LPCSTR lpFormat, ...)
为CLogflout(LPCSTR lpFile, int nLine,LPCSTR lpFormat, ...)
-----------------------------------------------------------------------------
版本号: 1.
时间: 2013/5/15
正常摘用
******************************************************************************/

 

代码及例程下载链接 http://download.csdn.net/detail/hixi2007/5383127

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
VC6.0是微软公司开发的一款集成开发环境(IDE),用于开发Windows平台下的应用程序。在VC6.0中,可以使用C/C++语言编写串口调试助手。 要编写串口调试助手,首先需要了解串口通信的基本原理和相关知识。串口通信是指通过串行接口(如RS232)进行数据传输的一种通信方式。在Windows平台下,可以使用Windows API提供的函数来实现串口通信。 以下是一个简单的示例代码,演示了如何使用VC6.0编写一个串口调试助手: ```c++ #include <windows.h> #include <iostream> int main() { HANDLE hSerial; DCB dcbSerialParams = { 0 }; COMMTIMEOUTS timeouts = { 0 }; char buffer[256]; DWORD bytesRead; // 打开串口 hSerial = CreateFile("COM1", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hSerial == INVALID_HANDLE_VALUE) { std::cout << "无法打开串口" << std::endl; return 1; } // 配置串口参数 dcbSerialParams.DCBlength = sizeof(dcbSerialParams); if (!GetCommState(hSerial, &dcbSerialParams)) { std::cout << "无法获取串口参数" << std::endl; CloseHandle(hSerial); return 1; } dcbSerialParams.BaudRate = CBR_9600; dcbSerialParams.ByteSize = 8; dcbSerialParams.StopBits = ONESTOPBIT; dcbSerialParams.Parity = NOPARITY; if (!SetCommState(hSerial, &dcbSerialParams)) { std::cout << "无法设置串口参数" << std::endl; CloseHandle(hSerial); return 1; } // 配置串口超时时间 timeouts.ReadIntervalTimeout = 50; timeouts.ReadTotalTimeoutConstant = 50; timeouts.ReadTotalTimeoutMultiplier = 10; timeouts.WriteTotalTimeoutConstant = 50; timeouts.WriteTotalTimeoutMultiplier = 10; if (!SetCommTimeouts(hSerial, &timeouts)) { std::cout << "无法设置串口超时时间" << std::endl; CloseHandle(hSerial); return 1; } // 读取串口数据 while (true) { if (!ReadFile(hSerial, buffer, sizeof(buffer), &bytesRead, NULL)) { std::cout << "无法读取串口数据" << std::endl; CloseHandle(hSerial); return 1; } if (bytesRead > 0) { // 处理接收到的数据 std::cout << "接收到的数据:" << buffer << std::endl; } } // 关闭串口 CloseHandle(hSerial); return 0; } ``` 以上代码是一个简单的串口调试助手,它通过打开指定的串口(这里使用COM1作为示例),配置串口参数和超时时间,然后循环读取串口数据并进行处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值