亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C++ > 正文

詳解Windows C++ 應用程序通用日志組件的使用介紹

2020-02-24 14:31:30
字體:
來源:轉載
供稿:網友

  我們在調試、跟蹤和執行應用程序的過程中,程序日志可以為這些任務提供大量有價值的運行信息,因此程序日志對于應用程序的運行和維護非常重要,武林技術頻道小編和你分享詳解Windows C++ 應用程序通用日志組件的使用介紹。

  在如何記錄程序日志方面,通常有三種選擇:

  1、采用Log4CXX等公共開源日志組件:這類日志組件的特點是跨平臺且功能比較強大,例如可以把日志發往另一臺服務器或記錄到數據庫中等;另外,可配置性較高,可以通過配置文件或程序代碼對日志進行很多個性化設置。但從另外一個角度看,由于這些優點往往也導致了在使用方面的缺點。首先,對于一般應用程序來說,它們并不需要太多的功能,通常只需要把日志記錄到文件或反饋到應用程序,功能太多反正讓用戶使用起來覺得繁瑣還得背負很多從來都用不到的代碼。其次,這類日志組件通常是跨平臺的,并不只是針對 Windows 或 VC 的應用程序,因此使用起來總會覺得有點別扭,例如他們的字符都是用 char 類型的,對于一個 Unicode 程序來說每次寫日志都要做字符轉換是很不爽的事情,本座在多年前曾經使用過 Log4Cpp ,程序執行時總是報告日志組件有內存泄露,雖然有可能是誤報,但是使用起來總覺得很不舒服。

  2、自己寫幾個簡單的類或函數記錄日志:這種方法的確很簡單,通常都不用一兩百行的代碼。但這種方法通常缺乏規范性和通用性,其他程序需要記錄類似的但有點差異的日志時,通常的作法是:Copy-Paste-Modify;另外,這類方法很可能也沒有考慮性能或并發方面的問題,通常是直接在工作線程中寫日志,對于那些性能要求較高的應用程序是絕對不允許的。

  3、干脆不記錄任何日志:的確,現在很多程序由于各種原因并沒有記錄任何日志。但本座以為,如果一個程序是有用的,具備一定功能,并且需要連續運行較長一段時間,那么記錄日志是必須的;否則,得認真考慮該程序是否有存在的必要了。
?

設計

  綜上所述,編寫一個通用的日志組件應該著重考慮三個方面:功能、可用性和性能。下面,本座詳細說明在設計日志組件時對這些方面問題的考慮:

  1、功能:本日志組件的目的是滿足大多數應用程序記錄日志的需求 —— 把日志輸出到文件或發送到應用程序中,并不提供一些復雜但不常用的功能。本日志組件的功能包括:

??? 把日志信息輸出到指定文件

??? 每日生成一個日志文件

??? 對于 GUI 程序,可以把日志信息發送到指定窗口

??? 對于Console應用程序,可以把日志信息發往標準輸出 (std::cout)

??? 支持 MBCS / UNICODE,Console / GUI 程序

??? 支持動態加載和靜態加載日志組件 DLL

??? 支持 DEBUG/TRACE/INFO/WARN/ERROR/FATAL 等多個日志級別

  2、可用性:本日志組件著重考慮了可用性,盡量讓使用者用起來覺得簡便、舒心:

??? 簡單純凈:不依賴任何程序庫或框架

??? 使用接口簡單,不需復雜的配置或設置工作

??? 提供 CStaticLogger 和 CDynamicLogger 包裝類用于靜態或動態加載以及操作日志組件,用戶無需關注加載細節

??? 程序如果要記錄多個日志文件只需為每個日志文件創建相應的 CStaticLogger 或 CDynamicLogger 對象

??? 只需調用 Log()/Debug()/Trace()/Info()/Warn()/Error()/Fatal() 等方法記錄日志

??? 日志記錄方法支持可變參數

??? 日志輸出格式:<時間> <線程ID> <日志級別> <日志內容>

  3、性能:性能是組件是否值得使用的硬指標,本組件從設計到編碼的過程都盡量考慮到性能優化:

??? 支持多線程同時發送寫日志請求

??? 使用單獨線程在后臺寫日志,不影響工作線程的正常執行

??? 采用批處理方式批量記錄日志







接口

  1、ILogger:日志組件對象接口

?

