前面转载了两篇关于windows下窗口程序printf函数输出的问题,这里做一个简单的总结。
1.我们可以在开发时修改项目的链接属性,把[链接器]-[系统]-[子系统]修改为/SUBSYSTEM:CONSOLE,并把主函数名换成 main,这样在开发阶段就能看到printf输出的调试信息了,到发布时再把这一属性改成SUBSYSTEM:WINDOWS就可以了。前面文章中提到的PeDbg各editbin 工具应该就是修改这一属性。
2.可以用SetStdHandle函数把windows程序的标准输出重定向。可重定向到文件、管道、串口等。但是这个方法比较繁杂,因为在你用SetStdHandle时,运行时库已经设置好了标准输入输出,用SetStdHandle也没法改变。有一个方法,可以在当前进程中改变,然后创建一个子进程,这时子进程继承父里程的设置,可重定向标准输入输出。
下面是MSDN中的一个相关示例:
Creating a Child Process with Redirected Input and Output
The example in this topic demonstrates how to create a child process using the CreateProcess function from a console process. It also demonstrates a technique for using anonymous pipes to redirect the child process's standard input and output handles. Note that named pipes can also be used to redirect process I/O.
The CreatePipe function uses the SECURITY_ATTRIBUTES structure to create inheritable handles to the read and write ends of two pipes. The read end of one pipe serves as standard input for the child process, and the write end of the other pipe is the standard output for the child process. These pipe handles are specified in the STARTUPINFO structure, which makes them the standard handles inherited by the child process.
The parent process uses the other ends of the pipes to write to the child process's input and read the child process's output. The handles to these ends of the pipe are also inheritable. However, the handle must not be inherited. Before creating the child process, the parent process uses SetHandleInformation to ensure that the read handle for standard input and the write handle for standard output cannot be inherited. For more information, see Pipes.
The following is the code for the parent process. It takes a single command-line argument: the name of a text file.
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#define BUFSIZE 4096
HANDLE hChildStdinRd, hChildStdinWr,
hChildStdoutRd, hChildStdoutWr,
hInputFile, hStdout;
BOOL CreateChildProcess(VOID);
VOID WriteToPipe(VOID);
VOID ReadFromPipe(VOID);
VOID ErrorExit(LPSTR);
int _tmain(int argc, TCHAR *argv[])
{
SECURITY_ATTRIBUTES saAttr;
BOOL fSuccess;
// Set the bInheritHandle flag so pipe handles are inherited.
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
// Get the handle to the current STDOUT.
hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
// Create a pipe for the child process's STDOUT.
if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0))
ErrorExit("Stdout pipe creation failed\n");
// Ensure the read handle to the pipe for STDOUT is not inherited.
SetHandleInformation( hChildStdoutRd, HANDLE_FLAG_INHERIT, 0);
// Create a pipe for the child process's STDIN.
if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0))
ErrorExit("Stdin pipe creation failed\n");
// Ensure the write handle to the pipe for STDIN is not inherited.
SetHandleInformation( hChildStdinWr, HANDLE_FLAG_INHERIT, 0);
// Now create the child process.
fSuccess = CreateChildProcess();
if (! fSuccess)
ErrorExit("Create process failed with");
// Get a handle to the parent's input file.
if (argc == 1)
ErrorExit("Please specify an input file");
printf( "\nContents of %s:\n\n", argv[1]);
hInputFile = CreateFile(argv[1], GENERIC_READ, 0, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
if (hInputFile == INVALID_HANDLE_VALUE)
ErrorExit("CreateFile failed");
// Write to pipe that is the standard input for a child process.
WriteToPipe();
// Read from pipe that is the standard output for child process.
ReadFromPipe();
return 0;
}
BOOL CreateChildProcess()
{
TCHAR szCmdline[]=TEXT("child");
PROCESS_INFORMATION piProcInfo;
STARTUPINFO siStartInfo;
BOOL bFuncRetn = FALSE;
// Set up members of the PROCESS_INFORMATION structure.
ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
// Set up members of the STARTUPINFO structure.
ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.hStdError = hChildStdoutWr;
siStartInfo.hStdOutput = hChildStdoutWr;
siStartInfo.hStdInput = hChildStdinRd;
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
// Create the child process.
bFuncRetn = CreateProcess(NULL,
szCmdline, // command line
NULL, // process security attributes
NULL, // primary thread security attributes
TRUE, // handles are inherited
0, // creation flags
NULL, // use parent's environment
NULL, // use parent's current directory
&siStartInfo, // STARTUPINFO pointer
&piProcInfo); // receives PROCESS_INFORMATION
if (bFuncRetn == 0)
ErrorExit("CreateProcess failed\n");
else
{
CloseHandle(piProcInfo.hProcess);
CloseHandle(piProcInfo.hThread);
return bFuncRetn;
}
}
VOID WriteToPipe(VOID)
{
DWORD dwRead, dwWritten;
CHAR chBuf[BUFSIZE];
// Read from a file and write its contents to a pipe.
for (;;)
{
if (! ReadFile(hInputFile, chBuf, BUFSIZE, &dwRead, NULL) ||
dwRead == 0) break;
if (! WriteFile(hChildStdinWr, chBuf, dwRead,
&dwWritten, NULL)) break;
}
// Close the pipe handle so the child process stops reading.
if (! CloseHandle(hChildStdinWr))
ErrorExit("Close pipe failed\n");
}
VOID ReadFromPipe(VOID)
{
DWORD dwRead, dwWritten;
CHAR chBuf[BUFSIZE];
// Close the write end of the pipe before reading from the
// read end of the pipe.
if (!CloseHandle(hChildStdoutWr))
ErrorExit("Closing handle failed");
// Read output from the child process, and write to parent's STDOUT.
for (;;)
{
if( !ReadFile( hChildStdoutRd, chBuf, BUFSIZE, &dwRead,
NULL) || dwRead == 0) break;
if (! WriteFile(hStdout, chBuf, dwRead, &dwWritten, NULL))
break;
}
}
VOID ErrorExit (LPSTR lpszMessage)
{
fprintf(stderr, "%s\n", lpszMessage);
ExitProcess(0);
}
The following is the code for the child process. It uses the inherited handles for STDIN and STDOUT to access the pipe created by the parent. The parent process reads from its input file and writes the information to a pipe. The child receives text through the pipe using STDIN and writes to the pipe using STDOUT. The parent reads from the read end of the pipe and displays the information to its STDOUT.
#include <windows.h>
#define BUFSIZE 4096
VOID main(VOID)
{
CHAR chBuf[BUFSIZE];
DWORD dwRead, dwWritten;
HANDLE hStdin, hStdout;
BOOL fSuccess;
hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
hStdin = GetStdHandle(STD_INPUT_HANDLE);
if ((hStdout == INVALID_HANDLE_VALUE) ||
(hStdin == INVALID_HANDLE_VALUE))
ExitProcess(1);
for (;;)
{
// Read from standard input.
fSuccess = ReadFile(hStdin, chBuf, BUFSIZE, &dwRead, NULL);
if (! fSuccess || dwRead == 0)
break;
// Write to standard output.
fSuccess = WriteFile(hStdout, chBuf, dwRead, &dwWritten, NULL);
if (! fSuccess)
break;
}
}
重新定位windows窗口程序的标准输出
最新推荐文章于 2020-04-28 19:21:14 发布