2
我正在使用虛擬串行端口設備驅動程序與USB設備進行通信的應用程序。我們遇到了這樣的情況:如果在串行端口句柄打開的情況下拔掉設備(或崩潰),則在串行端口句柄關閉後重新連接的唯一方法是拔下設備然後重新插入。使用Windows USB虛擬COM端口識別斷開事件
如果我能夠快速檢測到故障,則可能會有解決方法。問題在於,在這些條件下,以下函數調用不報告錯誤:ClearCommError(),GetCommModemStatus()和ReadFile()。根據我的經驗,當設備被拔出時唯一返回錯誤的函數是WriteFile()。可以理解的是,我並不想寫無意義的數據來測試端口連接是否仍然有效。
我的問題是,是否有一些方法可以用來確定端口連接是否仍然有效。
如果有關於我在做什麼任何問題,下面的代碼片段顯示了我的口輪詢線程是這樣做的:
// set up the communications timeouts
COMMTIMEOUTS timeouts;
if(!GetCommTimeouts(port_handle, &timeouts))
throw OsException(my_strings[strid_get_comm_timeouts_failed].c_str());
timeouts.ReadIntervalTimeout = MAXDWORD;
timeouts.ReadTotalTimeoutMultiplier = MAXDWORD;
timeouts.ReadTotalTimeoutConstant = 10;
timeouts.WriteTotalTimeoutMultiplier = 0;
timeouts.WriteTotalTimeoutConstant = 10000;
if(!SetCommTimeouts(port_handle, &timeouts))
throw OsException(my_strings[strid_set_comm_timeouts_failed].c_str());
on_open();
// we need to set a base for the carrier detect signal. This will be used to determine
// when the signal "changes" while the loop executes
bool carrier_detect_set = false;
uint4 modem_status = 0;
if(!GetCommModemStatus(port_handle, &modem_status))
throw OsException(my_strings[strid_get_modem_status_failed].c_str());
if(modem_status & MS_RLSD_ON)
carrier_detect_set = true;
// we are now ready to enter the main service loop for this thread.
OVERLAPPED io_control;
memset(&io_control, 0, sizeof(io_control));
while(!should_close)
{
// we need to check to see if any comm errors have occurred
uint4 comm_errors = 0;
if(!ClearCommError(port_handle, &comm_errors, 0))
throw OsException(my_strings[strid_clear_comm_errors_failed].c_str());
if(comm_errors != 0)
on_comm_errors(comm_errors);
// we also need to determine if the carrier detect line has changed
modem_status = 0;
if(!GetCommModemStatus(port_handle, &modem_status))
throw OsException(my_strings[strid_get_modem_status_failed].c_str());
if(carrier_detect_set && (modem_status & MS_RLSD_ON) == 0)
on_carrier_detect_change(false);
else if(!carrier_detect_set && (modem_status & MS_RLSD_ON) != 0)
on_carrier_detect_change(true);
// we will now execute any command that might be waiting
command_handle command;
commands_protector.lock();
while(!commands.empty())
{
command = commands.front();
commands.pop_front();
commands_protector.unlock();
command->execute(this, port_handle, false);
commands_protector.lock();
}
commands_protector.unlock();
// now we will try to write anything that is pending in the write queue
fill_write_buffer(tx_queue);
while(!tx_queue.empty() && !should_close)
{
uint4 bytes_avail = tx_queue.copy(tx_buff, sizeof(tx_buff));
uint4 bytes_written = 0;
rcd = WriteFile(
port_handle, tx_buff, bytes_avail, &bytes_written, &io_control);
if(!rcd || bytes_written == 0)
throw Csi::OsException(my_strings[strid_write_failed].c_str());
if(rcd)
{
SetLastError(0);
if(bytes_written)
{
tx_queue.pop(bytes_written);
on_low_level_write(tx_buff, bytes_written);
}
if(bytes_written < bytes_avail)
throw OsException(my_strings[strid_write_timed_out].c_str());
}
}
// we will now poll to see if there is any data available to be written
uint4 bytes_read = 0;
rcd = ReadFile(
port_handle, rx_buff, sizeof(rx_buff), &bytes_read, &io_control);
if(rcd && bytes_read)
on_low_level_read(rx_buff, bytes_read);
else if(!rcd)
throw OsException(my_strings[strid_read_failed].c_str());
}
我也遇到同樣的問題,當使用重疊I/O,以及。
我可能會設置一個不可見的窗口並尋找[WM_DEVICECHANGE](http://msdn.microsoft.com/en-us/library/windows/desktop/aa363480(v = vs.85).aspx)消息,然後從那裏處理句柄的有效性。我很確定這涉及任何類型的端口,包括USB。 – NmdMystery
同意,另見'RegisterDeviceNotification'。尋找'DEV_BROADCAST_DEVICEINTERFACE'事件。 – MSalters
BTW,顯然是微軟[在Windows 8中破壞了這一點](http://social.msdn.microsoft.com/Forums/windowshardware/en-US/9bf1c183-5d6e-4d43-8252-056a0d3ef958/win8-i-cant-receive -dbtdeviceremovecomplete事件換dbtdevtypport型?論壇= WDK) – MSalters