/******************************************************************************
?Module:? Logger.h
?Notices: Copyright (c) 2012 Bruce Liang - http://www.cnblogs.com/ldcsaa/

?Purpose: 記錄程序日志。
???????? 1. 把日志信息輸出到指定文件
???????? 2. 對于 GUI 程序,可以把日志信息發送到指定窗口
???????? 3. 對于Console應用程序,可以把日志信息發往標準輸出 (std::cout)

?Desc:
???????? 1、功能:
???????? --------------------------------------------------------------------------------------
???????? a) 把日志信息輸出到指定文件
???????? b) 每日生成一個日志文件
???????? c) 對于 GUI 程序,可以把日志信息發送到指定窗口
???????? d) 對于Console應用程序,可以把日志信息發往標準輸出 (std::cout)
???????? e) 支持 MBCS / UNICODE,Console / GUI 程序
???????? f) 支持動態加載和靜態加載日志組件 DLL
???????? g) 支持 DEBUG/TRACE/INFO/WARN/ERROR/FATAL 等多個日志級別

???????? 2、可用性:
???????? --------------------------------------------------------------------------------------
???????? a) 簡單純凈:不依賴任何程序庫或框架
???????? b) 使用接口簡單,不需復雜的配置或設置工作
???????? c) 提供 CStaticLogger 和 CDynamicLogger 包裝類用于靜態或動態加載以及操作日志組件,用戶無需關注加載細節
???????? d) 程序如果要記錄多個日志文件只需為每個日志文件創建相應的 CStaticLogger 或 CDynamicLogger 對象
???????? e) 只需調用 Log()/Debug()/Trace()/Info()/Warn()/Error()/Fatal() 等方法記錄日志
???????? f) 日志記錄方法支持可變參數
???????? g) 日志輸出格式:<時間> <線程ID> <日志級別> <日志內容>

???????? 3、性能:
???????? --------------------------------------------------------------------------------------
???????? a) 支持多線程同時發送寫日志請求
???????? b) 使用單獨線程在后臺寫日志,不影響工作線程的正常執行
???????? c) 采用批處理方式批量記錄日志

?Usage:
???????? 方法一:(靜態加載 Logger DLL)
???????? --------------------------------------------------------------------------------------
???????? 0. 應用程序包含 StaticLogger.h 頭文件
???????? 1. 創建 CStaticLogger 對象(通常為全局對象)
???????? 2. 調用 CStaticLogger->Init(...) 初始化日志組件
???????? 3. 使用 CStaticLogger->Log()/Debug()/Trace()/Info()/Warn()/Error()/Fatal() 等方法寫日志
???????? 4. 調用 CStaticLogger->UnInit(...) 清理日志組件(CStaticLogger 對象析構時也會自動清理日志組件)

???????? 方法二:(動態加載 Logger DLL)
???????? --------------------------------------------------------------------------------------
???????? 0. 應用程序包含 DynamicLogger.h 頭文件
???????? 1. 創建 CDynamicLogger 對象(通常為全局對象)
???????? 2. 調用 CDynamicLogger->Init(...) 初始化日志組件
???????? 3. 使用 CDynamicLogger->Log()/Debug()/Trace()/Info()/Warn()/Error()/Fatal() 等方法寫日志
???????? 4. 調用 CDynamicLogger->UnInit(...) 清理日志組件(CDynamicLogger 對象析構時也會自動清理日志組件)

???????? 方法三:(直接用導出函數加載 Logger DLL)
???????? --------------------------------------------------------------------------------------
???????? 0. 應用程序包含 Logger.h 頭文件
???????? 1. 手工調用 ILoger_Create() 和 ILoger_Create() 導出函數創建和銷毀 ILogger 對象
???????? (注:如果是動態加載,需手工調用 ::LoadLibrary()/::FreeLibrary() 系列 API 函數加載和卸載 Logger DLL)

???????? [
???????????? ***** 對于希望通過窗口接收日志信息的 GUI 程序 *****

???????????? A. 日志組件初始化成功后調用 SetGUIWindow(HWND) 設置收日志的窗口
???????????? B. 窗口須響應處理 LOG_MESSAGE 消息
???????????? C. 處理完 LOG_MESSAGE 消息后,調用 ILogger::FreeLogMsg() 銷毀接收到的 TLogMsg
???????? ]

?Environment:
???????? 1. Windows 2000 or later (_WIN32_WINNT >= 0x0500)
???????? 2. VC++ 2010 or later

?Release:
???????? 1. Logger_C.dll???? - Console/MBCS/Release
???????? 2. Logger_CD.dll??? - Console/MBCS/Debug
???????? 3. Logger_CU.dll??? - Console/Unicode/Release
???????? 4. Logger_CUD.dll?? - Console/Unicode/Debug
???????? 5. Logger.dll?????? - GUI/MBCS/Release
???????? 6. Logger_D.dll???? - GUI/MBCS/Debug
???????? 7. Logger_U.dll???? - GUI/Unicode/Release
???????? 8. Logger_UD.dll??? - GUI/Unicode/Debug

?Examples:
???????? 1. TestGUILogger??????? - GUI 版測試程序?????? (靜態加載)
???????? 2. TestDynamicLogger??? - GUI 版測試程序?????? (動態加載)
???????? 3. TestConsoleLogger??? - Console 版測試程序? (靜態加載)

?******************************************************************************/

