C++ 带有虚拟COM端口的USB串行设备-如果将CreateFile()与USB路径一起使用,则ReadFile()读取零字节
我有一个销售点应用程序,它使用串行通信端口(RS-232)与称重产品的秤进行通信。我现在正致力于能够直接支持USB设备,而不是使用虚拟串行通信端口,因为它们有移动的恼人倾向 我们发现,虽然Windows 7似乎可以自动创建虚拟串行通信端口,但其他版本的Windows(如POS Ready 7)可能不会。我们怀疑这是由于POS Ready 7中缺少Windows 7的特定.inf文件造成的。有人能证实吗 我有一个间歇工作的USB示例应用程序。我与C++ 带有虚拟COM端口的USB串行设备-如果将CreateFile()与USB路径一起使用,则ReadFile()读取零字节,c++,winapi,usb,C++,Winapi,Usb,我有一个销售点应用程序,它使用串行通信端口(RS-232)与称重产品的秤进行通信。我现在正致力于能够直接支持USB设备,而不是使用虚拟串行通信端口,因为它们有移动的恼人倾向 我们发现,虽然Windows 7似乎可以自动创建虚拟串行通信端口,但其他版本的Windows(如POS Ready 7)可能不会。我们怀疑这是由于POS Ready 7中缺少Windows 7的特定.inf文件造成的。有人能证实吗 我有一个间歇工作的USB示例应用程序。我与ReadFile()Windows API函数的US
ReadFile()
Windows API函数的USB级通信有问题。我正在使用CreateFile()
指定USB设备路径以获取I/O句柄,然后使用WriteFile()
和ReadFile()
与电子秤通信。在某些情况下,ReadFile()
不提供数据
背景信息
我使用的是Brecknell 67xx台秤,它使用虚拟串行通信端口,直接与销售点应用程序一起开箱即用。我用USB电缆将电子秤连接到我的Windows 7电脑,Windows自动安装了驱动程序,创建了一个虚拟串行端口,在我的例子中是COM4。然后,我将应用程序配置为通过COM4与秤对话,一切正常
使用电子秤的协议是向电子秤发送一个两字节的命令“W\r”(大写字母W后跟回车字符),然后读取一个16字节的响应,该响应包含当前重量以及有关电子秤机械装置(如运动中)的状态信息
我正在学习的示例USB应用程序将成功地提供一个权重。然后,它将停止正常工作,其行为为ReadFile()
返回零字节读取。一旦停止工作,它将继续无法从ReadFile()
提供数据,即使我拔下并重新插入USB电缆或重新启动电脑
先前版本的学习应用程序挂起在ReadFile()
上,当Visual Studio完成全部中断时,将显示一个暂停,然后显示一条指示死锁的消息。但是,自从我开始在ReadTotalTimeoutConstant
中使用带有5000毫秒超时值的SetCommTimeouts()
以来,我看到在ReadFile()返回读取零字节之前有一个持续5秒的暂停
奇怪的是,如果我使用打开虚拟串行通信端口COM4的应用程序,该应用程序工作正常,秤会报告物品的重量
然后,我可以返回到使用直接USB而不是虚拟串行通信端口的示例应用程序,它可以很好地工作
但是,如果我随后拔下连接电子秤和PC的USB电缆(该电缆也关闭了电子秤的电源),然后重新插入USB电缆,示例应用程序将不再正常工作,我再次看到暂停超时
然后我尝试使用原始的销售点应用程序,该应用程序依赖于使用虚拟串行端口COM4的串行通信端口,并且该应用程序可以很好地称量物品
然后,当我重试我的示例应用程序时,它还将报告项目权重
我的问题。
如果USB设备在插入时创建了虚拟串行通信端口,那么是否只需要通过在CreateFile()
调用中指定通信端口COM4来使用虚拟串行端口
如果设备导致Windows生成虚拟通信端口,如何通过使用USB设备路径进行直接USB串行通信
是否有某种方法可以指定任何版本的Windows在插入设备时自动为其创建虚拟串行通信端口
示例USB应用程序的源代码
使用Visual Studio 2005的示例USB Windows控制台应用程序的源代码如下所示,main位于底部,其中大部分是用于查找特定USB设备的类,然后允许ReadFile()
和WriteFile()
:
//usb\u test\u cons.cpp:定义控制台应用程序的入口点。
//
#包括“stdafx.h”
#包括
#包括
#包括
#包括
//这是USB设备类的GUID。
//它在Microsoft Windows驱动程序工具包的include文件Usbiodef.h中定义。
//另见https://msdn.microsoft.com/en-us/library/windows/hardware/ff545972(v=vs.85)。aspx哪个
//提供有关此GUID的基本文档。
定义GUID(GUID设备接口USB设备,0xA5DCBF10L、0x6530、0x11D2、0x90、0x1F、0x00、0xC0、0x4F、0xB9、0x51、0xED);
//(A5DCBF10-6530-11D2-901F-00C04FB951ED)
//以下是将与所有应用程序一起使用的标准定义
//通过UIE接口使用的设备。
#访问设备时定义UIE_设备错误(-11)/*错误*/
#定义UIE_设备\u未提供(-12)/*未提供设备*/
#定义UIE_设备_错误_范围(-13)/*范围错误*/
#定义UIE\U设备错误\U COM(-14)/*通信错误*/
#定义UIE_设备_超时(-15)/*通信错误*/
#定义特定于UIE_设备的(-20)/*特定于设备的错误从这里开始*/
#定义UIE_比例_ETX 0x03/*ETX字符*/
#定义运动中的UIE\U比例0x01/*运动中的比例*/
#定义UIE_标尺_零0x02/*零重量*/
#定义
// usb_test_cons.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <windows.h>
#include <setupapi.h>
#include <initguid.h>
#include <stdio.h>
// This is the GUID for the USB device class.
// It is defined in the include file Usbiodef.h of the Microsoft Windows Driver Kit.
// See also https://msdn.microsoft.com/en-us/library/windows/hardware/ff545972(v=vs.85).aspx which
// provides basic documentation on this GUID.
DEFINE_GUID(GUID_DEVINTERFACE_USB_DEVICE, 0xA5DCBF10L, 0x6530, 0x11D2, 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED);
// (A5DCBF10-6530-11D2-901F-00C04FB951ED)
// Following are standard defines to be used with all of the
// devices that are use through the UIE interface.
#define UIE_DEVICE_ERROR (-11) /* error when accessing the device */
#define UIE_DEVICE_NOT_PROVIDE (-12) /* device is not provided */
#define UIE_DEVICE_ERROR_RANGE (-13) /* range error */
#define UIE_DEVICE_ERROR_COM (-14) /* communication error */
#define UIE_DEVICE_TIMEOUT (-15) /* communication error */
#define UIE_DEVICE_SPECIFIC (-20) /* device specific errors start here */
#define UIE_SCALE_ETX 0x03 /* ETX character */
#define UIE_SCALE_IN_MOTION 0x01 /* scale in motion */
#define UIE_SCALE_ZERO 0x02 /* zero weight */
#define UIE_SCALE_UNDER 0x01 /* under capacity */
#define UIE_SCALE_OVER 0x02 /* over capacity */
#define UIE_SCALE_ERROR UIE_DEVICE_ERROR /* error */
#define UIE_SCALE_NOT_PROVIDE UIE_DEVICE_NOT_PROVIDE /* not provide */
#define UIE_SCALE_TIMEOUT UIE_DEVICE_TIMEOUT /* time out when reading from scale */
#define UIE_SCALE_MOTION (UIE_DEVICE_SPECIFIC-1) /* motion */
#define UIE_SCALE_UNDER_CAPACITY (UIE_DEVICE_SPECIFIC-2) /* under capacity */
#define UIE_SCALE_OVER_CAPACITY (UIE_DEVICE_SPECIFIC-3) /* over capacity */
#define UIE_SCALE_DATAFORMAT (UIE_DEVICE_SPECIFIC-4) /* Data read from scale incorrect format in UieScaleAnalysis() */
#define UIE_SCALE_DATAUNITS (UIE_DEVICE_SPECIFIC-5) /* Units read from scale incorrect in UieScaleAnalysis() */
static SHORT UieScaleStatus(char *puchBuffer, DWORD sLength)
{
UCHAR uchByte;
switch (sLength) {
case 16:
// The scale message is a weight message with a status section.
// Move the buffer pointer to where the status section should begin.
// A status only message has the same format as the status section of a weight message.
puchBuffer += 10;
case 6:
// The scale message may be a status only message if there is a problem with the scale.
// A status only message is 6 characters with the letter S as the second character.
if (*(puchBuffer + 0) != '\n' ||
*(puchBuffer + 1) != 'S' ||
*(puchBuffer + 4) != '\r' ||
*(puchBuffer + 5) != UIE_SCALE_ETX) {
return (UIE_SCALE_DATAFORMAT); /* exit ... */
}
break;
default:
return (UIE_SCALE_DATAFORMAT); /* exit ... */
break;
}
/* --- check status of low byte --- */
uchByte = *(puchBuffer + 3) - (UCHAR)0x30;
if (uchByte & UIE_SCALE_UNDER) {
return (UIE_SCALE_UNDER_CAPACITY);
} else if (uchByte & UIE_SCALE_OVER) {
return (UIE_SCALE_OVER_CAPACITY);
}
/* --- check status of high byte --- */
uchByte = *(puchBuffer + 2) - (UCHAR)0x30;
if (uchByte & UIE_SCALE_IN_MOTION) {
return (UIE_SCALE_MOTION);
} else if (uchByte & UIE_SCALE_ZERO) {
return (0);
} else {
return (TRUE);
}
}
class UsbSerialDevice
{
public:
UsbSerialDevice();
~UsbSerialDevice();
int CreateEndPoint (wchar_t *wszVendorId);
int CloseEndPoint ();
int ReadStream (void *bString, size_t nBytes);
int WriteStream (void *bString, size_t nBytes);
DWORD m_dwError; // GetLastError() for last action
DWORD m_dwErrorWrite; // GetLastError() for last write
DWORD m_dwErrorRead; // GetLastError() for last read
DWORD m_dwBytesWritten;
DWORD m_dwBytesRead;
private:
HANDLE m_hFile;
DWORD m_dwStatError;
COMMTIMEOUTS m_timeOut;
COMSTAT m_statOut;
};
UsbSerialDevice::UsbSerialDevice() :
m_dwError(0),
m_dwErrorWrite(0),
m_dwErrorRead(0),
m_dwBytesWritten(0),
m_dwBytesRead(0),
m_hFile(NULL)
{
}
UsbSerialDevice::~UsbSerialDevice()
{
CloseHandle (m_hFile);
}
int UsbSerialDevice::WriteStream(void *bString, size_t nBytes)
{
BOOL bWrite = FALSE;
if (m_hFile) {
m_dwError = m_dwErrorWrite = 0;
m_dwBytesWritten = 0;
ClearCommError (m_hFile, &m_dwStatError, &m_statOut);
bWrite = WriteFile (m_hFile, bString, nBytes, &m_dwBytesWritten, NULL);
m_dwError = m_dwErrorWrite = GetLastError();
return 0;
}
return -1;
}
int UsbSerialDevice::ReadStream(void *bString, size_t nBytes)
{
BOOL bRead = FALSE;
if (m_hFile) {
m_dwError = m_dwErrorRead = 0;
m_dwBytesRead = 0;
ClearCommError (m_hFile, &m_dwStatError, &m_statOut);
bRead = ReadFile (m_hFile, bString, nBytes, &m_dwBytesRead, NULL);
m_dwError = m_dwErrorRead = GetLastError();
return 0;
}
return -1;
}
int UsbSerialDevice::CreateEndPoint (wchar_t *wszVendorId)
{
HDEVINFO hDevInfo;
m_dwError = ERROR_INVALID_HANDLE;
// We will try to get device information set for all USB devices that have a
// device interface and are currently present on the system (plugged in).
hDevInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_USB_DEVICE, NULL, 0, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
if (hDevInfo != INVALID_HANDLE_VALUE)
{
DWORD dwMemberIdx;
BOOL bContinue = TRUE;
SP_DEVICE_INTERFACE_DATA DevIntfData;
// Prepare to enumerate all device interfaces for the device information
// set that we retrieved with SetupDiGetClassDevs(..)
DevIntfData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
dwMemberIdx = 0;
// Next, we will keep calling this SetupDiEnumDeviceInterfaces(..) until this
// function causes GetLastError() to return ERROR_NO_MORE_ITEMS. With each
// call the dwMemberIdx value needs to be incremented to retrieve the next
// device interface information.
for (BOOL bContinue = TRUE; bContinue; ) {
PSP_DEVICE_INTERFACE_DETAIL_DATA DevIntfDetailData;
SP_DEVINFO_DATA DevData;
DWORD dwSize;
dwMemberIdx++;
SetupDiEnumDeviceInterfaces(hDevInfo, NULL, &GUID_DEVINTERFACE_USB_DEVICE, dwMemberIdx, &DevIntfData);
if (GetLastError() == ERROR_NO_MORE_ITEMS) break;
// As a last step we will need to get some more details for each
// of device interface information we are able to retrieve. This
// device interface detail gives us the information we need to identify
// the device (VID/PID), and decide if it's useful to us. It will also
// provide a DEVINFO_DATA structure which we can use to know the serial
// port name for a virtual com port.
DevData.cbSize = sizeof(DevData);
// Get the required buffer size. Call SetupDiGetDeviceInterfaceDetail with
// a NULL DevIntfDetailData pointer, a DevIntfDetailDataSize
// of zero, and a valid RequiredSize variable. In response to such a call,
// this function returns the required buffer size at dwSize.
SetupDiGetDeviceInterfaceDetail(hDevInfo, &DevIntfData, NULL, 0, &dwSize, NULL);
// Allocate memory for the DeviceInterfaceDetail struct. Don't forget to
// deallocate it later!
DevIntfDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize);
DevIntfDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
if (SetupDiGetDeviceInterfaceDetail(hDevInfo, &DevIntfData, DevIntfDetailData, dwSize, &dwSize, &DevData))
{
// Finally we can start checking if we've found a useable device,
// by inspecting the DevIntfDetailData->DevicePath variable.
//
// The DevicePath looks something like this for a Brecknell 67xx Series Serial Scale
// \\?\usb#vid_1a86&pid_7523#6&28eaabda&0&2#{a5dcbf10-6530-11d2-901f-00c04fb951ed}
//
// The VID for a particular vendor will be the same for a particular vendor's equipment.
// The PID is variable for each device of the vendor.
//
// As you can see it contains the VID/PID for the device, so we can check
// for the right VID/PID with string handling routines.
// See https://github.com/Microsoft/Windows-driver-samples/blob/master/usb/usbview/vndrlist.h
if (wcsstr (DevIntfDetailData->DevicePath, wszVendorId)) {
m_dwError = 0;
m_hFile = CreateFile (DevIntfDetailData->DevicePath, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
if (m_hFile == INVALID_HANDLE_VALUE) {
m_dwError = GetLastError();
} else {
GetCommTimeouts (m_hFile, &m_timeOut);
m_timeOut.ReadIntervalTimeout = 0;
m_timeOut.ReadTotalTimeoutMultiplier = 0;
m_timeOut.ReadTotalTimeoutConstant = 5000;
SetCommTimeouts (m_hFile, &m_timeOut);
m_dwError = GetLastError();
}
bContinue = FALSE; // found the vendor so stop processing after freeing the heap.
}
}
HeapFree(GetProcessHeap(), 0, DevIntfDetailData);
}
SetupDiDestroyDeviceInfoList(hDevInfo);
}
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
UsbSerialDevice myDev;
myDev.CreateEndPoint (L"vid_1a86&pid_7523");
switch (myDev.m_dwError) {
case 0:
// no error so just ignore.
break;
case ERROR_ACCESS_DENIED:
wprintf (_T(" CreateFile() failed. GetLastError() = %d\n ERROR_ACCESS_DENIED: Access is denied.\n Is it already in use?\n"), myDev.m_dwError);
break;
case ERROR_GEN_FAILURE:
wprintf (_T(" CreateFile() failed. GetLastError() = %d\n ERROR_GEN_FAILURE: A device attached to the system is not functioning.\n Is it an HID?\n"), myDev.m_dwError);
break;
case ERROR_INVALID_HANDLE:
wprintf (_T(" CreateFile() failed. GetLastError() = %d\n ERROR_INVALID_HANDLE: The handle is invalid.\n CreateFile() failed?\n"), myDev.m_dwError);
break;
default:
wprintf (_T(" CreateFile() failed. GetLastError() = %d\n"), myDev.m_dwError);
break;
}
if (myDev.m_dwError == 0) {
char reqWeight[] = "W\r";
char resWeight[256] = {0};
myDev.WriteStream (reqWeight, strlen (reqWeight));
wprintf (_T(" Sent request now get response.\n"));
Sleep (50);
myDev.ReadStream (resWeight, 16);
wprintf (_T(" Got response.\n"));
if (resWeight[0] != '\n' || resWeight[9] != '\r') {
wprintf (_T(" Unexpected format of response.\n"));
}
short sRet = UieScaleStatus (resWeight, myDev.m_dwBytesRead);
resWeight[9] = 0; // terminate the weight string so that we can write it out.
wprintf (_T(" ScaleStatus = %d, Response from device - \"%S\"\n"), sRet, resWeight + 1);
}
return 0;
}
class UsbSerialDevice
{
public:
UsbSerialDevice();
UsbSerialDevice(DWORD BaudRate, BYTE ByteSize = 8, BYTE Parity = NOPARITY, BYTE StopBits = ONESTOPBIT);
~UsbSerialDevice();
int CreateEndPoint (wchar_t *wszVendorId);
int SetCommPortSettings (DWORD BaudRate, BYTE ByteSize = 8, BYTE Parity = NOPARITY, BYTE StopBits = ONESTOPBIT);
int CloseEndPoint ();
int ReadStream (void *bString, size_t nBytes);
int WriteStream (void *bString, size_t nBytes);
int UpdateSettingsProxy (void);
DWORD m_dwError; // GetLastError() for last action
DWORD m_dwErrorWrite; // GetLastError() for last write
DWORD m_dwErrorRead; // GetLastError() for last read
DWORD m_dwErrorCommState;
DWORD m_dwErrorCommTimeouts;
DWORD m_dwBytesWritten;
DWORD m_dwBytesRead;
COMMTIMEOUTS m_timeOut; // last result from GetCommTimeouts(), updated by UpdateSettingsProxy()
COMSTAT m_statOut; // last result from ClearCommError()
DCB m_commSet; // last result from GetCommState(), updated by UpdateSettingsProxy()
private:
HANDLE m_hFile;
DWORD m_dwStatError;
DCB m_commSetDefault; // the defaults used as standard
wchar_t m_portName[24]; // contains portname if defined for device in form \\.\\COMnn
};
UsbSerialDevice::UsbSerialDevice() :
m_dwError(0),
m_dwErrorWrite(0),
m_dwErrorRead(0),
m_dwBytesWritten(0),
m_dwBytesRead(0),
m_hFile(NULL)
{
// initialize our COM port settings and allow people to change with
memset (&m_commSetDefault, 0, sizeof(m_commSetDefault));
m_commSetDefault.DCBlength = sizeof(m_commSetDefault);
m_commSetDefault.BaudRate = CBR_9600;
m_commSetDefault.ByteSize = 7;
m_commSetDefault.Parity = EVENPARITY;
m_commSetDefault.StopBits = ONESTOPBIT;
m_commSet.fDtrControl = DTR_CONTROL_DISABLE;
m_portName[0] = 0;
}
int UsbSerialDevice::CreateEndPoint (wchar_t *wszVendorId)
{
HDEVINFO hDevInfo;
m_dwError = ERROR_INVALID_HANDLE;
// We will try to get device information set for all USB devices that have a
// device interface and are currently present on the system (plugged in).
hDevInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_USB_DEVICE, NULL, 0, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
if (hDevInfo != INVALID_HANDLE_VALUE)
{
DWORD dwMemberIdx;
BOOL bContinue = TRUE;
SP_DEVICE_INTERFACE_DATA DevIntfData;
// Prepare to enumerate all device interfaces for the device information
// set that we retrieved with SetupDiGetClassDevs(..)
DevIntfData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
dwMemberIdx = 0;
// Next, we will keep calling this SetupDiEnumDeviceInterfaces(..) until this
// function causes GetLastError() to return ERROR_NO_MORE_ITEMS. With each
// call the dwMemberIdx value needs to be incremented to retrieve the next
// device interface information.
for (BOOL bContinue = TRUE; bContinue; ) {
PSP_DEVICE_INTERFACE_DETAIL_DATA DevIntfDetailData;
SP_DEVINFO_DATA DevData;
DWORD dwSize;
dwMemberIdx++;
SetupDiEnumDeviceInterfaces(hDevInfo, NULL, &GUID_DEVINTERFACE_USB_DEVICE, dwMemberIdx, &DevIntfData);
if (GetLastError() == ERROR_NO_MORE_ITEMS) break;
// As a last step we will need to get some more details for each
// of device interface information we are able to retrieve. This
// device interface detail gives us the information we need to identify
// the device (VID/PID), and decide if it's useful to us. It will also
// provide a DEVINFO_DATA structure which we can use to know the serial
// port name for a virtual com port.
DevData.cbSize = sizeof(DevData);
// Get the required buffer size. Call SetupDiGetDeviceInterfaceDetail with
// a NULL DevIntfDetailData pointer, a DevIntfDetailDataSize
// of zero, and a valid RequiredSize variable. In response to such a call,
// this function returns the required buffer size at dwSize.
SetupDiGetDeviceInterfaceDetail(hDevInfo, &DevIntfData, NULL, 0, &dwSize, NULL);
// Allocate memory for the DeviceInterfaceDetail struct. Don't forget to
// deallocate it later!
DevIntfDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize);
DevIntfDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
if (SetupDiGetDeviceInterfaceDetail(hDevInfo, &DevIntfData, DevIntfDetailData, dwSize, &dwSize, &DevData))
{
// Finally we can start checking if we've found a useable device,
// by inspecting the DevIntfDetailData->DevicePath variable.
//
// The DevicePath looks something like this for a Brecknell 67xx Series Serial Scale
// \\?\usb#vid_1a86&pid_7523#6&28eaabda&0&2#{a5dcbf10-6530-11d2-901f-00c04fb951ed}
//
// The VID for a particular vendor will be the same for a particular vendor's equipment.
// The PID is variable for each device of the vendor.
//
// As you can see it contains the VID/PID for the device, so we can check
// for the right VID/PID with string handling routines.
// See https://github.com/Microsoft/Windows-driver-samples/blob/master/usb/usbview/vndrlist.h
if (wcsstr (DevIntfDetailData->DevicePath, wszVendorId)) {
HKEY hKey;
m_dwError = 0;
// To find out the serial port for our scale device,
// we'll need to check the registry:
hKey = SetupDiOpenDevRegKey(hDevInfo, &DevData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ);
if (hKey != INVALID_HANDLE_VALUE) {
DWORD dwSize = 0, dwType = 0;
wchar_t lpData[16] = {0};
dwType = REG_SZ;
dwSize = sizeof(lpData);
LONG queryStat = RegQueryValueEx(hKey, _T("PortName"), NULL, &dwType, (LPBYTE)&lpData[0], &dwSize);
RegCloseKey(hKey);
if (queryStat == ERROR_SUCCESS) {
wcscpy (m_portName, L"\\\\.\\");
wcsncat (m_portName, lpData, dwSize / sizeof(wchar_t));
}
} else {
m_dwError = GetLastError();
}
m_hFile = CreateFile (DevIntfDetailData->DevicePath, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
if (m_hFile == INVALID_HANDLE_VALUE) {
m_dwError = GetLastError();
} else {
m_dwError = 0;
GetCommState (m_hFile, &m_commSet);
m_commSet = m_commSetDefault;
SetCommState (m_hFile, &m_commSet);
m_dwErrorCommState = GetLastError();
GetCommState (m_hFile, &m_commSet);
GetCommTimeouts (m_hFile, &m_timeOut);
m_timeOut.ReadIntervalTimeout = 0;
m_timeOut.ReadTotalTimeoutMultiplier = 0;
m_timeOut.ReadTotalTimeoutConstant = 5000;
SetCommTimeouts (m_hFile, &m_timeOut);
GetCommTimeouts (m_hFile, &m_timeOut);
m_dwErrorCommTimeouts = GetLastError();
}
bContinue = FALSE; // found the vendor so stop processing after freeing the heap.
}
}
HeapFree(GetProcessHeap(), 0, DevIntfDetailData);
}
SetupDiDestroyDeviceInfoList(hDevInfo);
}
return 0;
}