2014-11-23 75 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); 
}