?#pragma once

?/**************************************************/
?/********** imports / exports Logger.dll **********/

?#ifdef LOGGER_EXPORTS
???? #define LOGGER_API __declspec(dllexport)
???? //#define TRY_INLINE??? inline
?#else
???? #define LOGGER_API __declspec(dllimport)
???? //#define TRY_INLINE
?#endif

?/**************************************************/
?/****************** 日志組件接口 *******************/

?class LOGGER_API ILogger
?{
?public:
???? /***** 日志級別 *****/
???? enum LogLevel
???? {
???????? LL_NONE???? = 0XFF,
???????? LL_DEBUG??? = 1,
???????? LL_TRACE??? = 2,
???????? LL_INFO???? = 3,
???????? LL_WARN???? = 4,
???????? LL_ERROR??? = 5,
???????? LL_FATAL??? = 6
???? };

???? /***** 操作錯誤碼 *****/
???? enum ErrorCode
???? {
???????? // 無錯誤
???????? EC_OK??? = NO_ERROR,
???????? // 文件操作相關的錯誤
???????? EC_FILE_GENERIC,
???????? EC_FILE_FILENOTFOUND,
???????? EC_FILE_BADPATH,
???????? EC_FILE_TOMANYOPERFILES,
???????? EC_FILE_ACCESSDENIED,
???????? EC_FILE_INVALIDFILE,
???????? EC_FILE_REMOVECURRENTDIR,
???????? EC_FILE_DIRECTORYFULL,
???????? EC_FILE_BADSEEK,
???????? EC_FILE_HARDIO,
???????? EC_FILE_SHARINGVIOLATION,
???????? EC_FILE_LOCKVIOLATION,
???????? EC_FILE_DISKFULL,
???????? EC_FILE_ENDOFFILE,
???????? // 其他錯誤
???????? EC_INVALID_STATE,
???????? EC_INIT_LOGLEVEL,
???????? EC_INIT_PRINTFLAG,
???????? EC_INIT_CREATE_LOG_THREAD_FAIL
???? };

???? /******************************************
???????????????????? 日志信息結構
???? *******************************************/
???? struct TLogMsg
???? {
???????? DWORD?????? m_dwSize;?????? // 結構大小 - 跟據消息長度動態變化
???????? LogLevel??? m_logLevel;???? // 日志級別
???????? UINT??????? m_uiThreadID;?? // 線程ID
???????? SYSTEMTIME? m_stMsgTime;??? // 記錄時間
???????? TCHAR?????? m_psMsg[1];???? // 消息內容
???? };

?public:
???? ILogger(void);
???? virtual ~ILogger(void);
?private:
???? ILogger(const ILogger&);
???? ILogger& operator = (const ILogger&);

?public:
???? // 日志組件初始化方法
???? virtual BOOL Init(
???????????????????????? LPCTSTR logFile? = NULL????????????????? // 日志文件. 默認: {AppPath}/logs/{AppName}-YYYYMMDD.log
?????????????????????? , LogLevel ll????? = DEFAULT_LOG_LEVEL???? // 日志級別. 默認: [Debug -> LL_DEBUG] / [Release -> LL_INFO]
?????????????????????? , int printFlag??? = DEFAULT_PRINT_FLAG??? // 輸出掩碼. 是否輸出到文件和(或)屏幕. 默認: 只輸出到文件
????????????????????? )?????? = 0;
???? // 日志組件清理方法
???? virtual BOOL UnInit()??? = 0;

?public:
???? // 寫日志方法:傳入日志內容字符串(對于不需要格式化的日志文本,用本方法效率最高)
???? virtual void Log_0? (LogLevel ll, LPCTSTR msg) = 0;
???? virtual void Debug_0(LPCTSTR msg);
???? virtual void Trace_0(LPCTSTR msg);
???? virtual void Info_0 (LPCTSTR msg);
???? virtual void Warn_0 (LPCTSTR msg);
???? virtual void Error_0(LPCTSTR msg);
???? virtual void Fatal_0(LPCTSTR msg);

???? // 寫日志方法:傳入格式化字符串和參數棧指針(通常只在組件內部使用)
???? virtual void LogV?? (LogLevel ll, LPCTSTR format, va_list arg_ptr);

???? // 寫日志方法:傳入格式化字符串和可變參數(非常靈活簡便)
???? virtual void Log???? (LogLevel ll, LPCTSTR format, ...);
???? virtual void Debug?? (LPCTSTR format, ...);
???? virtual void Trace?? (LPCTSTR format, ...);
???? virtual void Info??? (LPCTSTR format, ...);
???? virtual void Warn??? (LPCTSTR format, ...);
???? virtual void Error?? (LPCTSTR format, ...);
???? virtual void Fatal?? (LPCTSTR format, ...);

???? // 寫日志方法:傳入格式化字符串和可變參數(與上一組方法類似,但在進行任何操作前會檢查日志級別)
???? virtual void TryLog???? (LogLevel ll, LPCTSTR format, ...);
???? virtual void TryDebug?? (LPCTSTR format, ...);
???? virtual void TryTrace?? (LPCTSTR format, ...);
???? virtual void TryInfo??? (LPCTSTR format, ...);
???? virtual void TryWarn??? (LPCTSTR format, ...);
???? virtual void TryError?? (LPCTSTR format, ...);
???? virtual void TryFatal?? (LPCTSTR format, ...);

???? // 通用輔助方法
???? virtual BOOL HasInited?????????? ()??????? const??? = 0;??????? // 是否已經初始化???????????????????????????
???? virtual BOOL IsPrint2File??????? ()??????? const??? = 0;??????? // 是否把日志輸出到文件???
???? virtual BOOL IsPrint2Screen????? ()??????? const??? = 0;??????? // 是否把日志輸出到屏幕窗口???
???? virtual int??? GetPrintFlag????? ()??????? const??? = 0;??????? // 打印標志???????????????????
???? virtual LogLevel??? GetLogLevel? ()??????? const??? = 0;??????? // 日志級別???????
???? virtual LPCTSTR??????? GetLogFile()??????? const??? = 0;??????? // 日志文件
???? virtual ErrorCode??? GetLastError()??????? const??? = 0;??????? // 當前操作錯誤碼

?/****************************** GUI ******************************/
?#ifdef _WINDOWS
???? public:
???????? // 設置接收日志信息的窗口, hWndGUI == NULL 則取消接收
???????? virtual void SetGUIWindow(HWND hWndGUI)??? = 0;
???????? // 獲取接收日志信息的窗口
???????? virtual HWND GetGUIWindow()??????????????? = 0;

???????? // 銷毀在發送 LOG_MESSAGE 消息時動態創建的 TLogMsg 對象
???????? virtual void FreeLogMsg(const TLogMsg* pLogMsg);

???????? // 虛擬窗口句柄標掩碼:用于向 GUI 窗口發送 LOG_MESSAGE 消息時作為發送源標識
???????? static const int LOGGER_FAKE_WINDOW_BASE = 0X80001111;
???????? // 自定義日志消息:通過本消息向 GUI 窗口發送日志
???????? // 其中:WPARAM -> ILogger 對象指針,LPARAM -> TLogMsg 結構體指針
???????? static const int LOG_MESSAGE = WM_USER | (0x7FFF & LOGGER_FAKE_WINDOW_BASE);
?#endif

?public:
???? static const int PRINT_FLAG_FILE??????????? = 0x00000001;??????????? // 打印到文件
???? static const int PRINT_FLAG_SCREEN????????? = 0x00000002;??????????? // 打印到屏幕
???? static const int DEFAULT_PRINT_FLAG???????? = PRINT_FLAG_FILE;??????? // 默認日志掩碼
???? static const LogLevel DEFAULT_LOG_LEVEL???? =
?#ifdef _DEBUG
???????????????? LL_DEBUG
?#else
???????????????? LL_INFO
?#endif

?};

