调用SetupDiEnumDeviceInfo会导致后续CreateFile返回ERROR_SHARING_VIOLATION

时间:2012-10-26 15:58:42

标签: c++ windows createfile

在以下代码中,对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需要被清除的原因(我也找不到一种方法)。有没有人遇到过这个?

0 个答案:

没有答案