วิธีการ spawn กระบวนการคอนโซลที่จับมาตรฐานเปลี่ยนเส้นทาง

การแปลบทความ การแปลบทความ
หมายเลขบทความ (Article ID): 190351 - ผลิตภัณฑ์ที่เกี่ยวข้องในบทความนี้
ขยายทั้งหมด | ยุบทั้งหมด

เนื้อหาบนหน้านี้

สรุป

บทความนี้อธิบายวิธีการเปลี่ยนเส้นทางการป้อนข้อมูลและผลลัพธ์ของกระบวนการลูกที่ได้รับค่านำเข้าจากหมายเลขอ้างอิงสำหรับการป้อนค่ามาตรฐาน หรือส่งออกไปยังหมายเลขอ้างอิงของการแสดงผลมาตรฐาน Win32 API ช่วยให้โปรแกรมประยุกต์เพื่อ spawn กระบวนการคอนโซลลูกกับการจัดการมาตรฐานเปลี่ยนเส้นทาง ลักษณะการทำงานนี้ช่วยให้กระบวนการหลักส่ง และรับค่านำเข้าและขาออกของกระบวนการย่อย

หมายเหตุ:โปรแกรมประยุกต์บางโปรแกรมคอนโซลที่ใช้ไม่ได้ใช้จัดการกับมาตรฐานสำหรับการดำเนินการ (IO) ของตนอินพุต/เอาท์พุต Win32 API ไม่สนับสนุนการเปลี่ยนเส้นทางของกระบวนการเหล่านี้

ข้อมูลเพิ่มเติม

API CreateProcess() ผ่านโครงสร้าง STARTUPINFO ช่วยให้คุณจัดการกับมาตรฐานของลูกคอนโซลที่ขึ้นอยู่กับกระบวนการเปลี่ยนเส้นทาง ถ้ามีกำหนดสมาชิก dwFlags เป็น STARTF_USESTDHANDLES จากนั้นสมาชิก STARTUPINFO ต่อไปนี้ระบุจุดจับมาตรฐานของกระบวนการคอนโซลที่ใช้ลูก:
   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.
				
คุณสามารถตั้งค่าเหล่านี้จัดการกับค่าแฮนเดิลของไปป์ หมายเลขอ้างอิงแฟ้ม หรือมีหมายเลขอ้างอิงที่สามารถทำแบบซิงโครนัสอ่านและเขียนข้อมูลผ่าน ReadFile() และ WriteFile() API จับต้องสืบทอดได้ และ CreateProcess() API ต้องระบุว่า จุดจับที่สืบทอดได้รับมา โดยการดำเนินการย่อย โดยการระบุ TRUE ในพารามิเตอร์ bInheritHandles ถ้ากระบวนการหลักเท่านั้น wishes การเปลี่ยนเส้นทางหนึ่ง หรือสองจับมาตรฐาน การระบุ GetStdHandle() สำหรับการจัดการกับเฉพาะสาเหตุย่อยเพื่อสร้างหมายเลขอ้างอิงมาตรฐาน ตามที่มันปกติ โดยไม่มีการเปลี่ยนเส้นทาง ตัวอย่างเช่น ถ้ากระบวนการหลักเท่านั้นจำเป็นต้องเปลี่ยนเส้นทางขาออกที่มาตรฐานและข้อผิดพลาดของกระบวนการย่อย จากนั้นสมาชิก hStdInput ของโครงสร้าง STARTUPINFO จะถูกกรอกข้อมูลต่อไปนี้:
   hStdInput = GetStdHandle(STD_INPUT_HANDLE);
				
หมายเหตุ:กระบวนการย่อยที่ใช้ฟังก์ชันการทำเช่น C printf() และ fprintf() สามารถทำงานไม่ดีเมื่อมีการเปลี่ยนเส้นทาง ฟังก์ชันการทำ C รักษาบัฟเฟอร์ IO แยกต่างหาก เมื่อมีการเปลี่ยนเส้นทาง บัฟเฟอร์เหล่านี้อาจไม่สามารถ flushed ทันทีหลังจากแต่ละ IO เรียก ด้วยเหตุ ผลลัพธ์การไปป์เปลี่ยนเส้นทางของสาย printf() หรือป้อนข้อมูลการจากการเรียก getch() คือไม่ flushed ทันที และความล่าช้า เกิดความล่าช้าในบางครั้ง-infinite ปัญหานี้คือ avoided ถ้ากระบวนการย่อย flushes บัฟเฟอร์ IO หลังจากแต่ละการเรียกไปยังฟังก์ชัน IO ทำ C เฉพาะกระบวนการย่อยสามารถล้างบัฟเฟอร์การ IO เวลารันของ C กระบวนการสามารถล้างบัฟเฟอร์การ IO เวลารันของ C โดยการเรียกฟังก์ชัน fflush()

