MFC應用程序中添加控制檯窗口

在MFC程序中輸出調試信息的方法有兩種,一種是使用TRACE宏,可以向Output窗口輸出調試信息;另一種是用MessageBox,彈出消息框來輸出調試信息,但會影響程序的運行。
其實有一種方法可以更爲方便的輸出調試信息,就是輸出到控制檯(Console)中,即不影響程序運行,又便於查看調試信息。方法如下:


1.  使用時略顯麻煩。需要建立全局的instance,使用時需要p->print.  不能格式輸出,不太方便。 推薦指數:★★★


在寫MFC這個是一種調試的方法。 
代碼下載


++++++++++++++++++++++


MFC程序利用控制檯輸出調試信息 

 


  
        近日研究師兄的一個MFC程序,見其會生成一個控制檯窗口輸出信息,就如同ANSYS的Output窗口,覺得這個功能實在有用。 
        於是研究了一下他的代碼,不過因爲其爲DLL工程,又可憐我的VC6打不開他的VS2005的Test工程,原先的工程沒有辦法編通過。 
        於是想把實現此功能的類拆出來,仔細研究之後,做了個Test工程,居然不好用,不知道哪裏出了問題。 
        於是google之,有幾個結果可供參考: 
(1)Creating a console for your MFC app's debug output[http://www.codeproject.com/KB/debug/mfcconsole.aspx?df=100&forumid=822&exp=0&select=2656] 
(2)MFC 利用控制檯輸出調試信息   http://blog.csdn.net/wang23432/article/details/5747897
(3) MFC/DLL 編程時用獨立的控制檯窗口顯示用戶自定義調試信息[這篇文章因爲被轉載多次,找不到出處,google標題即可找到] 
(4) GUI程序也能使用控制檯窗口[http://bbs.51cto.com/thread-396954-1-1.html] 
  
        綜合一下,其實現的方法基本一致。 
                1)調用AllocConsole()函數,創建一個Console; 
                2)調用_cprintf()函數,輸出字符串; 
                        或者,重定向輸出流(詳見下文); 
                3)調用FreeConsole()函數,釋放Console。 
  
        爲了使用方便,參考了師兄使用的“單例模式”,寫了下面的class。 