?/**************************************************/
?/************** Logger DLL 導出函數 ***************/

?// 創建 ILogger 對象
?EXTERN_C LOGGER_API ILogger* ILogger_Create();
?// 銷毀 ILogger 對象
?EXTERN_C LOGGER_API void ILogger_Destroy(ILogger* p);

?// 獲取各日志級別的文字描述
?EXTERN_C LOGGER_API LPCTSTR??? ILogger_GetLogLevelDesc (ILogger::LogLevel ll);
?// 獲取各操作錯誤碼的文字描述
?EXTERN_C LOGGER_API LPCTSTR??? ILogger_GetErrorDesc??? (ILogger::ErrorCode ec);


?

?

?  代碼中的注釋基本已經能夠說明日志組件的使用方法,這里只做一些簡單的概括:

  版本:日志組件以 DLL 的形式提供,已編譯成 Debug/Release、MBCS/Unicode、GUI/Console 8個版本

  測試:三個測試程序 TestGUILogger、TestDynamicLogger 和 TestConsoleLogger 用于測試所有版本。其中 TestDynamicLogger 采用動態加載方式加載 Logger DLL

  使用方法:

    0. 應用程序包含 Logger.h 頭文件
    1. 調用 ILogger_Create() 導出函數創建 ILogger 對象
    2. 調用 ILogger->Init(...) 初始化日志組件
    3. 使用 ILogger->Log()/Debug()/Trace()/Info()/Warn()/Error()/Fatal() 等方法寫日志
    4. 調用 ILogger->UnInit(...) 清理日志組件
    5. 調用 ILogger_Destroy() 導出函數銷毀 ILogger 對象