หมายเหตุ:windows 95 และ Windows 98 ต้องใช้ขั้นตอนที่พิเศษเมื่อคุณเปลี่ยนเส้นทางการจัดการกับมาตรฐานของกระบวนการย่อยที่แน่นอน

ตัวอย่างต่อไปนี้ที่เปลี่ยนเส้นทางการป้อนข้อมูลมาตรฐาน ออก และข้อผิดพลาดของกระบวนการย่อยที่ระบุในการเรียก CreateProcess ตัวอย่างนี้เปลี่ยนเส้นทางการประมวลผลคอนโซลที่ให้มา (Child.c)

โค้ดตัวอย่าง

   /*++

      Copyright (c) 1998  Microsoft Corporation

      Module Name:

         Redirect.c

      Description:
          This sample illustrates how to spawn a child console based
          application with redirected standard handles.

          The following import libraries are required:
          user32.lib

      Dave McPherson (davemm)   11-March-98

   --*/ 

   #include<windows.h>
   #pragma comment(lib, "User32.lib")
   void DisplayError(char *pszAPI);
   void ReadAndHandleOutput(HANDLE hPipeRead);
   void PrepAndLaunchRedirectedChild(HANDLE hChildStdOut,
                                     HANDLE hChildStdIn,
                                     HANDLE hChildStdErr);
   DWORD WINAPI GetAndSendInputThread(LPVOID lpvThreadParam);

   HANDLE hChildProcess = NULL;
   HANDLE hStdIn = NULL; // Handle to parents std input.
   BOOL bRunThread = TRUE;


   void main ()
   {
      HANDLE hOutputReadTmp,hOutputRead,hOutputWrite;
      HANDLE hInputWriteTmp,hInputRead,hInputWrite;
      HANDLE hErrorWrite;
      HANDLE hThread;
      DWORD ThreadId;
      SECURITY_ATTRIBUTES sa;


      // Set up the security attributes struct.
      sa.nLength= sizeof(SECURITY_ATTRIBUTES);
      sa.lpSecurityDescriptor = NULL;
      sa.bInheritHandle = TRUE;


      // Create the child output pipe.
      if (!CreatePipe(&hOutputReadTmp,&hOutputWrite,&sa,0))
         DisplayError("CreatePipe");


      // Create a duplicate of the output write handle for the std error
      // write handle. This is necessary in case the child application
      // closes one of its std output handles.
      if (!DuplicateHandle(GetCurrentProcess(),hOutputWrite,
                           GetCurrentProcess(),&hErrorWrite,0,
                           TRUE,DUPLICATE_SAME_ACCESS))
         DisplayError("DuplicateHandle");


      // Create the child input pipe.
      if (!CreatePipe(&hInputRead,&hInputWriteTmp,&sa,0))
         DisplayError("CreatePipe");


      // Create new output read handle and the input write handles. Set
      // the Properties to FALSE. Otherwise, the child inherits the
      // properties and, as a result, non-closeable handles to the pipes
      // are created.
      if (!DuplicateHandle(GetCurrentProcess(),hOutputReadTmp,
                           GetCurrentProcess(),
                           &hOutputRead, // Address of new handle.
                           0,FALSE, // Make it uninheritable.
                           DUPLICATE_SAME_ACCESS))
         DisplayError("DupliateHandle");

      if (!DuplicateHandle(GetCurrentProcess(),hInputWriteTmp,
                           GetCurrentProcess(),
                           &hInputWrite, // Address of new handle.
                           0,FALSE, // Make it uninheritable.
                           DUPLICATE_SAME_ACCESS))
      DisplayError("DupliateHandle");


      // Close inheritable copies of the handles you do not want to be
      // inherited.
      if (!CloseHandle(hOutputReadTmp)) DisplayError("CloseHandle");
      if (!CloseHandle(hInputWriteTmp)) DisplayError("CloseHandle");


      // Get std input handle so you can close it and force the ReadFile to
      // fail when you want the input thread to exit.
      if ( (hStdIn = GetStdHandle(STD_INPUT_HANDLE)) ==
                                                INVALID_HANDLE_VALUE )
         DisplayError("GetStdHandle");

      PrepAndLaunchRedirectedChild(hOutputWrite,hInputRead,hErrorWrite);


      // Close pipe handles (do not continue to modify the parent).
      // You need to make sure that no handles to the write end of the
      // output pipe are maintained in this process or else the pipe will
      // not close when the child process exits and the ReadFile will hang.
      if (!CloseHandle(hOutputWrite)) DisplayError("CloseHandle");
      if (!CloseHandle(hInputRead )) DisplayError("CloseHandle");
      if (!CloseHandle(hErrorWrite)) DisplayError("CloseHandle");


      // Launch the thread that gets the input and sends it to the child.
      hThread = CreateThread(NULL,0,GetAndSendInputThread,
                              (LPVOID)hInputWrite,0,&ThreadId);
      if (hThread == NULL) DisplayError("CreateThread");


      // Read the child's output.
      ReadAndHandleOutput(hOutputRead);
      // Redirection is complete


      // Force the read on the input to return by closing the stdin handle.
      if (!CloseHandle(hStdIn)) DisplayError("CloseHandle");


      // Tell the thread to exit and wait for thread to die.
      bRunThread = FALSE;

      if (WaitForSingleObject(hThread,INFINITE) == WAIT_FAILED)
         DisplayError("WaitForSingleObject");

      if (!CloseHandle(hOutputRead)) DisplayError("CloseHandle");
      if (!CloseHandle(hInputWrite)) DisplayError("CloseHandle");
   }


   /////////////////////////////////////////////////////////////////////// 
   // PrepAndLaunchRedirectedChild
   // Sets up STARTUPINFO structure, and launches redirected child.
   /////////////////////////////////////////////////////////////////////// 
   void PrepAndLaunchRedirectedChild(HANDLE hChildStdOut,
                                     HANDLE hChildStdIn,
                                     HANDLE hChildStdErr)
   {
      PROCESS_INFORMATION pi;
      STARTUPINFO si;

      // Set up the start up info struct.
      ZeroMemory(&si,sizeof(STARTUPINFO));
      si.cb = sizeof(STARTUPINFO);
      si.dwFlags = STARTF_USESTDHANDLES;
      si.hStdOutput = hChildStdOut;
      si.hStdInput  = hChildStdIn;
      si.hStdError  = hChildStdErr;
      // Use this if you want to hide the child:
      //     si.wShowWindow = SW_HIDE;
      // Note that dwFlags must include STARTF_USESHOWWINDOW if you want to
      // use the wShowWindow flags.


      // Launch the process that you want to redirect (in this case,
      // Child.exe). Make sure Child.exe is in the same directory as
      // redirect.c launch redirect from a command line to prevent location
      // confusion.
      if (!CreateProcess(NULL,"Child.EXE",NULL,NULL,TRUE,
                         CREATE_NEW_CONSOLE,NULL,NULL,&si,&pi))
         DisplayError("CreateProcess");


      // Set global child process handle to cause threads to exit.
      hChildProcess = pi.hProcess;


      // Close any unnecessary handles.
      if (!CloseHandle(pi.hThread)) DisplayError("CloseHandle");
   }


   /////////////////////////////////////////////////////////////////////// 
   // ReadAndHandleOutput
   // Monitors handle for input. Exits when child exits or pipe breaks.
   /////////////////////////////////////////////////////////////////////// 
   void ReadAndHandleOutput(HANDLE hPipeRead)
   {
      CHAR lpBuffer[256];
      DWORD nBytesRead;
      DWORD nCharsWritten;

      while(TRUE)
      {
         if (!ReadFile(hPipeRead,lpBuffer,sizeof(lpBuffer),
                                          &nBytesRead,NULL) || !nBytesRead)
         {
            if (GetLastError() == ERROR_BROKEN_PIPE)
               break; // pipe done - normal exit path.
            else
               DisplayError("ReadFile"); // Something bad happened.
         }

         // Display the character read on the screen.
         if (!WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE),lpBuffer,
                           nBytesRead,&nCharsWritten,NULL))
            DisplayError("WriteConsole");
      }
   }


   /////////////////////////////////////////////////////////////////////// 
   // GetAndSendInputThread
   // Thread procedure that monitors the console for input and sends input
   // to the child process through the input pipe.
   // This thread ends when the child application exits.
   /////////////////////////////////////////////////////////////////////// 
   DWORD WINAPI GetAndSendInputThread(LPVOID lpvThreadParam)
   {
      CHAR read_buff[256];
      DWORD nBytesRead,nBytesWrote;
      HANDLE hPipeWrite = (HANDLE)lpvThreadParam;

      // Get input from our console and send it to child through the pipe.
      while (bRunThread)
      {
         if(!ReadConsole(hStdIn,read_buff,1,&nBytesRead,NULL))
            DisplayError("ReadConsole");

         read_buff[nBytesRead] = '\0'; // Follow input with a NULL.

         if (!WriteFile(hPipeWrite,read_buff,nBytesRead,&nBytesWrote,NULL))
         {
            if (GetLastError() == ERROR_NO_DATA)
               break; // Pipe was closed (normal exit path).
            else
            DisplayError("WriteFile");
         }
      }

      return 1;
   }


   /////////////////////////////////////////////////////////////////////// 
   // DisplayError
   // Displays the error number and corresponding message.
   /////////////////////////////////////////////////////////////////////// 
   void DisplayError(char *pszAPI)
   {
       LPVOID lpvMessageBuffer;
       CHAR szPrintBuffer[512];
       DWORD nCharsWritten;

       FormatMessage(
                FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
                NULL, GetLastError(),
                MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                (LPTSTR)&lpvMessageBuffer, 0, NULL);

       wsprintf(szPrintBuffer,
         "ERROR: API    = %s.\n   error code = %d.\n   message    = %s.\n",
                pszAPI, GetLastError(), (char *)lpvMessageBuffer);

       WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE),szPrintBuffer,
                     lstrlen(szPrintBuffer),&nCharsWritten,NULL);

       LocalFree(lpvMessageBuffer);
       ExitProcess(GetLastError());
   }

   ////////////////////////////////////////////////////////////////////// 
   // child.c
   // Echoes all input to stdout. This will be redirected by the redirect
   // sample. Compile and build child.c as a Win32 Console application and
   // put it in the same directory as the redirect sample.
   // 
   #include<windows.h>
   #include<stdio.h>
   #include<string.h>

   void main ()
   {
      FILE*    fp;
      CHAR     szInput[1024];


      // Open the console. By doing this, you can send output directly to
      // the console that will not be redirected.

      fp = fopen("CON", "w");
      if (!fp) {
         printf("Error opening child console - perhaps there is none.\n");
         fflush(NULL);
      }
      else
      {

      // Write a message direct to the console (will not be redirected).

         fprintf(fp,"This data is being printed directly to the\n");
         fprintf(fp,"console and will not be redirected.\n\n");
         fprintf(fp,"Since the standard input and output have been\n");
         fprintf(fp,"redirected data sent to and from those handles\n");
         fprintf(fp,"will be redirected.\n\n");
         fprintf(fp,"To send data to the std input of this process.\n");
         fprintf(fp,"Click on the console window of the parent process\n");
         fprintf(fp,"(redirect), and enter data from it's console\n\n");
         fprintf(fp,"To exit this process send the string 'exit' to\n");
         fprintf(fp,"it's standard input\n");
         fflush(fp);
      }

      ZeroMemory(szInput,1024);
      while (TRUE)
      {
         gets(szInput);
         printf("Child echoing [%s]\n",szInput);
         fflush(NULL);  // Must flush output buffers or else redirection
                        // will be problematic.
         if (!_stricmp(szInput,"Exit") )
            break;

         ZeroMemory(szInput,strlen(szInput) );

      }
   }

