1. 程式人生 > >MFC窗體程式中呼叫控制檯輸出資訊

MFC窗體程式中呼叫控制檯輸出資訊

最近執行一個MFC對話方塊窗體程式,編譯環境是VS2010,由於需要長時間測試,想像Tomcat那樣開啟一個控制檯輸出日誌。檢視相關資料後,發現其實也不難的,現把呼叫步驟總結一下。

  1. 開啟控制檯輸出
    在程式的InitInstance()函式中新增如下程式碼:
#ifdef _DEBUG
	AllocConsole();
#endif

因為是除錯時需要,所以這裡加上_DEBUG巨集,有初始化就得有關閉,善始善終嘛。在ExitInstance()函式中新增:

#ifdef _DEBUG
	FreeConsole();
#endif
	...
	return CWinApp::ExitInstance();

這樣執行程式,開啟對話方塊同時也打開了控制檯終端:
開啟終端
那麼如何向終端輸出內容呢,需要呼叫WriteConsole函式:

HANDLE g_hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
char out[20] = "測試列印內容\n";
WriteConsole(g_hOutput, out, strlen(out), NULL, NULL);
CloseHandle(g_hOutput);

列印測試內容
我這裡要列印16進位制的金鑰,需要把字串轉16進位制輸出:

char buff[17];
char out[50] = "16進位制:";
 int len = 8;

HANDLE g_hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
DES((unsigned char*)key, source, (unsigned char*)buff);

for (int i=0; i<len; i++) {
	 sprintf(out,"%s%02x", out, (unsigned char)buff[i]);
}
WriteConsole(g_hOutput, out, strlen(out), NULL, NULL);
CloseHandle(g_hOutput);

顯示結果如下:
列印16進位制內容
這裡要注意下CloseHandle函式要在最後呼叫,如果列印“測試列印內容”後呼叫,那後面的16進位制內容就輸出不了了。

  1. 使用printf函式輸出
    使用C的程式設計師都習慣用printf函式,而且格式化輸出很方便,這裡要想使用printf函式輸出,在初始化的時候就麻煩一些了,要進行輸出重定向,InitInstance()函式中修改一下:
#ifdef _DEBUG
	//AllocConsole();
	InitConsoleWindow();
#endif

InitConsoleWindow內容如下:

static int fHandle = -1;
void CDES加密測試App::InitConsoleWindow()
{
	FILE *fp;
	AllocConsole();
	fHandle = _open_osfhandle((long)GetStdHandle(STD_OUTPUT_HANDLE), _O_TEXT);
	if (fHandle > 0)
	{
		fp = _fdopen(fHandle, "w");
		*stdout = *fp;
		setvbuf(stdout, NULL, _IONBF, 0);
	}
}

ExitInstance()函式也修改下:

#ifdef _DEBUG
	if (fHandle > 0)
		_close(fHandle);
	FreeConsole();
#endif
	...
	return CWinApp::ExitInstance();

還要新增上標頭檔案:

#include <io.h>
#include <fcntl.h>

接下來就可以測試使用printf函數了,在使用的地方別忘新增上標頭檔案:

#include <stdio.h> 
...
char buff[17];
char out[50] = "16進位制:";
int len = 8;

//HANDLE g_hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
DES((unsigned char*)key, source, (unsigned char*)buff);

for (int i=0; i<len; i++) {
	sprintf(out,"%s%02x", out, (unsigned char)buff[i]);
}
//WriteConsole(g_hOutput, out, strlen(out), NULL, NULL);
//CloseHandle(g_hOutput);
printf("%s\n", out);

執行結果跟使用WriteConsole輸出是一樣的,這下好用多了。

  1. 關閉問題解決
    無意間先關閉了控制檯終端,程式就發生異常了:
    發生異常
    看來得監聽控制檯的事件資訊,在對話方塊的WriteConsole函式中新增事件回撥函式:
if (::SetConsoleCtrlHandler((PHANDLER_ROUTINE)ConsoleHandler, TRUE) == FALSE)
{
	return FALSE;
}

ConsoleHandler用來處理事件內容,程式碼如下:

BOOL WINAPI ConsoleHandler(DWORD CEvent)
{
	// 處理對應的CTRL_事件
	switch (CEvent) 
	{
	case CTRL_C_EVENT:
	case CTRL_BREAK_EVENT:
	case CTRL_CLOSE_EVENT:
	case CTRL_LOGOFF_EVENT:
	case CTRL_SHUTDOWN_EVENT:
		break;

	default:
		return FALSE;
	} 
	return TRUE;
}

該函式返回TRUE時程式退出,這裡只是簡單測試,如果有需要在關閉前處理的內容請編寫相應程式碼。這次再關閉控制檯視窗時,程式就不報異常了。