[cpp] view plain copy
  1. //.h  
  2. class CConsolePrinter    
  3. {  
  4. public:  
  5.     void print(const char* str);  
  6.     static void Destroy();  
  7.     static CConsolePrinter* Instance();  
  8.       
  9.       
  10.     virtual ~CConsolePrinter();  
  11.   
  12. protected:  
  13.     CConsolePrinter();  
  14.   
  15. private:  
  16.     static CConsolePrinter* _instance;  
  17.     FILE *file;  
  18.   
  19. };  
  20. //.cpp  
  21. CConsolePrinter* CConsolePrinter::_instance = 0;  
  22.   
  23. CConsolePrinter::CConsolePrinter()  
  24. {  
  25.     // create a new console to the process  
  26.     AllocConsole();  
  27.       
  28.     int hCrun;      
  29.     hCrun = _open_osfhandle((long)GetStdHandle(STD_OUTPUT_HANDLE), _O_TEXT);  
  30.     file  = _fdopen(hCrun, "w");  
  31.       
  32.     // use default stream buffer  
  33.     setvbuf(file, NULL, _IONBF, 0);  
  34.     *stdout = *file;  
  35.   
  36.     std::cout << "Ready!\n";  
  37. }  
  38.   
  39. CConsolePrinter::~CConsolePrinter()  
  40. {  
  41.     FreeConsole();  
  42.     fclose(file);  
  43.   
  44. }  
  45.   
  46. CConsolePrinter* CConsolePrinter::Instance()  
  47. {  
  48.     if (_instance == 0)  
  49.     {  
  50.         _instance = new CConsolePrinter;  
  51.     }  
  52.     return _instance;  
  53. }  
  54.   
  55. void CConsolePrinter::Destroy()  
  56. {  
  57.     if (_instance)  
  58.     {  
  59.         delete _instance;  
  60.     }  
  61.     _instance = 0;  
  62. }  
  63.   
  64. void CConsolePrinter::print(const char *str)  
  65. {  
  66.     std::cout << str << std::endl;  
  67. }  
  68.     
  69.     使用方法也很簡單。  
  70.     首先在應用程序類的InitInstance()函數中添加CConsolePrinter::Instance();,例如:  
  71. BOOL CMfcWithConsoleApp::InitInstance()  
  72. {  
  73.     // details omitted  
  74.   
  75.     // allocate a console  
  76. #ifdef _DEBUG  
  77.     CConsolePrinter::Instance();  
  78. #endif  
  79.   
  80.                      // details omitted  
  81.   
  82.     // The one and only window has been initialized, so show and update it.  
  83.     m_pMainWnd->ShowWindow(SW_SHOW);  
  84.     m_pMainWnd->UpdateWindow();  
  85.   
  86.     return TRUE;  
  87. }  
  88.     
  89.     第二步在應用程序類的ExitInstance()函數中添加CConsolePrinter::Destroy();,例如:  
  90. int CMfcWithConsoleApp::ExitInstance()   
  91. {  
  92.     // TODO: Add your specialized code here and/or call the base class  
  93.   
  94. #ifdef _DEBUG  
  95.     CConsolePrinter::Destroy();  
  96. #endif  
  97.       
  98.     return CWinApp::ExitInstance();  
  99. }  
  100.   
  101.     然後就是在需要輸出字符串信息的地方調用CConsolePrinter::Instance()->print();函數。  
  102. void CMfcWithConsoleDoc::OnEditCopy()   
  103. {   // TODO: Add your command handler code here  
  104. #ifdef _DEBUG  
  105.     CConsolePrinter::Instance()->print("CMfcWithConsoleDoc::OnEditCopy() ");  
  106. #endif    
  107. }  
  108.     需要注意的是,如果關閉控制檯窗口會導致主程序退出。  


++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

2. MFC/DLL 編程時用獨立的控制檯窗口顯示用戶自定義調試信息     推薦指數:★★★★

支持格式輸出!只需在待輸出文件include "DBWindow.h",用DBWindowWrite 代替printf

 不好的地方是程序開始時就會彈出console,顯得不太高級~

我將這個功能封裝爲兩個文件,請將此文本內容下載到本地,保存爲正確的文件名後使用。在不改變源代碼的情況下實現,Debug版顯示調試信息窗口,在Release版下不現實調試窗口且不增加程序負擔。

 

###############DBWindow.h##################

 

/********************************************************************
 創建日期: 2004/09/02
 文件名稱: DBWindow.h
  
      作者: 劉磊(vietor)
      版本: 2.0
      郵箱: 
[email protected]

  創建目的:
      用VC MFC/DLL編程時通常Debug版需要將測試信息通過控制檯輸出,而
      編譯成Release版時需要將這些輸出調試信息的代碼給註釋掉,通
      常這些代碼較多操作比較麻煩。
      這個程序的作用就是爲了程序員在進行MFC/DLL軟件開發時Debug版可以
      在一個單獨的控制檯窗口進行調試程序的輸出,而做成Release版時
      不必手工將這些代碼註釋掉,由此程序自動完成。
      注意:在一個進程之內只存在一個控制檯窗口,對於多個可能同時調試的DLL
      請用顏色識別。
  版權聲明:
      您可以隨意拷貝和使用這個程序的副本,但請保證所有文件的完整和
      不被修改,如果您有修改意見,請與作者聯繫。
 
*********************************************************************/

#ifndef _DBWINDOW_
#define _DBWINDOW_

#include <windows.h>