ข้อมูลอ้างอิง

เอกสารประกอบ SDK ไลบรารีของ MSDN: CreateProcess(); STARTUPINFO โครงสร้าง

ตัวอย่างใน SDK แพลตฟอร์มที่ Win32 ภายใต้การสืบทอดมา:
   \MSSDK\samples\winbase\ipc\inherit
				

คุณสมบัติ

หมายเลขบทความ (Article ID): 190351 - รีวิวครั้งสุดท้าย: 7 มกราคม 2554 - Revision: 4.0
ใช้กับ
  • Microsoft Win32 Application Programming Interface
Keywords: 
kbapi kbconsole kbFAQ kbhowto kbipc kbkernbase kbmt KB190351 KbMtth
แปลโดยคอมพิวเตอร์
ข้อมูลสำคัญ: บทความนี้แปลโดยซอฟต์แวร์การแปลด้วยคอมพิวเตอร์ของ Microsoft แทนที่จะเป็นนักแปลที่เป็นบุคคล Microsoft มีบทความที่แปลโดยนักแปลและบทความที่แปลด้วยคอมพิวเตอร์ เพื่อให้คุณสามารถเข้าถึงบทความทั้งหมดในฐานความรู้ของเรา ในภาษาของคุณเอง อย่างไรก็ตาม บทความที่แปลด้วยคอมพิวเตอร์นั้นอาจมีข้อบกพร่อง โดยอาจมีข้อผิดพลาดในคำศัพท์ รูปแบบการใช้ภาษาและไวยากรณ์ เช่นเดียวกับกรณีที่ชาวต่างชาติพูดผิดเมื่อพูดภาษาของคุณ Microsoft ไม่มีส่วนรับผิดชอบต่อความคลาดเคลื่อน ความผิดพลาดหรือความเสียหายที่เกิดจากการแปลเนื้อหาผิดพลาด หรือการใช้บทแปลของลูกค้า และ Microsoft มีการปรับปรุงซอฟต์แวร์การแปลด้วยคอมพิวเตอร์อยู่เป็นประจำ
ต่อไปนี้เป็นฉบับภาษาอังกฤษของบทความนี้:190351

ให้ข้อเสนอแนะ

 

Contact us for more help

Contact us for more help
Connect with Answer Desk for expert help.
Get more support from smallbusiness.support.microsoft.com