2014-11-23 74 views
0

我正在使用CreatePipe將stdin/out從進程重定向到我的進程。取消IO管道

http://msdn.microsoft.com/en-us/library/windows/desktop/aa365152(v=vs.85).aspx

這工作正常爲止。問題是當我想終止等待客戶端進程寫入內容的線程時。

我可以使用CancelIoEx(),但這隻適用於Vista +,我也想要一個XP解決方案。如果沒有CancelIoEx(),另一個線程中的ReadFile()將不會返回。

我不能使用OVERLAPPED ReadFile,因爲用CreatePipe創建的管道不支持它。

任何選項?

+0

只需關閉管道,ReadFile()就會失敗。 – 2014-11-23 14:14:38

+0

@HansPassant它不,CloseHandle()塊。 – Michael 2014-11-23 14:16:20

+0

改爲使用CreateNamedPipe,然後您可以使用重疊的I/O。 – 2014-11-23 23:23:03

回答

0

創建子進程時,保存標準輸出管道的寫入結束句柄。然後你可以寫一個字符來解鎖已經調用ReadFile的線程(即從標準輸出管道的讀取端讀取)。爲了不將其解釋爲數據,請在寫入虛擬字符的線程中創建一個設置爲(SetEvent)的Event(CreateEvent),並在ReadFile返回後進行檢查。有點混亂,但似乎工作。

/* Init */ 

stdout_closed_event = CreateEvent(NULL, TRUE, FALSE, NULL); 

/* Read thread */ 

read_result = ReadFile(stdout_read, data, buf_len, &bytes_read, NULL);    
if (!read_result) 
    ret = -1; 
else 
    ret = bytes_read;  
if ((bytes_read > 0) && (WAIT_OBJECT_0 == WaitForSingleObject(stdout_closed_event, 0))) { 
    if (data[bytes_read-1] == eot) { 
     if (bytes_read > 1) {      
      /* Discard eot character, but return the rest of the read data that should be valid. */  
      ret--; 
     } else { 
      /* No data. */ 
      ret = -1; 
     } 
    } 
} 

/* Cancel thread */ 

HMODULE mod = LoadLibrary (L"Kernel32.dll"); 
BOOL WINAPI (*cancel_io_ex) (HANDLE, LPOVERLAPPED) = NULL; 
if (mod != NULL) { 
    cancel_io_ex = (BOOL WINAPI (*) (HANDLE, LPOVERLAPPED)) GetProcAddress (mod, "CancelIoEx");   
} 
if (cancel_io_ex != NULL) { 
    cancel_io_ex(stdout_write_pipe, NULL); 
} else { 
    SetEvent(stdout_closed_event);    
    WriteFile(stdout_write_pipe, &eot, 1, &written, NULL); 
}