Windows进程内标准输出重定向及其在程序调试上的应用
2012-09-06 23:36
316 查看
一、如何实现 打印调试信息的方法有很多,最常用的是使用标准输出设备(如printf、cout等),也可以用OutPutDebugString输出、用DebugView工具查看,还可以写入日志文件。如果程序运行需要记录日志(log),往往需要打开个文件,或许是写入系统事件、用系统的事件查看器查看。 应用程序打印调试信息、日志的方法往往是确定的,但如果是要编写一个模块或者说组件,那样的输出信息应该写入哪里呢?或者说程序本身对此也没有明确需求的话,那该怎么办呢? 可喜的是一个进程的标准输出是可以重定向的,所以我建议把调试信息直接打到标准输出上,这样代码中可以统一使用cout或者printf,然后根据需要将标准输出重定向。 Linux中重定向标准输出就容易了,因为有强大的dup2函数。而对于Windows的重定向,貌似往往是用于子进程的,在用CreateProcess创建子进程时设置子进程的标准输出句柄。而我们想要的是重定向自己这个进程的标准输出,那个用不上。我在MSDN中也没找到类似dup2的Win32 API函数,只有一个DuplicateHandle函数,这相当于linux中的dup,也用不上。 这里顺便提下,SetStdHandle是不能实现重定向的。这个函数的功能是将某句柄指向标准设备,并不能将标准设备句柄重定向到另外的句柄。 于是我就想到,Windows不是支持一部分POSIX标准的吗。于是我找到了一个CRT的函数,叫_dup2,看起来是不是特眼熟,对了,这就是Windows中dup2的兼容版本。 值得注意的是,_dup2以及与此相关的一系列CRT中的IO函数(如_read,_write)均以下划线开头,其余与linux大致相同,其参数中所谓的文件描述符与Win32中的句柄不一样,文件描述符实际上是句柄数组的索引,也就是说文件描述符不能与句柄混用。比如0,1,2分别是标准输入、标准输出、标准错误的文件描述符,但句柄值不是这样确定的。文件描述符不是Win32的概念,是POSIX中的概念。 _dup2用法与dup2大致相同,不多解释,不了解的可以查阅dup2相关资料。下面讲点应用。 二、如何应用于调试 写一个模块时,我们可以直接用cout/printf来作调试。但是如果这个模块用于图形界面或许是系统服务呢?这时标准输出看不到了,我们可以用OutPutDebugString函数和DebugView这样的调试工具。这样就带来一种选择,而选择往往是增加软件复杂度的因素。所以我的想法是代码中只用cout/printf,如果需要将其重定向到调试工具中去。 如何实现呢,用匿名管道和线程。 用一个pipe,标准输出重定向到其write端,然后创建一个线程,线程要做的就是从pipe的read端读出数据后用OutPutDebugString输出。 下面是实现代码。 头文件是这样子的,构造时重定向,析构时解除: namespace common { // 将标准输出重定向到DebugView,保持对象存在即有效 class StdoutToDebugString { public: StdoutToDebugString(); ~StdoutToDebugString(); private: int fds_[2]; int orign_stdout_; uintptr_t thread_handle_; }; } 实现文件: #include <io.h> #include <fcntl.h> #include <stdio.h> #include <process.h> #include <Windows.h> #include "StdoutRedirect.h" using namespace common; const int kBufferSize = 4096; unsigned __stdcall RedirectThreadProc(void* param) { int pipe_read = (int)param; char buf[kBufferSize]; int bytes_read; do { bytes_read = ::_read(pipe_read, buf, kBufferSize); buf[bytes_read] = 0; ::OutputDebugString(buf); } while (bytes_read); return 0; }; StdoutToDebugString::StdoutToDebugString() { ::_pipe(fds_, kBufferSize, _O_TEXT); orign_stdout_ = ::_dup(_fileno(stdout)); ::_dup2(fds_[1], _fileno(stdout)); thread_handle_ = ::_beginthreadex(NULL, 0, RedirectThreadProc, (void*)fds_[0], 0, NULL); ::CloseHandle((HANDLE)thread_handle_); } StdoutToDebugString::~StdoutToDebugString() { ::_dup2(orign_stdout_, _fileno(stdout)); } 测试代码: #include <iostream> #include <Windows.h> #include "../Common/StdoutRedirect.h" using namespace std; using namespace common; void main() { StdoutToDebugStringredirect; cout<< "hello" << endl; ::system("pause"); }
相关文章推荐
- Windows进程内标准输出重定向及其在程序调试上的应用
- sys.stdout的应用,Python标准输出sys.stdout的重定向
- c#中重定向windows控制台程序的输出信息
- Windows程序调试之格式化输出
- gdb 重定向标准输出 -- 调试ncurse比较有用
- wxPython 笔记(11)重定向程序输出到标准控制台窗口
- MFC(win32GUI)程序中显示Dos调试信息.console.显示控制台界面.标准输出.
- c#中重定向windows控制台程序的输出信息
- OJ 调试技巧:VS2010 中 通过设置编译参数定义宏,无需修改源文件重定向标准输入输出
- windows下eclipse cdt 无法运行和调试程序,没有输出(调试和运行时不修改系统变量导入第三方dll库)
- linux下通过dup2标准输出重定向查看系统进程方法(也是popen函数实现的方法)
- 重定向已经运行进程的标准输出到文件的办法(通过ptrace注入代码到其他进程并运行)
- 一种将程序的标准输出重定向到telnet终端的方法
- c#中重定向windows控制台程序的输出信息
- 调试程序时在不中断程序的情况下输出函数调用信息(Mac OS,Linux & Windows)
- c#中重定向windows控制台程序的输出信息
- 重新定位windows窗口程序的标准输出
- 调试程序时在不中断程序的情况下输出函数调用信息(Mac OS,Linux & Windows)
- 编写一个小程序,从标准输入读入一系列string对象,寻找连续重复出现的单词。程序应该找出满足一下条件的单词:该单词的后面紧接着再次出现自己本身。跟踪重复次数最多的单词及其重复次数,输出.
- ASCII码的应用(.编写一个程序从标准输入读取字符,并把他们写到标准输出。除了大写字母转换成小写字母之外,其他的原样输出。)