Standard output redirection in Windows and Its Application in program debugging

Source: Internet
Author: User
Tags posix

I. How to Implement

There are many ways to print debugging information. The most common method is to use standard output devices (such as printf and cout). You can also use OutPutDebugString to output and DebugView to view the information, you can also write log files. If the program runs a program that requires logging, you often need to open a file, which may be written to system events and viewed in the System Event Viewer.

The method for printing debugging information and logs of an application is usually definite. But if you want to write a module or component, where should the output information be written? Or if the program itself has no clear requirements for this, what should we do?

Fortunately, the standard output of a process can be redirected. Therefore, we recommend that you directly call the debugging information to the standard output so that cout or printf can be used in the code, then, redirect the standard output as needed.

In Linux, it is easy to redirect standard output because of the powerful dup2 function. Windows redirection is usually used for sub-processes. When CreateProcess is used to create a sub-process, the standard output handle of the sub-process is set. What we want is to redirect the standard output of our own process, which cannot be used. I have not found any Win32 API function similar to dup2 in MSDN. There is only one DuplicateHandle function, which is equivalent to dup in linux and cannot be used.

By the way, SetStdHandle cannot implement redirection. This function points a handle to a standard device and cannot redirect the handle to another device.

So I thought that Windows does not support some POSIX standards. So I found a CRT function named _ dup2, which seems familiar to me. By the way, this is the compatible version of dup2 in Windows.

It is worth noting that _ dup2 and a series of related I/O functions (such as _ read, _ write) in the CRT start with an underscore, and the rest are roughly the same as those in linux, in the parameter, the so-called file descriptor is different from the handle in Win32. The file descriptor is actually the index of the handle array, that is, the file descriptor cannot be mixed with the handle. For example, 0, 1, and 2 are standard input, standard output, and standard error file descriptors, but the handle value is not determined in this way. File descriptors are not Win32 concepts, but POSIX concepts.

_ The usage of dup2 is roughly the same as that of dup2. For more information, see dup2. The following describes the application.

Ii. How to apply it to debugging

When writing a module, we can directly use cout/printf for debugging. But what if this module is used for graphical interfaces or system services? In this case, the standard output is invisible. We can use debugging tools such as OutPutDebugString and DebugView. In this way, there is a choice, and the choice is often a factor that increases the complexity of the software. So my idea is that only cout/printf is used in the Code. If you need to redirect it to the debugging tool.

How to implement it? Use anonymous pipelines and threads.

With a pipe, the standard output is redirected to its write end, and a thread is created. The thread needs to read data from the pipe read end and output the data with OutPutDebugString.

The following is the implementation code.

The header file is like this. It is redirected during construction and removed during analysis:

Namespace common {

// Redirects the standard output to the DebugView to ensure that the object exists.

Class StdoutToDebugString {
Public:
StdoutToDebugString ();

~ StdoutToDebugString ();

Private:
Int fds _ [2];
Int orign_stdout _;
Uintptr_t thread_handle _;
};
}

Implementation file:

# 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 ));
}

Test code:

# Include <iostream>
# Include <Windows. h>
# Include "../Common/StdoutRedirect. h"
Using namespace std;
Using namespace common;

Void main (){
StdoutToDebugStringredirect;
Cout <"hello" <endl;
: System ("pause ");
}
 

When running, you can see that the Console does not print hello, but you can see it in DebugView.

3. Unsolved problems?

Because _ read is blocked, I cannot safely end the thread, so I cannot wait for the thread to end in the destructor. If _ close is used in the destructor to close the file descriptor, when the object has been destructed and the thread is still running, _ read will cause assert to crash.

However, in general, it is no problem to construct such an object at the beginning of main to achieve redirection until the end of main.

We hope you can give us some advice on this issue.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.