在以下代码中,对SetupDiEnumDeviceInfo()
的调用会导致后续CreateFile
返回ERROR_SHARING_VIOLATION
,而不是打开文件。我能够通过注释掉其他代码来确定该行,直到我遇到一行会导致CreateFile
失败。
String SerialATDT::getComPortId()
{
#if 1
HDEVINFO hDevInfo;
SP_DEVINFO_DATA DeviceInfoData;
LPTSTR buffer = NULL;
DWORD buffersize = 0;
String comPort = "";
// Create a HDEVINFO with all present devices.
hDevInfo = SetupDiGetClassDevs(&GUID_DEVCLASS_MODEM,
0, // Enumerator
0,
DIGCF_PRESENT );
if (hDevInfo == INVALID_HANDLE_VALUE)
{
// Insert error handling here.
return "";
}
// Enumerate through all devices in Set.
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
int offset = 0;
while ( SetupDiEnumDeviceInfo(hDevInfo, offset++, &DeviceInfoData) )
{
DWORD DataT;
#if 1
//
// Call function with null to begin with,
// then use the returned buffer size (doubled)
// to Alloc the buffer. Keep calling until
// success or an unknown failure.
//
// Double the returned buffersize to correct
// for underlying legacy CM functions that
// return an incorrect buffersize value on
// DBCS/MBCS systems.
//
while (!SetupDiGetDeviceRegistryProperty(
hDevInfo,
&DeviceInfoData,
SPDRP_FRIENDLYNAME,
&DataT,
(PBYTE)buffer,
buffersize,
&buffersize))
{
if (GetLastError() ==
ERROR_INSUFFICIENT_BUFFER)
{
// Change the buffer size.
if (buffer) LocalFree(buffer);
// Double the size to avoid problems on
// W2k MBCS systems per KB 888609.
buffer = (LPTSTR)LocalAlloc(LPTR,buffersize * 2);
}
else
{
// Insert error handling here.
break;
}
}
// Look for identifying info in the name
if ( mComPortIdentifier.size() > 0 ) {
const char *temp = strstr(buffer, mComPortIdentifier.c_str());
if ( temp == 0 ) {
continue;
}
}
// Now find out the port number
DWORD nSize=0 ;
TCHAR buf[MAX_PATH];
if ( SetupDiGetDeviceInstanceId(hDevInfo, &DeviceInfoData, buf, MAX_PATH, &nSize) )
{
HKEY devKey = SetupDiOpenDevRegKey(hDevInfo, &DeviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ);
DWORD size = 0;
DWORD type;
RegQueryValueEx(devKey, TEXT("PortName"), NULL, NULL, NULL, & size);
BYTE* buff = new BYTE[size];
String result;
if( RegQueryValueEx(devKey, TEXT("PortName"), NULL, &type, buff, & size) == ERROR_SUCCESS ) {
comPort = (char*)buff;
if ( comPort.size() > 0 ) {
RegCloseKey(devKey);
break;
}
}
RegCloseKey(devKey);
delete [] buff;
}
#else
comPort = "COM44";
#endif
}
// Cleanup
SetupDiDestroyDeviceInfoList (hDevInfo);
if (buffer) {
LocalFree(buffer);
}
if ( GetLastError()!=NO_ERROR &&
GetLastError()!=ERROR_NO_MORE_ITEMS &&
GetLastError() != ERROR_INVALID_HANDLE )
{
TRACE_L("ATDT error after free %ld", GetLastError() );
// Insert error handling here.
return "";
}
return comPort;
#else
return "COM44";
#endif
}
bool SerialATDT::getComPort(HANDLE *hFile)
{
String comPort = getComPortId();
*hFile = INVALID_HANDLE_VALUE;
if ( comPort.size() > 0 ) {
String comPortStr;
comPortStr.Format("\\\\.\\%s", comPort.c_str());
*hFile = ::CreateFile( comPortStr.c_str(),
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
0,
NULL );
if ( *hFile == INVALID_HANDLE_VALUE ) {
TRACE_L("AT file open error %ld", GetLastError());
}
}
return *hFile != INVALID_HANDLE_VALUE;
}
我一直在寻找但是没有找到为什么DeviceInfoData
需要被清除的原因(我也找不到一种方法)。有没有人遇到过这个?