?

  2、CStaticLogger:ILogger 包裝器(智能指針)—— 用于靜態加載 Logger DLL

?

#pragma once

?#include "Logger.h"

?/**************************************************/
?/********* http://www.cnblogs.com/ldcsaa/ *********/
?/********** ILogger 包裝器(智能指針) ***********/
?/*********** 用于靜態加載 Logger DLL ************/

?class LOGGER_API CStaticLogger
?{
?public:
???? // 構造函數:如果 bCreate 為 TRUE,則在構建 CStaticLogger 實例的同時創建 ILogger 對象
???? CStaticLogger(BOOL bCreate = TRUE);
???? // 析構函數
???? ~CStaticLogger();
?private:
???? CStaticLogger(const CStaticLogger&);
???? CStaticLogger& operator = (const CStaticLogger&);

?public:
???? inline void Reset?????????? (ILogger* pLogger);???? // 重設其封裝的 ILogger 指針
???? inline BOOL IsValid???????? ()??? const;??????????? // 判斷其封裝的 ILogger 指針是否非空
???? inline ILogger* Get???????? ()??? const;??????????? // 獲取 ILogger 指針
???? inline ILogger& operator *? ()??? const;??????????? // 獲取 ILogger 引用
???? inline ILogger* operator -> ()??? const;??????????? // 獲取 ILogger 指針
???? inline operator ILogger*??? ()??? const;??????????? // 轉換為 ILogger 指針

?private:
???? ILogger* m_pLogger;
?};


  CStaticLogger 為簡化日志組件使用而設計,用于靜態加載 Logger DLL 的場合。使用方法:

?

    0. 應用程序包含 StaticLogger.h 頭文件
    1. 創建 CStaticLogger 對象(通常為全局對象)
    2. 調用 CStaticLogger->Init(...) 初始化日志組件
    3. 使用 CStaticLogger->Log()/Debug()/Trace()/Info()/Warn()/Error()/Fatal() 等方法寫日志
    4. 調用 CStaticLogger->UnInit(...) 清理日志組件(CStaticLogger 對象析構時也會自動清理日志組件)

?

  3、CDynamicLogger:ILogger 包裝器(智能指針)—— 用于動態加載 Logger DLL

?

#pragma once

?#include "Logger.h"

?/**************************************************/
?/********* http://www.cnblogs.com/ldcsaa/ *********/
?/************** Logger DLL 默認文件名 ***************/