//控制檯輸出時的文本顏色
#define WDS_T_RED    FOREGROUND_RED
#define WDS_T_GREEN  FOREGROUND_GREEN
#define WDS_T_BLUE  FOREGROUND_BLUE
//控制檯輸出時的文本背景顏色
#define WDS_BG_RED  BACKGROUND_RED
#define WDS_BG_GREEN BACKGROUND_GREEN
#define WDS_BG_BLUE  BACKGROUND_BLUE

#ifdef _DEBUG

//設置控制檯輸出窗口標題
BOOL DBWindowTile(LPCTSTR tile);
//格式化文本輸出
BOOL DBWindowWrite(LPCTSTR fmt,...);
//帶顏色格式化文本輸出
BOOL DBWindowWrite(WORD Attrs,LPCTSTR fmt,...);

#else

#define DBWindowTile
#define DBWindowWrite

#endif

#endif

###############DBWindow.cpp################

/********************************************************************
 創建日期: 2004/09/02
 文件名稱: DBWindow.cpp
  
      作者: 劉磊(vietor)
      版本: 2.0
      郵箱: 
[email protected]

  創建目的:
      用VC MFC/DLL編程時通常Debug版需要將測試信息通過控制檯輸出,而
      編譯成Release版時需要將這些輸出調試信息的代碼給註釋掉,通
      常這些代碼較多操作比較麻煩。
      這個程序的作用就是爲了程序員在進行MFC/DLL軟件開發時Debug版可以
      在一個單獨的控制檯窗口進行調試程序的輸出,而做成Release版時
      不必手工將這些代碼註釋掉,由此程序自動完成。
      注意:在一個進程之內只存在一個控制檯窗口,對於多個可能同時調試的DLL
      請用顏色識別。
  版權聲明:
      您可以隨意拷貝和使用這個程序的副本,但請保證所有文件的完整和
      不被修改,如果您有修改意見,請與作者聯繫。
 
*********************************************************************/


#include "stdafx.h"
#include "DBWindow.h"

#ifdef _DEBUG

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

#define CONSOLE_TILE _T("DBWindow Ver 2.0 by LiuLei")

class ConsoleWindow  
{
public:
  ConsoleWindow();
  virtual ~ConsoleWindow();

  BOOL SetTile(LPCTSTR lpTile);
  BOOL WriteString(LPCTSTR lpString);
  BOOL WriteString(WORD Attrs,LPCTSTR lpString);
private:
  HANDLE m_hConsole;
  BOOL   m_bCreate;
  BOOL   m_bAttrs;
  WORD   m_OldColorAttrs; 
};

ConsoleWindow::ConsoleWindow()
{
 m_hConsole=NULL;
 m_bCreate=FALSE;
 if(AllocConsole())
 {
  m_hConsole=GetStdHandle(STD_OUTPUT_HANDLE);
  SetConsoleTitle(CONSOLE_TILE);
  SetConsoleMode(m_hConsole,ENABLE_PROCESSED_OUTPUT);
  m_bCreate=TRUE;
 }
 else{
  m_hConsole=GetStdHandle(STD_OUTPUT_HANDLE);
  if(m_hConsole==INVALID_HANDLE_VALUE)
   m_hConsole=NULL;
 }
 if(m_hConsole)
 {
  CONSOLE_SCREEN_BUFFER_INFO csbiInfo; 
  if(GetConsoleScreenBufferInfo(m_hConsole, &csbiInfo))
  {
   m_bAttrs=TRUE;
   m_OldColorAttrs = csbiInfo.wAttributes;      
  }
  else{
   m_bAttrs=FALSE;
   m_OldColorAttrs = 0;
  }
 }
}

ConsoleWindow::~ConsoleWindow()
{
 if(m_bCreate)
  FreeConsole();
}

BOOL ConsoleWindow::SetTile(LPCTSTR lpTile)
{
  return SetConsoleTitle(lpTile);
}

