VC調試--輸出調試字符串(含示例代碼)

  一.前言:
  一開始學習C++時,在控制檯下寫程序做練習,很容易輸出程序變量,所以調試很方便。之後學習編寫MFC程序,程序運行時要實時查看變量的情況就很麻煩了,雖然有TRACE宏(這個也是後來才知道的),但必須是程序結束後才能查看,而且閱讀起來也很費勁。最開始自己寫了個簡陋的dis()函數(請看本文後面的附錄),很簡單,幾行代碼往程序一粘貼,再調用dis函數就可以顯示字符串和int變量了。但後面輸出的變量會覆蓋之前的變量,所以還是不方便。於是一直在尋找一種輸出變量更好的方法,偶然的情況下在網上下載了個DebugView.exe( 下載),試了一下,就覺愛不釋手。TRACE輸出的變量實時地顯示在DebugView上,給調試帶來了更多的方便。本來以爲是這已經是終極好方法,誰知又在偶然的情況下,看到一位高手寫的一段代碼,可以很簡單的將變量輸出到控制檯窗口,比起用DebugView的方法是更甚一籌了。之後自己再做了些研究,不斷改進,力求簡單傻瓜,終於有了一個較爲滿意的解決法案了。現在拿出來很大家分享。希望對你有所幫助。
  二.把trace函數添加到你的工程:
  添加trace.h和trace.cpp到工程裏,然後在StdAfx.h包含它。
  trace.h /*==================trace function====更新日期:2010-10-17================== (一)功能: 輸出調試變量(類似於TRACE) (二)特點: 1.可以自動適應變量的類型(最主要依賴於ostringstream) 2.會在輸出的變量值前面自動添加變量的名稱,方便查看 3.程序自動創建Edit窗口用於輸出變量,不需要依賴外部程序 4.自動保存程序運行過程中所有輸出的變量到文件。 5.多種編譯模式,比如可讓DEBUG和Release版本都能輸出調試變量或者都不輸出 6.支持UNICODE,WIN32,Dll,MFC (三)說明: 1.添加 trace.h 和 trace.cpp 到工程裏。 2.在"stdafx.h"裏包含頭文件 #include "trace.h" 3.所有輸出的變量都會保存在工程目錄下的"DebugData.txt"文件,以方便查看 (四)關於一些宏設置: 1.默認情況下 NO_TRACE_WINDOW 和 TRACE_WINDOW都沒定義,則 DEBUG版本會輸出調試字符串,而Release版本不會 2.開頭定義了#define NO_TRACE_WINDOW DEBUG版本和Release版本都不會輸出輸出調試字符串 3.開頭定義了#define TRACE_WINDOW DEBUG版本和Release版本都會輸出輸出調試字符串 4.每次修改後上面2個宏後最好全部重新編譯 版權聲明: 沒有版權,許可任何單位,個人隨意使用,拷貝,修改,但作者不承擔由 此代碼帶來的任何損失。由於作者水平有限,錯誤或不完善之處,在 所難免,由此爲你帶來的不便,還望海涵。如果有任何BUG,請聯繫作者, 大家一起完善它!以後有更新統一放在以下網址上,你可以瀏覽並獲得 更新以及詳細的使用說明: http://hi.baidu.com/qiujiejia/blog/item/e43943187f c1f90e34fa4176.html 最後: 如果此份代碼爲你帶來了幫助,並且使你心生感謝之意。那我可否請你 誠心恭敬地念10遍"南(音:拿na)無(音:摩mo)阿彌陀佛"? 願得佛力加持,使你工作順利,閤家幸福! Jacky [email protected] ================================================== ======================*/ #ifndef _EASY_TRACE_H_ #define _EASY_TRACE_H_ //#define NO_TRACE_WINDOW //DEBUG版本和Release版本都不會輸出輸出調試字符串 //#define TRACE_WINDOW //DEBUG版本和Release版本都會輸出輸出調試字符串 //---------------------------------------- #ifdef NO_TRACE_WINDOW #else #ifdef _DEBUG #define TRACE_WINDOW #else #ifdef RELEASE_TRACE #define TRACE_WINDOW #endif #endif #endif //---------------------------------------- #ifndef TRACE_WINDOW /************************Not #define TRACE_WINDOW******************************/ #define trace(X) #define trace2(X,Y) #define trace3(X,Y,Z) #define trace4(X,Y,Z,W) #define TracePoint(P) #define TraceRect(X) #define TraceLastError() #define TraceWnd(X) #define TraceRel(X,Y) #else /************************Begin #define TRACE_WINDOW******************************/ //需要的頭文件 #include #include #include //----------------------------------------兼容unicode #ifdef _UNICODE #define tstring wstring #define tostringstream wostringstream #else #define tstring string #define tostringstream ostringstream #endif //----------------------------------------兼容unicode //---------------------------------------類定義 class CTraceWnd { public: static WNDPROC OldWndProc; static UINT index; static bool IsAutoWndWidth; static int WindowWidth; ~CTraceWnd() { CloseTraceWnd();} static LRESULT CALLBACK WindowProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam); static void PrintString(const TCHAR* OutputStr); static HWND CreateTraceWnd(); static void CloseTraceWnd(); static void TraceResult(TCHAR* str,int IsOk); static void TraceWindowInfo(HWND hWnd); }; //---------------------------------------類定義 //宏定義 #define Trace(X) _tcschr(_T(#X),'\"')!=NULL ? FormatString字符串還是一個變量,並且格式化*/ #define INITIAL_TRACE std::tostringstream FormatString; FormatString字符串輸出到窗口 #define TraceTab FormatString字符串到窗口,並自動調整窗口寬度 ************************************************** **************************/ void CTraceWnd::PrintString(const TCHAR* OutputStr) { //尋找已創建的輸出窗口 HWND hWnd=::FindWindow(NULL,TRACE_WND_TEXT); //如果不存在,則創建窗口並初始化設置 if ( !hWnd ) { hWnd=CreateTraceWnd(); if (!hWnd) return; } //將字符串輸出到窗口 ::SendMessage(hWnd,EM_REPLACESEL,FALSE,(LPARAM)Out putStr); } /************************************************* *************************** 創建Edit窗口 ************************************************** **************************/ HWND CTraceWnd::CreateTraceWnd() { HWND hWnd=CreateWindowEx(WS_EX_TOPMOST,TEXT("Edit"),TRA CE_WND_TEXT , WS_VISIBLE|WS_OVERLAPPEDWINDOW|WS_VSCROLL|WS_HSCRO LL| ES_AUTOHSCROLL|ES_WANTRETURN|ES_MULTILINE , 0,0,200,600, NULL,NULL,NULL,NULL); if (hWnd==NULL) return NULL; //創建菜單,並添加到窗口 HMENU hMenu = CreateMenu() ; AppendMenu(hMenu,MF_STRING, 3,_T("清空窗口")); AppendMenu(hMenu,MF_STRING, 4,_T("禁止自動調整寬度")); ::SetMenu(hWnd,hMenu); //修改edit框的字符個數 ::SendMessage(hWnd,EM_SETLIMITTEXT,1000000, 0); //清空Edit ::SendMessage(hWnd,WM_SETTEXT,NULL,(LPARAM)_T("")) ; // 設置字體參數 LOGFONT LogFont; ::memset(&LogFont, 0, sizeof(LOGFONT)); lstrcpy(LogFont.lfFaceName,_T("Fixedsys")); LogFont.lfHeight = -12; // 字體大小 LogFont.lfCharSet = GB2312_CHARSET; // 創建字體 HFONT hFont=CreateFontIndirect(&LogFont); // 設置字體 ::SendMessage(hWnd, WM_SETFONT, (WPARAM)hFont, 0); //把hWnd的默認窗口過程替換爲WindowProc,返回默認函數過程的函數指針 OldWndProc=(WNDPROC)SetWindowLong(hWnd,GWL_WNDPROC , (LONG)WindowProc); if (!OldWndProc) return NULL; //窗口創建後初始化參數 WindowWidth=200; IsAutoWndWidth=true; return hWnd; } /************************************************* *************************** close the edit wnd and save data ************************************************** **************************/ void CTraceWnd::CloseTraceWnd() { //尋找已創建的輸出窗口 HWND hWnd=::FindWindow(NULL,TRACE_WND_TEXT); if (!hWnd) return; //刪除字體 DeleteObject( (HFONT)::SendMessage(hWnd,WM_GETFONT,0,0) ); //刪除菜單 DestroyMenu(GetMenu(hWnd)); //打開由於保存數據文件DebugData.txt, FILE* fp=fopen("DebugData.txt","w"); //獲取窗口的字符串 int len=::SendMessage(hWnd,WM_GETTEXTLENGTH,0,0); TCHAR* WindowText=new TCHAR[len]; ::GetWindowText(hWnd,WindowText,len); #ifdef _UNICODE //如果定義了unicode,則先轉爲ansi再保存 char* buff = new char[len*2+1]; memset(buff,0,len*2+1); setlocale(LC_ALL,".936"); int nChars = wcstombs(buff,WindowText,len*2+1); setlocale(LC_ALL,"C"); fwrite(buff,1,nChars,fp); delete buff; #else fwrite(WindowText,1,len,fp); #endif delete[] WindowText; fclose(fp); ::DestroyWindow(hWnd); } /************************************************* *************************** Edit Window的窗口過程 ************************************************** **************************/ LRESULT CALLBACK CTraceWnd::WindowProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam) { switch(message) { case EM_REPLACESEL: { //光標指向最後 ::SendMessage(hWnd,EM_SETSEL,4294967290, 4294967290); //調用默認過程添加字符串到edit 窗口 ::CallWindowProc(OldWndProc, hWnd, message, wParam, lParam); //自動調整窗口的寬度 if (IsAutoWndWidth) { int MinPos,MaxPos; GetScrollRange(hWnd,SB_HORZ, &MinPos,&MaxPos); if (WindowWidth0) FormatString字符串
  trace("測試");
  trace(_T("測試"));
  }
  void CDemoDlg::OnButton2()
  {
  int a=45; double b=67.45;
  trace2(a,b);
  }
  void CDemoDlg::OnButton3()
  {
  POINT point;
  GetCursorPos(&point);
  TracePoint(point);
  }
  void CDemoDlg::OnButton4()
  {
  RECT rect;
  ::GetWindowRect(m_hWnd,&rect);
  TraceRect(rect);
  }
  void CDemoDlg::OnButton5()
  {
  TraceLastError();
  }
  四.幾點說明
  1.輸出函數有以下幾個:
  trace(X) //輸出1個變量
  trace2(X,Y) //輸出2個變量
  trace3(X,Y,Z) //輸出3個變量
  trace4(X,Y,Z,W) //輸出4個變量
  TracePoint(P) //輸出座標型POINT的數據
  TraceRect(X) //輸出RECT型的數據
  TraceLastError()//輸出上次錯誤的代碼號
  2.幾個trace函數都具有自動識別數據類型的功能。
  如:
  int a=45; trace(a); //輸出int型
  char str[10]="jacky"; trace(str); //輸出字符串
  double b=67.45; trace(b); //輸出double型
  3.用trace()函數直接輸出字符串時,可以不添加_T() 或 TEXT() 宏
  trace("my test");
  trace(_T("my test"));
  trace(TEXT("my test"));
  以上三個函數輸出的都是 "my test";
  4.關於一些宏設置:
  1.默認情況下 NO_TRACE_WINDOW 和 TRACE_WINDOW都沒定義,則
  DEBUG版本會輸出調試字符串,而Release版本不會
  2.開頭定義了#define NO_TRACE_WINDOW
  DEBUG版本和Release版本都不會輸出輸出調試字符串
  3.開頭定義了#define TRACE_WINDOW
  DEBUG版本和Release版本都會輸出輸出調試字符串
  4.每次修改後上面2個宏後最好全部重新編譯
  5.上面的代碼支持Unicode,在VC6和VS2008中編譯通過
  五.圖片預覽
  六.示例代碼下載
  trace_Demo.zip (在VC6下編譯通過,支持unicode)(請不要直接使用迅雷下載)
  七.另一個監視變量的工具
  它是高手Paul DiLascia寫的,相信會很不錯。
  http://www.dilascia.com/TraceWin.htm
  八.之前輸出字符串的窗口一直是控制檯窗口,
  現在修改成edit窗口,方便很多。如需要查看控制檯窗口輸出字符串的代碼,請看:
  http://hi.baidu.com/%B4%E7%B2%DD%D0%C4%5F/blog/ite m/d586040f9fe702e2ab645732.html
  九.推薦:
  獅姐的博客(獅子窩,學佛與靈魂之探究)
  大方廣(學習傳統文化)
  慈善點擊(輕鬆一點,行善積德,何樂不爲)
  電影《地球公民》(揭示不爲人知的一面)
  心向光明 遠離邪淫(現世警鐘,不可不看)
  戒淫(上篇)(正淫節慾,戒除邪淫)
  戒淫(中篇)(縱慾之樂,憂患隨之)
  公民教育--命由我造
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章