WriteFile,WriteConsole和_tprintf的一些差别
这几个API都是用于输出的,但都有各自的特点:
1. _tprintf的实现利用了WriteFile和WideCharToMultiByte。
2. WriteFile只接受字节流,没有UNICODE的概念,WriteFile可以实现重定向。
3. WriteConsole有两个版本WriteConsoleA和WriteConsoleW, 可以分别接收ANSI和UNICODE字符串,不支持重定向。
1. _tprintf的实现利用了WriteFile和WideCharToMultiByte。
2. WriteFile只接受字节流,没有UNICODE的概念,WriteFile可以实现重定向。
3. WriteConsole有两个版本WriteConsoleA和WriteConsoleW, 可以分别接收ANSI和UNICODE字符串,不支持重定向。
看下面这个简单的程序,编译后再用eXeScope分析一下Import
1 #include <stdio.h>
2
3 void wmain(int argc, wchar_t* argv[])
4 {
5 wprintf(L"Hello World\n");
6 }
看了eXeScope的输出后,发现wprintf的实现利用了WideCharToMultiByte和WriteFile等API,在写入文件前首先是将UNICODE转换成多字节的。
然后本人试着直接调用API进行输出,分别使用了API WriteConsole和WriteFile
1 #include <windows.h>
2
3 #pragma comment(lib, "User32")
4 #pragma comment(lib, "Kernel32")
5 #pragma comment(linker, "/Entry:wmain")
6 #pragma comment(linker, "/Merge:.rdata=.text")
7
8 void *operator new[](unsigned int size){
9 return HeapAlloc (GetProcessHeap(), NULL, size);
10 }
11
12 void operator delete[] (void* memblock){
13 HeapFree (GetProcessHeap(), NULL, memblock);
14 }
15
16 bool WINAPI StdOut( wchar_t* lpString)
17 {
18 HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
19 DWORD numOfCharsWritten=0;
20 WriteConsole(hStdOut, lpString, lstrlen(lpString), &numOfCharsWritten, NULL);
21
22 DWORD dwNum = WideCharToMultiByte(CP_OEMCP,NULL,lpString, -1, NULL, 0, NULL, false);
23 char *pText = new char[dwNum];
24 WideCharToMultiByte(CP_OEMCP,NULL,lpString,-1,pText,dwNum,NULL,false);
25 BOOL bRet = WriteFile(hStdOut, pText, dwNum, &numOfCharsWritten, NULL);
26 delete[] pText;
27 return bRet;
28 }
29
30 void wmain()
31 {
32 wchar_t *pChar = L"Hello World!\n";
33 StdOut(pChar);
34 }
命令行编译 cl client.cpp /DUNICODE /D_UNICODE /LINK /ALIGN:16
程序执行结果为:
Hello World!
Hello World!
下面的程序Parent.cpp用于输出重定向
1 #include "stdafx.h"
2 #include <windows.h>
3 #include <tchar.h>
4 #include <stdio.h>
5
6 HANDLE SpawnAndRedirect(LPCTSTR commandLine, HANDLE *hStdOutputReadPipe, LPCTSTR lpCurrentDirectory);
7
8 int _tmain()
9 {
10 HANDLE hOutput, hProcess;
11 hProcess = SpawnAndRedirect(_T("client.exe"), &hOutput, NULL);
12 if (!hProcess){
13 _tprintf(_T("Failed to spawn the thread\n"));
14 return 1;
15 }
16
17 char buffer[129];
18 DWORD read;
19 while(ReadFile(hOutput, buffer, 128, &read, NULL))
20 {
21 buffer[read] = '\0';
22 printf("%s\n", buffer);
23 }
24
25 CloseHandle(hOutput);
26 CloseHandle(hProcess);
27
28 return 0;
29 }
30
31
32 // The following function is a shortened variant of Q190351 - HOWTO: Spawn Console Processes with Redirected Standard Handles
33 // There is no special magic here, and this version doesn't address issues like:
34 // - redirecting Input handle
35 // - spawning 16-bits process
36 // - command-line limitations (unsafe 1024-char buffer)
37 // So you might want to use more advanced versions such as the ones you can find on CodeProject
38 HANDLE SpawnAndRedirect(LPCTSTR commandLine, HANDLE *hStdOutputReadPipe, LPCTSTR lpCurrentDirectory)
39 {
40 HANDLE hStdOutputWritePipe, hStdOutput, hStdError;
41 CreatePipe(hStdOutputReadPipe, &hStdOutputWritePipe, NULL, 0); // create a non-inheritable pipe
42 DuplicateHandle(GetCurrentProcess(), hStdOutputWritePipe,
43 GetCurrentProcess(), &hStdOutput, // duplicate the "write" end as inheritable stdout
44 0, TRUE, DUPLICATE_SAME_ACCESS);
45 DuplicateHandle(GetCurrentProcess(), hStdOutput,
46 GetCurrentProcess(), &hStdError, // duplicate stdout as inheritable stderr
47 0, TRUE, DUPLICATE_SAME_ACCESS);
48 CloseHandle(hStdOutputWritePipe); // no longer need the non-inheritable "write" end of the pipe
49
50 PROCESS_INFORMATION pi;
51 STARTUPINFO si;
52 ZeroMemory(&si, sizeof(STARTUPINFO));
53 si.cb = sizeof(STARTUPINFO);
54 si.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
55 si.hStdInput = GetStdHandle(STD_INPUT_HANDLE); // (this is bad on a GUI app)
56 si.hStdOutput = hStdOutput;
57 si.hStdError = hStdError;
58 si.wShowWindow = SW_HIDE; // IMPORTANT: hide subprocess console window
59 TCHAR commandLineCopy[1024]; // CreateProcess requires a modifiable buffer
60 _tcscpy(commandLineCopy, commandLine);
61 if (!CreateProcess( NULL, commandLineCopy, NULL, NULL, TRUE,
62 CREATE_NEW_CONSOLE, NULL, lpCurrentDirectory, &si, &pi))
63 {
64 CloseHandle(hStdOutput);
65 CloseHandle(hStdError);
66 CloseHandle(*hStdOutputReadPipe);
67 *hStdOutputReadPipe = INVALID_HANDLE_VALUE;
68 return NULL;
69 }
70
71 CloseHandle(pi.hThread);
72 CloseHandle(hStdOutput);
73 CloseHandle(hStdError);
74 return pi.hProcess;
75 }
调用Parent,这个程序会创建子进程Client,并且通过pipe将Client的输出定向为Parent的输出,程序的执行结果为
Hello World!
在Client中WriteConsole的输出没有重定向过来!
Hello World!
在Client中WriteConsole的输出没有重定向过来!
没有评论:
发表评论