[转]子进程继承父控制台
原文链接:https://support.microsoft.com/en-us/kb/190351
How to spawn console processes with redirected standard handles
SUMMARY
Note Some console based applications do not use the standard handles for their input/output (IO) operations. The Win32 API does not support redirection of these processes.
MORE INFORMATION
HANDLE hStdInput - Standard input handle of the child process. HANDLE hStdOutput - Standard output handle of the child process. HANDLE hStdError - Standard error handle of the child process.You can set these handles to either a pipe handle, file handle, or any handle that can do synchronous reads and writes through the ReadFile() and WriteFile() API. The handles must be inheritable and the CreateProcess() API must specify that inheritable handles are to be inherited by the child process by specifying TRUE in the bInheritHandles parameter. If the parent process only wishes to redirect one or two standard handles, specifying GetStdHandle() for the specific handles causes the child to create the standard handle as it normally would without redirection. For example, if the parent process only needs to redirect the standard output and error of the child process, then the hStdInput member of the STARTUPINFO structure is filled as follows:
hStdInput = GetStdHandle(STD_INPUT_HANDLE);Note Child processes that use such C run-time functions as printf() and fprintf() can behave poorly when redirected. The C run-time functions maintain separate IO buffers. When redirected, these buffers might not be flushed immediately after each IO call. As a result, the output to the redirection pipe of a printf() call or the input from a getch() call is not flushed immediately and delays, sometimes-infinite delays occur. This problem is avoided if the child process flushes the IO buffers after each call to a C run-time IO function. Only the child process can flush its C run-time IO buffers. A process can flush its C run-time IO buffers by calling the fflush() function.
Note Windows 95 and Windows 98 require an extra step when you redirect the standard handles of certain child processes.
The following sample redirects the standard input, output, and error of the child process specified in the CreateProcess call. This sample redirects the provided console process (Child.c).
Sample code
1 /*++ 2 3 Copyright (c) 1998 Microsoft Corporation 4 5 Module Name: 6 7 Redirect.c 8 9 Description: 10 This sample illustrates how to spawn a child console based 11 application with redirected standard handles. 12 13 The following import libraries are required: 14 user32.lib 15 16 Dave McPherson (davemm) 11-March-98 17 18 --*/ 19 20 #include<windows.h> 21 #pragma comment(lib, "User32.lib") 22 void DisplayError(char *pszAPI); 23 void ReadAndHandleOutput(HANDLE hPipeRead); 24 void PrepAndLaunchRedirectedChild(HANDLE hChildStdOut, 25 HANDLE hChildStdIn, 26 HANDLE hChildStdErr); 27 DWORD WINAPI GetAndSendInputThread(LPVOID lpvThreadParam); 28 29 HANDLE hChildProcess = NULL; 30 HANDLE hStdIn = NULL; // Handle to parents std input. 31 BOOL bRunThread = TRUE; 32 33 34 void main () 35 { 36 HANDLE hOutputReadTmp,hOutputRead,hOutputWrite; 37 HANDLE hInputWriteTmp,hInputRead,hInputWrite; 38 HANDLE hErrorWrite; 39 HANDLE hThread; 40 DWORD ThreadId; 41 SECURITY_ATTRIBUTES sa; 42 43 44 // Set up the security attributes struct. 45 sa.nLength= sizeof(SECURITY_ATTRIBUTES); 46 sa.lpSecurityDescriptor = NULL; 47 sa.bInheritHandle = TRUE; 48 49 50 // Create the child output pipe. 51 if (!CreatePipe(&hOutputReadTmp,&hOutputWrite,&sa,0)) 52 DisplayError("CreatePipe"); 53 54 55 // Create a duplicate of the output write handle for the std error 56 // write handle. This is necessary in case the child application 57 // closes one of its std output handles. 58 if (!DuplicateHandle(GetCurrentProcess(),hOutputWrite, 59 GetCurrentProcess(),&hErrorWrite,0, 60 TRUE,DUPLICATE_SAME_ACCESS)) 61 DisplayError("DuplicateHandle"); 62 63 64 // Create the child input pipe. 65 if (!CreatePipe(&hInputRead,&hInputWriteTmp,&sa,0)) 66 DisplayError("CreatePipe"); 67 68 69 // Create new output read handle and the input write handles. Set 70 // the Properties to FALSE. Otherwise, the child inherits the 71 // properties and, as a result, non-closeable handles to the pipes 72 // are created. 73 if (!DuplicateHandle(GetCurrentProcess(),hOutputReadTmp, 74 GetCurrentProcess(), 75 &hOutputRead, // Address of new handle. 76 0,FALSE, // Make it uninheritable. 77 DUPLICATE_SAME_ACCESS)) 78 DisplayError("DupliateHandle"); 79 80 if (!DuplicateHandle(GetCurrentProcess(),hInputWriteTmp, 81 GetCurrentProcess(), 82 &hInputWrite, // Address of new handle. 83 0,FALSE, // Make it uninheritable. 84 DUPLICATE_SAME_ACCESS)) 85 DisplayError("DupliateHandle"); 86 87 88 // Close inheritable copies of the handles you do not want to be 89 // inherited. 90 if (!CloseHandle(hOutputReadTmp)) DisplayError("CloseHandle"); 91 if (!CloseHandle(hInputWriteTmp)) DisplayError("CloseHandle"); 92 93 94 // Get std input handle so you can close it and force the ReadFile to 95 // fail when you want the input thread to exit. 96 if ( (hStdIn = GetStdHandle(STD_INPUT_HANDLE)) == 97 INVALID_HANDLE_VALUE ) 98 DisplayError("GetStdHandle"); 99 100 PrepAndLaunchRedirectedChild(hOutputWrite,hInputRead,hErrorWrite); 101 102 103 // Close pipe handles (do not continue to modify the parent). 104 // You need to make sure that no handles to the write end of the 105 // output pipe are maintained in this process or else the pipe will 106 // not close when the child process exits and the ReadFile will hang. 107 if (!CloseHandle(hOutputWrite)) DisplayError("CloseHandle"); 108 if (!CloseHandle(hInputRead )) DisplayError("CloseHandle"); 109 if (!CloseHandle(hErrorWrite)) DisplayError("CloseHandle"); 110 111 112 // Launch the thread that gets the input and sends it to the child. 113 hThread = CreateThread(NULL,0,GetAndSendInputThread, 114 (LPVOID)hInputWrite,0,&ThreadId); 115 if (hThread == NULL) DisplayError("CreateThread"); 116 117 118 // Read the child's output. 119 ReadAndHandleOutput(hOutputRead); 120 // Redirection is complete 121 122 123 // Force the read on the input to return by closing the stdin handle. 124 if (!CloseHandle(hStdIn)) DisplayError("CloseHandle"); 125 126 127 // Tell the thread to exit and wait for thread to die. 128 bRunThread = FALSE; 129 130 if (WaitForSingleObject(hThread,INFINITE) == WAIT_FAILED) 131 DisplayError("WaitForSingleObject"); 132 133 if (!CloseHandle(hOutputRead)) DisplayError("CloseHandle"); 134 if (!CloseHandle(hInputWrite)) DisplayError("CloseHandle"); 135 } 136 137 138 /////////////////////////////////////////////////////////////////////// 139 // PrepAndLaunchRedirectedChild 140 // Sets up STARTUPINFO structure, and launches redirected child. 141 /////////////////////////////////////////////////////////////////////// 142 void PrepAndLaunchRedirectedChild(HANDLE hChildStdOut, 143 HANDLE hChildStdIn, 144 HANDLE hChildStdErr) 145 { 146 PROCESS_INFORMATION pi; 147 STARTUPINFO si; 148 149 // Set up the start up info struct. 150 ZeroMemory(&si,sizeof(STARTUPINFO)); 151 si.cb = sizeof(STARTUPINFO); 152 si.dwFlags = STARTF_USESTDHANDLES; 153 si.hStdOutput = hChildStdOut; 154 si.hStdInput = hChildStdIn; 155 si.hStdError = hChildStdErr; 156 // Use this if you want to hide the child: 157 // si.wShowWindow = SW_HIDE; 158 // Note that dwFlags must include STARTF_USESHOWWINDOW if you want to 159 // use the wShowWindow flags. 160 161 162 // Launch the process that you want to redirect (in this case, 163 // Child.exe). Make sure Child.exe is in the same directory as 164 // redirect.c launch redirect from a command line to prevent location 165 // confusion. 166 if (!CreateProcess(NULL,"Child.EXE",NULL,NULL,TRUE, 167 CREATE_NEW_CONSOLE,NULL,NULL,&si,&pi)) 168 DisplayError("CreateProcess"); 169 170 171 // Set global child process handle to cause threads to exit. 172 hChildProcess = pi.hProcess; 173 174 175 // Close any unnecessary handles. 176 if (!CloseHandle(pi.hThread)) DisplayError("CloseHandle"); 177 } 178 179 180 /////////////////////////////////////////////////////////////////////// 181 // ReadAndHandleOutput 182 // Monitors handle for input. Exits when child exits or pipe breaks. 183 /////////////////////////////////////////////////////////////////////// 184 void ReadAndHandleOutput(HANDLE hPipeRead) 185 { 186 CHAR lpBuffer[256]; 187 DWORD nBytesRead; 188 DWORD nCharsWritten; 189 190 while(TRUE) 191 { 192 if (!ReadFile(hPipeRead,lpBuffer,sizeof(lpBuffer), 193 &nBytesRead,NULL) || !nBytesRead) 194 { 195 if (GetLastError() == ERROR_BROKEN_PIPE) 196 break; // pipe done - normal exit path. 197 else 198 DisplayError("ReadFile"); // Something bad happened. 199 } 200 201 // Display the character read on the screen. 202 if (!WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE),lpBuffer, 203 nBytesRead,&nCharsWritten,NULL)) 204 DisplayError("WriteConsole"); 205 } 206 } 207 208 209 /////////////////////////////////////////////////////////////////////// 210 // GetAndSendInputThread 211 // Thread procedure that monitors the console for input and sends input 212 // to the child process through the input pipe. 213 // This thread ends when the child application exits. 214 /////////////////////////////////////////////////////////////////////// 215 DWORD WINAPI GetAndSendInputThread(LPVOID lpvThreadParam) 216 { 217 CHAR read_buff[256]; 218 DWORD nBytesRead,nBytesWrote; 219 HANDLE hPipeWrite = (HANDLE)lpvThreadParam; 220 221 // Get input from our console and send it to child through the pipe. 222 while (bRunThread) 223 { 224 if(!ReadConsole(hStdIn,read_buff,1,&nBytesRead,NULL)) 225 DisplayError("ReadConsole"); 226 227 read_buff[nBytesRead] = '\0'; // Follow input with a NULL. 228 229 if (!WriteFile(hPipeWrite,read_buff,nBytesRead,&nBytesWrote,NULL)) 230 { 231 if (GetLastError() == ERROR_NO_DATA) 232 break; // Pipe was closed (normal exit path). 233 else 234 DisplayError("WriteFile"); 235 } 236 } 237 238 return 1; 239 } 240 241 242 /////////////////////////////////////////////////////////////////////// 243 // DisplayError 244 // Displays the error number and corresponding message. 245 /////////////////////////////////////////////////////////////////////// 246 void DisplayError(char *pszAPI) 247 { 248 LPVOID lpvMessageBuffer; 249 CHAR szPrintBuffer[512]; 250 DWORD nCharsWritten; 251 252 FormatMessage( 253 FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM, 254 NULL, GetLastError(), 255 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 256 (LPTSTR)&lpvMessageBuffer, 0, NULL); 257 258 wsprintf(szPrintBuffer, 259 "ERROR: API = %s.\n error code = %d.\n message = %s.\n", 260 pszAPI, GetLastError(), (char *)lpvMessageBuffer); 261 262 WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE),szPrintBuffer, 263 lstrlen(szPrintBuffer),&nCharsWritten,NULL); 264 265 LocalFree(lpvMessageBuffer); 266 ExitProcess(GetLastError()); 267 } 268 269 ////////////////////////////////////////////////////////////////////// 270 // child.c 271 // Echoes all input to stdout. This will be redirected by the redirect 272 // sample. Compile and build child.c as a Win32 Console application and 273 // put it in the same directory as the redirect sample. 274 // 275 #include<windows.h> 276 #include<stdio.h> 277 #include<string.h> 278 279 void main () 280 { 281 FILE* fp; 282 CHAR szInput[1024]; 283 284 285 // Open the console. By doing this, you can send output directly to 286 // the console that will not be redirected. 287 288 fp = fopen("CON", "w"); 289 if (!fp) { 290 printf("Error opening child console - perhaps there is none.\n"); 291 fflush(NULL); 292 } 293 else 294 { 295 296 // Write a message direct to the console (will not be redirected). 297 298 fprintf(fp,"This data is being printed directly to the\n"); 299 fprintf(fp,"console and will not be redirected.\n\n"); 300 fprintf(fp,"Since the standard input and output have been\n"); 301 fprintf(fp,"redirected data sent to and from those handles\n"); 302 fprintf(fp,"will be redirected.\n\n"); 303 fprintf(fp,"To send data to the std input of this process.\n"); 304 fprintf(fp,"Click on the console window of the parent process\n"); 305 fprintf(fp,"(redirect), and enter data from it's console\n\n"); 306 fprintf(fp,"To exit this process send the string 'exit' to\n"); 307 fprintf(fp,"it's standard input\n"); 308 fflush(fp); 309 } 310 311 ZeroMemory(szInput,1024); 312 while (TRUE) 313 { 314 gets(szInput); 315 printf("Child echoing [%s]\n",szInput); 316 fflush(NULL); // Must flush output buffers or else redirection 317 // will be problematic. 318 if (!_stricmp(szInput,"Exit") ) 319 break; 320 321 ZeroMemory(szInput,strlen(szInput) ); 322 323 } 324 }
作者:红山玉龙
出处:http://www.cnblogs.com/yhLinux/
各位看官如果觉得文章对您有用的话,请猛击右下方大姆指给个推荐,让更多的朋友能够看到,以节约搜索解决方案的时间,用来做更有意义的事情o(∩_∩)o
分享知识是快乐的,也应是自由的。欢迎各位朋友转载,请您在转载时帖上本文原文链接,谢谢!