?#ifdef _DEBUG
???? #ifdef _UNICODE
???????? #ifdef _WINDOWS
???????????? #define DEF_LOGGER_DLL_FILE_PATH??? _T("Logger_UD.dll")
???????? #else
???????????? #define DEF_LOGGER_DLL_FILE_PATH??? _T("Logger_CUD.dll")
???????? #endif
???? #else
???????? #ifdef _WINDOWS
???????????? #define DEF_LOGGER_DLL_FILE_PATH??? _T("Logger_D.dll")
???????? #else
???????????? #define DEF_LOGGER_DLL_FILE_PATH??? _T("Logger_CD.dll")
???????? #endif
???? #endif
?#else
???? #ifdef _UNICODE
???????? #ifdef _WINDOWS
???????? #define DEF_LOGGER_DLL_FILE_PATH??????? _T("Logger_U.dll")
???????? #else
???????????? #define DEF_LOGGER_DLL_FILE_PATH??? _T("Logger_CU.dll")
???????? #endif
???? #else
???????? #ifdef _WINDOWS
???????????? #define DEF_LOGGER_DLL_FILE_PATH??? _T("Logger.dll")
???????? #else
???????????? #define DEF_LOGGER_DLL_FILE_PATH??? _T("Logger_C.dll")
???????? #endif
???? #endif
?#endif

?/**************************************************/
?/*************** Logger DLL 導出函數 ***************/

?// 創建 ILogger 對象
?typedef ILogger*??????????? (*FN_ILogger_Create)??????????? ();
?// 銷毀 ILogger 對象
?typedef void??????????????? (*FN_ILogger_Destroy)?????????? (ILogger* p);
?// 獲取各日志級別的文字描述
?typedef LPCTSTR???????????? (*FN_ILogger_GetLogLevelDesc)?? (ILogger::LogLevel ll);
?// 獲取各操作錯誤碼的文字描述
?typedef LPCTSTR???????????? (*FN_ILogger_GetErrorDesc)????? (ILogger::ErrorCode ec);

?/*************************************************/
?/********** ILogger 包裝器(智能指針) ***********/
?/************ 用于動態加載 Logger DLL ************/

?class CDynamicLogger
?{
?public:
???? // 構造函數:如果 bLoad 為 TRUE,則在構建 CDynamicLogger 示例的同時創建 ILogger 對象
???? CDynamicLogger(BOOL bLoad = TRUE, LPCTSTR lpszFilePath = DEF_LOGGER_DLL_FILE_PATH)
???? {
???????? Reset();

???????? if(bLoad)
???????????? Load(lpszFilePath);
???? }

???? // 析構函數
???? ~CDynamicLogger()
???? {
???????? Free();
???? }

?private:
???? CDynamicLogger(const CDynamicLogger&);
???? CDynamicLogger& operator = (const CDynamicLogger&);

?public:
???? // 創建 ILogger 對象
???? ILogger* ILogger_Create()
???????? {return m_fnILoggerCreate();}
???? // 銷毀 ILogger 對象
???? void ILogger_Destroy(ILogger* p)
???????? {m_fnILoggerDestroy(p);}
???? // 獲取各日志級別的文字描述
???? LPCTSTR??? ILogger_GetLogLevelDesc(ILogger::LogLevel ll)
???????? {return m_fnILoggerGetLogLevelDesc(ll);}
???? // 獲取各操作錯誤碼的文字描述
???? LPCTSTR??? ILogger_GetErrorDesc(ILogger::ErrorCode ec)
???????? {return m_fnILoggerGetErrorDesc(ec);}

???? // 加載 Logger DLL
???? BOOL Load(LPCTSTR lpszFilePath = DEF_LOGGER_DLL_FILE_PATH)
???? {
???????? if(IsValid())
???????????? return FALSE;

???????? BOOL isOK = FALSE;
???????? m_hLogger = ::LoadLibrary(lpszFilePath);

???????? if(m_hLogger)
???????? {
???????????? m_fnILoggerCreate??????????? = (FN_ILogger_Create)??????????? ::GetProcAddress(m_hLogger, "ILogger_Create");
???????????? m_fnILoggerDestroy?????????? = (FN_ILogger_Destroy)?????????? ::GetProcAddress(m_hLogger, "ILogger_Destroy");
???????????? m_fnILoggerGetLogLevelDesc?? = (FN_ILogger_GetLogLevelDesc)?? ::GetProcAddress(m_hLogger, "ILogger_GetLogLevelDesc");
???????????? m_fnILoggerGetErrorDesc????? = (FN_ILogger_GetErrorDesc)????? ::GetProcAddress(m_hLogger, "ILogger_GetErrorDesc");

???????????? if(m_fnILoggerCreate && m_fnILoggerDestroy)
???????????? {
???????????????? m_pLogger?? = ILogger_Create();
???????????????? isOK??????? = (m_pLogger != NULL);
???????????? }
???????? }

???????? if(!isOK)
???????????? Free();

???????? return isOK;
???? }

???? // 卸載 Logger DLL
???? BOOL Free()
???? {
???????? if(!IsValid())
???????????? return TRUE;

???????? BOOL isOK = TRUE;

???????? if(m_pLogger)??? ILogger_Destroy(m_pLogger);
???????? if(m_hLogger)??? isOK = ::FreeLibrary(m_hLogger);

???????? Reset();

???????? return isOK;
???? }

???? BOOL IsValid??????????? ()??? const??? {return m_pLogger != NULL;}? // 判斷其封裝的 ILogger 指針是否非空
???? ILogger* Get??????????? ()??? const??? {return m_pLogger;}????????? // 獲取 ILogger 指針
???? ILogger& operator *???? ()??? const??? {return *m_pLogger;}???????? // 獲取 ILogger 引用
???? ILogger* operator ->??? ()??? const??? {return m_pLogger;}????????? // 獲取 ILogger 指針
???? operator ILogger*?????? ()??? const??? {return m_pLogger;}????????? // 轉換為 ILogger 指針

?private:
???? void Reset()
???? {
???????? m_hLogger??????????????????? = NULL;
???????? m_pLogger??????????????????? = NULL;
???????? m_fnILoggerCreate??????????? = NULL;
???????? m_fnILoggerDestroy?????????? = NULL;
???????? m_fnILoggerGetLogLevelDesc?? = NULL;
???????? m_fnILoggerGetErrorDesc????? = NULL;
???? }

?private:
???? HMODULE???????? m_hLogger;
???? ILogger*??????? m_pLogger;

???? FN_ILogger_Create??????????? m_fnILoggerCreate;
???? FN_ILogger_Destroy?????????? m_fnILoggerDestroy;
???? FN_ILogger_GetLogLevelDesc?? m_fnILoggerGetLogLevelDesc;
???? FN_ILogger_GetErrorDesc????? m_fnILoggerGetErrorDesc;
?};