BOOL ConsoleWindow::WriteString(LPCTSTR lpString)
{
 BOOL ret=FALSE;
 if(m_hConsole)
 {
  ret=WriteConsole(m_hConsole,lpString,_tcslen(lpString),NULL,NULL);
 }
 return ret;
}

BOOL ConsoleWindow::WriteString(WORD Attrs,LPCTSTR lpString)
{
  BOOL ret=FALSE;
  if(m_hConsole)
  {
    if(m_bAttrs)SetConsoleTextAttribute(m_hConsole,Attrs);
    ret=WriteConsole(m_hConsole,lpString,_tcslen(lpString),NULL,NULL);
    if(m_bAttrs)SetConsoleTextAttribute(m_hConsole,m_OldColorAttrs);
  }
  return ret; 
}

ConsoleWindow  ConWindow;

#define MAX_BUF_LEN 4096

BOOL DBWindowTile(LPCTSTR tile)
{
  return ConWindow.SetTile(tile);
}

BOOL DBWindowWrite(LPCTSTR fmt,...)
{
  TCHAR   message[MAX_BUF_LEN];
  va_list cur_arg;
  va_start(cur_arg,fmt);
  _vsntprintf(message,MAX_BUF_LEN,fmt,cur_arg);
  va_end(cur_arg);
  return ConWindow.WriteString(message);
}

BOOL DBWindowWrite(WORD Attrs,LPCTSTR fmt,...)
{
  TCHAR   message[MAX_BUF_LEN];
  va_list cur_arg;
  va_start(cur_arg,fmt);
  _vsntprintf(message,MAX_BUF_LEN,fmt,cur_arg);
  va_end(cur_arg);
  return ConWindow.WriteString(Attrs,message); 
}

#endif


++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

3.



1、在項目自動生成的stdafx.h文件中添加下面頭文件
#include <io.h>
#include <fcntl.h>
#include <stdio.h>
 
