一.前言:
一开始学习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 qiujiejia@gmail.com ================================================== ======================*/ #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
九.推荐:
狮姐的博客(狮子窝,学佛与灵魂之探究)
大方广(学习传统文化)
慈善点击(轻松一点,行善积德,何乐不为)
电影《地球公民》(揭示不为人知的一面)
心向光明 远离邪淫(现世警钟,不可不看)
戒淫(上篇)(正淫节欲,戒除邪淫)
戒淫(中篇)(纵欲之乐,忧患随之)
公民教育--命由我造
一开始学习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 qiujiejia@gmail.com ================================================== ======================*/ #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
九.推荐:
狮姐的博客(狮子窝,学佛与灵魂之探究)
大方广(学习传统文化)
慈善点击(轻松一点,行善积德,何乐不为)
电影《地球公民》(揭示不为人知的一面)
心向光明 远离邪淫(现世警钟,不可不看)
戒淫(上篇)(正淫节欲,戒除邪淫)
戒淫(中篇)(纵欲之乐,忧患随之)
公民教育--命由我造