控制台输出重定向到MFC的view对象里
转载自:https://www.xuebuyuan.com/2017000.html
一、思路:
1.将标准输出重定向到管道
2.创建一个线程从管道里取出数据
3.在view的OnPaint中将数据显示出来
二、实现
1.创建管道
1 BOOL bRet = CreatePipe(&hRead, &hWrite, NULL, 0); // 创建匿名管道 2 if (bRet != TRUE) 3 printf("创建匿名管道失败,错误代码:%d\n", GetLastError());
2.将标准输出重定向到管道的写句柄中
1 int nOpenHandle = _open_osfhandle((intptr_t)hWrite, _O_TEXT); 2 FILE* fp = _fdopen( nOpenHandle, "w"); 3 *stdout = *fp;
注意:这里不能使用SetStdHandle(STD_OUTPUT_HANDLE, hWrite),在MFC中SetStdHandle是没有效果的。
3.创建线程从管道取数据
boost::thread thr(boost::bind(&CKDSShellView::print_cb, this));
这里用到boost的thread创建线程,CKDSShellView就是你自己的view了,print_cb是自定义的线程函数。
1 void CKDSShellView::print_cb() 2 { 3 DWORD ReadNum = 0; 4 char ReadBuf[1024] = {0}; 5 while (1) 6 { 7 memset(ReadBuf, 0, 1024); 8 ReadFile(hRead, ReadBuf, 1024, &ReadNum, NULL); 9 10 if (ReadNum == 0 || ReadBuf[0] == 0) 11 { 12 continue; 13 } 14 this->AppendLog(ReadBuf); 15 } 16 }
死循环,通过ReadFile函数从管道的读句柄hRead中取出数据,然后AppendLog到一个vector容器中。
1 void CKDSShellView::AppendLog(const std::string& strLog) 2 { 3 if (log_vector.size() > 1024) 4 { 5 log_vector.erase(log_vector.begin()); 6 } 7 8 std::vector<std::string> tmp; 9 boost::split(tmp, strLog, boost::is_any_of("\n")); 10 11 for (int i = 0; i < tmp.size(); ++i) 12 { 13 boost::trim(tmp[i]); 14 if (!tmp[i].empty()) 15 { 16 std::string str = tmp[i]; 17 std::string::iterator it = str.end(); 18 while(str.size() > 1) 19 { 20 it = str.end() - 1; 21 if(*it == '\n' || *it == '\r') 22 { 23 str.erase(it); 24 } 25 else 26 { 27 break; 28 } 29 } 30 log_vector.push_back(str); 31 } 32 } 33 if(::IsWindow(m_hWnd)) 34 { 35 Invalidate(); 36 this->UpdateWindow(); 37 } 38 }
由于输出的字符串有\n\r的换行符,并且可能有多条日志同时输出,在view中显示不美观,因此做了一些字串的调整,主要是有log_vector.push_back(str),这是将处理好的字符串装入容器中,然后通过UpdateWindow()触发view的OnPaint()。
1 void CKDSShellView::OnPaint() 2 { 3 CPaintDC dc(this); // device context for painting 4 // TODO: 在此处添加消息处理程序代码 5 // Set the text color to red 6 dc.SetTextColor(RGB(0, 0, 0)); // 可根据日志警告级别改变字体颜色 7 8 // Set the background mode for text to transparent 9 // so background will show thru. 10 dc.SetBkMode(TRANSPARENT); 11 12 ////////////////////////////////////////////////////////////////////////// 13 TEXTMETRIC tm; 14 dc.GetTextMetrics(&tm); 15 16 int nFontHeight = tm.tmHeight; // 字体高度 17 int nExternal = tm.tmExternalLeading; // 估计是行距 18 19 CRect rect; 20 GetWindowRect(&rect); 21 int nMaxShowLine = rect.Height() / (nFontHeight * 1.1); 22 23 int i = 0; 24 if(nMaxShowLine < log_vector.size()) 25 { 26 i = log_vector.size() - nMaxShowLine; 27 } 28 int j = 0; 29 for(; i < log_vector.size(); i++) 30 { 31 x = 4; 32 y = j * nFontHeight * 1.1; 33 dc.TextOut(x,y,log_vector[i].c_str(),log_vector[i].length()); 34 j++; 35 } 36 // 不为绘图消息调用 CView::OnPaint() 37 }

没有坚守就没有事业,没有执着就没有未来!
浙公网安备 33010602011771号