父子进程通过管道通信(MFC重定向)

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

今天领导心血来潮说服务器的运行界面是一个黑乎乎的控制台,太低端了,看我们能不能把它图形化,至少做成一个窗口有按钮点启动、停止。好吧,领导拍脑袋就叫人干活的事不少,也没有产品规划,也就是让他看的舒服,只能去做了。

其中有一个关键性问题,就是原先是往控制台输出的信息,使用mfc图形化之后该往哪输出,工程维护人员肯定还是希望能在图形界面上能够看到这些信息的,因此就涉及到了如何获取到输出控制台的消息(都是cout、printf这种标准输出),然后再将这些消息重写到view上。这时候想到了标准输出重定向,因此整理了下思路:

1.将标准输出重定向到管道

2.创建一个线程从管道里取出数据

3.在view的OnPaint中将数据显示出来

二、实现

1.创建管道

[cpp]view plaincopyprint?

1.BOOL bRet = CreatePipe(&hRead, &hWrite, NULL, 0); // 创建匿名管道

2.if (bRet != TRUE)

3. printf("创建匿名管道失败,错误代码:%d\n", GetLastError());

2.将标准输出重定向到管道的写句柄中

[cpp]view plaincopyprint?

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.创建线程从管道取数据

[cpp]view plaincopyprint?

1.boost::thread thr(boost::bind(&CKDSShellView::print_cb, this));

这里用到boost的thread创建线程,CKDSShellView就是你自己的view了,print_cb是自定义的线程函数。

[cpp]view plaincopyprint?

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容器中。

[cpp]view plaincopyprint?

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 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()。

[cpp]view plaincopyprint?

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; // 字体高度

相关文档
最新文档