2010-07-24 20 views
6

Điều tôi muốn làm tương tự với những gì Visual Studio thực hiện trong cửa sổ đầu ra của nó hoặc các trình soạn thảo khác trong cửa sổ công cụ của họ: Bắt đầu một quy trình B khác từ quy trình A của tôi và bắt đầu ra stdout/stderr của nó.Cách lấy stdout từ một tiến trình khác trong Win32 mà không có độ trễ?

Cho đến nay, tôi đã làm việc với CreatePipe(), nhưng vì một lý do nào đó, đầu ra của B không đến B ngay khi được viết. Nó hoạt động giống như một bộ đệm của một số loại được lấp đầy và khi nó đầy, tất cả các nội dung bộ đệm đến A cùng một lúc. Tôi đã viết chương trình thử nghiệm của riêng mình để xuất kết quả và thực hiện trực tiếp fflush(stdout) sau đó. Sau đó, đầu ra trực tiếp đến A. Nhưng tôi không thể thay đổi mã của tất cả các quy trình B tôi muốn sử dụng theo cách đó. Cố gắng tuôn ra ống từ A cũng không hoạt động.

Làm cách nào để hoạt động?

mã khởi tạo của tôi cũng như đang tiêu thụ:

sa.nLength = sizeof(SECURITY_ATTRIBUTES); 
sa.bInheritHandle = TRUE; 
sa.lpSecurityDescriptor = NULL; 

err = CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &sa, stdouthistory); 
if (err == 0) 
    return 1; 
err = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd, 
         GetCurrentProcess(), &hChildStdoutRdDup , 0, 
         FALSE, 
         DUPLICATE_SAME_ACCESS); 
if (err == 0) 
    return 3; 
CloseHandle(hChildStdoutRd); 

DWORD a, b, c; 
a = PIPE_READMODE_BYTE | PIPE_NOWAIT; 
b = 0; 
c = 0; 
SetNamedPipeHandleState(hChildStdoutRdDup, &a, &b, &c); 

err = CreatePipe(&hChildStdinRd, &hChildStdinWr, &sa, stdinhistory); 
if (err == 0) 
    return 1; 
err = DuplicateHandle(GetCurrentProcess(), hChildStdinWr, 
         GetCurrentProcess(), &hChildStdinWrDup , 0, 
         FALSE, 
         DUPLICATE_SAME_ACCESS); 
if (err == 0) 
    return 4; 
CloseHandle(hChildStdinWr); 

a = PIPE_READMODE_BYTE | PIPE_NOWAIT; 
b = 0; 
c = 0; 

ZeroMemory(&si,sizeof(STARTUPINFO)); 
si.cb = sizeof(STARTUPINFO); 
si.dwFlags = STARTF_USESTDHANDLES; 
si.wShowWindow = SW_SHOW; 

si.hStdOutput = hChildStdoutWr; 
si.hStdError = hChildStdoutWr; 
si.hStdInput = hChildStdinRd; 

ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); 

err = CreateProcess(0, this->cmdline, 0, 0, true, CREATE_NO_WINDOW, 0, 0, &si, &pi); 
if (err == 0) 
    return 4; 

tiêu thụ:

DWORD avail; 
unsigned int ofs = 0; 
if (PeekNamedPipe(hChildStdoutRdDup, NULL, 0, NULL, &avail, NULL)) 
{ 
    if (avail != 0) 
    { 
     int err = ReadFile(hChildStdoutRdDup, s + ofs, slen, &threadbuffern, 0); 
          // Consume ... 
    } 
} 

Edit: Tôi chỉ tìm thấy câu hỏi này: Continuously read from STDOUT of external process in Ruby. Đó là cùng một vấn đề, nhưng trong bối cảnh của Ruby. Đáng buồn là giải pháp là sử dụng một số thư viện Ruby mà chỉ làm cho nó hoạt động. Thư viện đó làm như thế nào? Tương đương trong Win32/C++ là gì?

+1

Chuỗi được liên kết là giải pháp * nix. Không có gì tương tự trong Win32. –

+0

Làm thế nào để bạn biết rằng nó chỉ liên quan đến unix? Cũng lưu ý rằng có tồn tại các chương trình trên các cửa sổ có thể thực hiện tốt các mã nguồn đóng:/ – marc40000

Trả lời

3

Bạn không thể làm điều đó. Nếu đầu ra không được xóa trong quá trình vi phạm, nó không thực sự được ghi vào stdout ngay từ đầu. Đó là, hệ điều hành đã không thực sự thậm chí nhận được dữ liệu từ quá trình mục tiêu được nêu ra.

Đây không phải là bất kỳ loại độ trễ cố hữu nào với đường ống, đó là các chương trình bạn đang theo dõi chưa thực sự viết nó vào đường ống.

Bạn sẽ nhận thấy hành vi tương tự chính xác cho lời nhắc lệnh khi thực thi các chương trình đã nói, vì dấu nhắc lệnh sử dụng cùng một giải pháp đường ống bạn đang sử dụng. Nếu bạn không làm như vậy bởi vì các chương trình được đề cập đang phát hiện rằng chúng đang ghi vào một tập tin xử lý, chứ không phải là một bàn điều khiển, và làm đệm bổ sung.

+0

Hmm, làm thế nào để chúng phát hiện ra? Tôi có thể làm việc đó không? Đó là thư viện ruby ​​trong liên kết đến câu hỏi khác tôi đăng dường như có thể làm điều đó. – marc40000

+0

@marc: 1. Thư viện ruby ​​không có trên Windows. 2. Thư viện ruby ​​có thể/có thể không kiểm soát được một chương trình khác. Sự cần thiết cho thư viện thực sự trong Ruby là do hạn chế của ruby, không phải là một hạn chế của ứng dụng được kiểm soát. Vì vậy, một thư viện đã có thể sửa chữa nó. –

Các vấn đề liên quan