2、把下面的函數加到你初始化的地方,然後你就可以使用printf函數了
void InitConsoleWindow()
{
    int nCrt = 0;
    FILE* fp;
    AllocConsole();
    nCrt = _open_osfhandle((long)GetStdHandle(STD_OUTPUT_HANDLE), _O_TEXT);
    fp = _fdopen(nCrt, "w");
    *stdout = *fp;
    setvbuf(stdout, NULL, _IONBF, 0);
}
以下紅色部分是我初始化函數中添加的
BOOL CSerialPortptestDlg::OnInitDialog()
{
 CDialogEx::OnInitDialog();
  CString str;
 int    Index;
 HKEY   hKey;
 LONG   ret;   
  OSVERSIONINFO     osvi;   
  BOOL   bOsVersionInfoEx;   
 char   keyinfo[100],comm_name[200],ValueName[200];   
 int   i;   
 DWORD   sType,Reserved,cbData,cbValueName;
 // 設置此對話框的圖標。當應用程序主窗口不是對話框時,框架將自動
 //  執行此操作
 SetIcon(m_hIcon, TRUE);   // 設置大圖標
 SetIcon(m_hIcon, FALSE);  // 設置小圖標
 InitConsoleWindow();
 printf( "str   =   %s\n ",   "debug");
調用此函數後會彈出一個CONSOLE,然後printf的東西就會出現在上面。

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

4. MFC 利用控制檯輸出調試信息                                                     推薦指數:★★★★★★

第一種方案:

   WINDOWS爲你提供了一系列的API來完成這個功能,例如:ReadConsole,WriteConsole等,具體參見MSDN。   
    
  1、首先調用AllocConsole函數來爲你進程創建一個Console,該API是將當前進程Attache到一個新創建的   Console 上。你還可以通過調用SetConsoleTitle(tstrName)來設置Console的Title。   
    
  2、使用WriteConsoleOutput來將信息輸出到Console上;在輸出之前,先要得到Console的HANDLE,這通過 GetStdHandle(STD_OUTPUT_HANDLE)來得到,然後將信息組織成Console的格式,然後輸出。   
    
  3、關閉CONSOLE。當不需要這個CONSOLE的時候,調用FreeConsole來將當前進程從Console中Detach中。   
    
  4、通過創建一個進程來爲監視你的CONSOLE輸入和輸出;你可以創建一個線程然後來,在線程中取得標準輸入和輸出CONSOLE的HANDLE,然後循環監視其事件,再對不同的事件進行處理。   
      
第二種方案:   
      在 Project | Setting 中,選項 Post-builder  step 裏新建command,輸入:     
                             editbin   /SUBSYSTEM:CONSOLE   $(OUTDIR)/filename.exe     
               (其中 filename 爲可執行文件名)     
      則可以使用 printf 或者 std::cout在控制檯中輸出了。

      例如你的可執行文件名爲 HelloWorld.exe,則你新建的 command  就爲    
               editbin /SUBSYSTEM:CONSOLE $(OUTDIR)/HelloWorld.exe      

需注意空格問題,eg:  editbin   /SUBSYSTEM:CONSOLE  C:/Users/.../Documents/"Visual Studio 2008"/Projects/HelloMFC2/Debug/HelloMFC2.exe

清理工程後重新編譯。  我用了第二種方案,比較快捷而且簡單。  


第三種方案:

      就用TRACE,然後編譯debug的工程,直接運行你的可執行文件,可以用Dbgview來獲得輸出
第四種方案:

      http://community.csdn.net/Expert/FAQ/FAQ_Index.asp id=186174

第五種方案:

      就是將你的調試信息輸出到文件,如 *.txt 文件                                                     


+++++++++++++++++++++++++++++++++++++++++++++++

+++++++++++++++++++++++++++++++++++++++++++++++

+++++++++++++++++++++++++++++++++++++++++++++++

其餘參考:

1.   沒看懂: http://blog.csdn.net/zhuqinglu/article/details/2454524

2.

MFC窗體程序中添加調試控制檯

在編寫複雜程序的過程中,我們經常需要將一些信息輸出到文件或者屏幕上。較控制檯應用程序,MFC窗體程序要顯得麻煩一些!

下面有2種方法來實現爲MFC窗體程序添加調試控制檯,方便程序員調試程序和了解當前程序的運行狀態。

重要Windows API:AllocConsole();   //創建Console窗口

                         FreeConsole();     //銷燬Console窗口

(1)啓動控制檯窗口

需要包含的頭文件

#include <io.h>

#include <cstdio>

#include <FCNTL.H>

void CTestDebugConsoleDlg::OnBnClickedButton6()
{
// start debugconsole

AllocConsole();
intptr_t handle
= (intptr_t)GetStdHandle(STD_OUTPUT_HANDLE);
int hCrt = _open_osfhandle(handle,_O_TEXT);
FILE 
* hf = _fdopen( hCrt, "w" );
*stdout =*hf;

char title[1024={0};
sprintf_s(title, 
1024"DebugCosole[%u]", (unsigned long)(this->GetSafeHwnd()));
SetConsoleTitle(title);
SetConsoleTextAttribute((HANDLE)handle, FOREGROUND_RED 
| FOREGROUND_BLUE | FOREGROUND_INTENSITY);

HWND hwnd
=NULL; 
while(NULL==hwnd) hwnd=::FindWindow(NULL,(LPCTSTR)title); 

HMENU hmenu 
= ::GetSystemMenu ( hwnd, FALSE ); 
DeleteMenu ( hmenu, SC_CLOSE, MF_BYCOMMAND );

}

MFC窗體測試程序:

Console信息顯示:

代碼下載(VS2008):http://files.cnblogs.com/kekec/DebugConsole.rar

 

(2)設計另外一個MFC窗體程序

關於這種方法請詳見 Azure Product 的 “實現一個通用的調試控制檯”。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章