?

?

  CDynamicLogger 為簡化日志組件使用而設計,用于動態加載 Logger DLL 的場合。使用方法:

    0. 應用程序包含 DynamicLogger.h 頭文件
    1. 創建 CDynamicLogger 對象(通常為全局對象)
    2. 調用 CDynamicLogger->Init(...) 初始化日志組件
    3. 使用 CDynamicLogger->Log()/Debug()/Trace()/Info()/Warn()/Error()/Fatal() 等方法寫日志
    4. 調用 CDynamicLogger->UnInit(...) 清理日志組件(CDynamicLogger 對象析構時也會自動清理日志組件)

以上就是關于詳解Windows C++ 應用程序通用日志組件的使用介紹,雖然現在的技術人員需求沒以前那么火爆,但是還是很有前途的。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产精品999| 亚洲国产三级网| 成人激情av在线| 亚洲专区在线视频| 欧美野外wwwxxx| 色天天综合狠狠色| 91夜夜揉人人捏人人添红杏| 久久99热这里只有精品国产| 亚洲精品456在线播放狼人| 热草久综合在线| 欧美日韩国产在线播放| 亚洲精品久久久久久久久| 亚洲一区二区在线| 在线观看国产精品日韩av| 成人黄色短视频在线观看| 精品福利在线观看| 美女扒开尿口让男人操亚洲视频网站| 91sao在线观看国产| 欧美日韩免费在线| 精品国产依人香蕉在线精品| 亚洲国产中文字幕久久网| 日韩av一区二区在线| 亚洲日本欧美日韩高观看| 欧美成人合集magnet| 欧美电影在线观看高清| 亚洲国语精品自产拍在线观看| 精品久久久精品| 国产精品香蕉在线观看| 日韩精品福利在线| 成人免费观看网址| 国产欧美日韩中文字幕在线| 欧美极品美女视频网站在线观看免费| 日韩亚洲综合在线| 国产精品直播网红| 亚洲色图美腿丝袜| 欧美黄色成人网| 国产精品偷伦视频免费观看国产| 久久精品国产成人精品| 日本视频久久久| 亚洲精品之草原avav久久| 欧美国产精品人人做人人爱| 亚洲第一网站男人都懂| 亚洲国产高清高潮精品美女| 91精品国产乱码久久久久久蜜臀| 国产综合在线看| 成人av.网址在线网站| 理论片在线不卡免费观看| 亚洲综合国产精品| 91精品国产综合久久香蕉最新版| 日产日韩在线亚洲欧美| 国产性猛交xxxx免费看久久| 欧美丝袜一区二区三区| 国产精品视频区| 日韩精品视频免费| 色婷婷av一区二区三区在线观看| 欧美中文字幕视频在线观看| 5566日本婷婷色中文字幕97| 久久久久久久一区二区| 欧美电影免费观看网站| 色综合久久88色综合天天看泰| 97国产真实伦对白精彩视频8| 国产一区二区在线免费视频| 国产精品一区久久| 日韩成人av网| 2019亚洲日韩新视频| 亚洲成年网站在线观看| www亚洲欧美| 久久久久久久久久国产精品| 草民午夜欧美限制a级福利片| 日韩精品一二三四区| 国产欧美亚洲精品| 国产美女被下药99| 91成人在线播放| 国产精品激情av电影在线观看| 久久久久久久久久久亚洲| 日韩三级成人av网| 亚洲欧美在线免费| 久久精品国产视频| 国产大片精品免费永久看nba| 欧美激情精品久久久久久| 国产精品吹潮在线观看| 在线播放日韩专区| 欧美激情国内偷拍| 欧美国产日韩视频| 久久久免费观看| 精品久久久久久中文字幕大豆网| 欧美成人午夜激情视频| 国产69精品久久久久久| 国产精品夜色7777狼人| 中文字幕亚洲情99在线| 播播国产欧美激情| 国产精品ⅴa在线观看h| 亚洲专区中文字幕| 一本色道久久综合狠狠躁篇怎么玩| 国产有码在线一区二区视频| 欧美激情视频一区二区三区不卡| 欧美国产日韩视频| 91影院在线免费观看视频| 欧美—级a级欧美特级ar全黄| 国产成人在线一区| 国内自拍欧美激情| 国产精品ⅴa在线观看h| 久久久女女女女999久久| 九九精品视频在线| 亚洲一区国产精品| 久久综合免费视频| 国产精品久久久av久久久| 国产精品成久久久久三级| 精品福利视频导航| 国产在线精品一区免费香蕉| 亚洲欧美国产日韩中文字幕| 成人久久久久久| 自拍偷拍亚洲在线| 亚洲性视频网站| 亚洲韩国日本中文字幕| 91国语精品自产拍在线观看性色| 亚洲美女免费精品视频在线观看| 国产精品 欧美在线| 国产精品h在线观看| 欧美日韩免费网站| 久久夜色撩人精品| 久久久精品视频在线观看| 欧美日韩裸体免费视频| 国产成人精品视频在线观看| 国产欧美精品xxxx另类| 欧美日韩一区二区在线| 国产精品99久久久久久久久久久久| 亚洲欧美激情四射在线日| 国产精品久久色| 欧美视频13p| 国产综合在线观看视频| 欧美激情日韩图片| 久久久最新网址| 亚洲国产精品久久久久秋霞蜜臀| 伦理中文字幕亚洲| 亚洲天堂免费观看| 国产日产欧美精品| 成人性生交大片免费看小说| 韩剧1988免费观看全集| 国产这里只有精品| 久久亚洲精品中文字幕冲田杏梨| 亚洲成成品网站| 中文字幕精品一区二区精品| 成人黄色免费在线观看| 色狠狠av一区二区三区香蕉蜜桃| 国产欧美在线观看| 精品久久香蕉国产线看观看亚洲| 91爱视频在线| 国产精品入口夜色视频大尺度| 欧美大片欧美激情性色a∨久久| 日本久久久久久| 亚洲天堂男人的天堂| 2019最新中文字幕| 国产小视频国产精品| 91精品国产电影| 91精品久久久久久综合乱菊| 欧美黑人一区二区三区| 午夜精品久久久久久久白皮肤| 性色av一区二区咪爱| 日韩欧美亚洲一二三区| 日本成人精品在线| 欧美在线免费视频| 久久91亚洲精品中文字幕| 庆余年2免费日韩剧观看大牛|