You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

enum_serial_port.cpp 4.2 kB

2 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. #if defined(OS_WINDOWS)
  2. struct SSerInfo {
  3. CString strDevPath; // Device path for use with CreateFile()
  4. CString strPortName; // Simple name (i.e. COM1)
  5. CString strFriendlyName; // Full name to be displayed to a user
  6. CString strPortDesc; // friendly name without the COMx
  7. };
  8. void EnumSerialPorts(CArray<SSerInfo,SSerInfo&> &asi, BOOL bIgnoreBusyPorts)
  9. {
  10. // Clear the output array
  11. asi.RemoveAll();
  12. EnumPortsWdm(asi);
  13. for (int ii=0; ii<asi.GetSize(); ii++)
  14. {
  15. SSerInfo& rsi = asi[ii];
  16. if (bIgnoreBusyPorts) {
  17. // Only display ports that can be opened for read/write
  18. HANDLE hCom = CreateFile(rsi.strDevPath,
  19. GENERIC_READ | GENERIC_WRITE,
  20. 0, /* comm devices must be opened w/exclusive-access */
  21. NULL, /* no security attrs */
  22. OPEN_EXISTING, /* comm devices must use OPEN_EXISTING */
  23. 0, /* not overlapped I/O */
  24. NULL /* hTemplate must be NULL for comm devices */
  25. );
  26. if (hCom == INVALID_HANDLE_VALUE) {
  27. // It can't be opened; remove it.
  28. asi.RemoveAt(ii);
  29. ii--;
  30. continue;
  31. }
  32. else {
  33. // It can be opened! Close it and add it to the list
  34. ::CloseHandle(hCom);
  35. }
  36. }
  37. if (rsi.strFriendlyName.IsEmpty())
  38. {
  39. asi.RemoveAt(ii);
  40. ii--;
  41. continue;
  42. }
  43. CString fName = rsi.strFriendlyName;
  44. TCHAR *pt, *pt1;
  45. pt = fName.GetBuffer() + fName.GetLength() - 1;
  46. while (*pt != _T('('))
  47. {
  48. pt --;
  49. }
  50. if (_tcsncmp(pt, _T("(COM"), 4))
  51. {
  52. asi.RemoveAt(ii);
  53. ii--;
  54. continue;
  55. }
  56. rsi.strPortName.Empty();
  57. rsi.strPortName = _T("COM");
  58. pt1 = pt + 4;
  59. while ((*pt1>=_T('0')) && (*pt1<=_T('9')))
  60. {
  61. rsi.strPortName += *pt1++;
  62. }
  63. pt -= 2;
  64. pt1 = fName.GetBuffer();
  65. rsi.strPortDesc.Empty();
  66. while (pt1 <= pt)
  67. {
  68. rsi.strPortDesc += *pt1++;
  69. }
  70. }
  71. }
  72. void EnumPortsWdm(CArray<SSerInfo,SSerInfo&> &asi)
  73. {
  74. CString strErr;
  75. // Create a device information set that will be the container for
  76. // the device interfaces.
  77. GUID *guidDev = (GUID*) &GUID_CLASS_COMPORT;
  78. HDEVINFO hDevInfo = INVALID_HANDLE_VALUE;
  79. SP_DEVICE_INTERFACE_DETAIL_DATA *pDetData = NULL;
  80. try {
  81. hDevInfo = SetupDiGetClassDevs( guidDev,
  82. NULL,
  83. NULL,
  84. DIGCF_PRESENT | DIGCF_DEVICEINTERFACE
  85. );
  86. if(hDevInfo == INVALID_HANDLE_VALUE)
  87. {
  88. strErr.Format(_T("SetupDiGetClassDevs failed. (err=%lx)"),
  89. GetLastError());
  90. throw strErr;
  91. }
  92. // Enumerate the serial ports
  93. BOOL bOk = TRUE;
  94. SP_DEVICE_INTERFACE_DATA ifcData;
  95. DWORD dwDetDataSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) + 256;
  96. pDetData = (SP_DEVICE_INTERFACE_DETAIL_DATA*) new char[dwDetDataSize];
  97. // This is required, according to the documentation. Yes,
  98. // it's weird.
  99. ifcData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
  100. pDetData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
  101. for (DWORD ii=0; bOk; ii++) {
  102. bOk = SetupDiEnumDeviceInterfaces(hDevInfo,
  103. NULL, guidDev, ii, &ifcData);
  104. if (bOk) {
  105. // Got a device. Get the details.
  106. SP_DEVINFO_DATA devdata = {sizeof(SP_DEVINFO_DATA)};
  107. bOk = SetupDiGetDeviceInterfaceDetail(hDevInfo,
  108. &ifcData, pDetData, dwDetDataSize, NULL, &devdata);
  109. if (bOk) {
  110. CString strDevPath(pDetData->DevicePath);
  111. // Got a path to the device. Try to get some more info.
  112. TCHAR fname[256];
  113. BOOL bSuccess = SetupDiGetDeviceRegistryProperty(
  114. hDevInfo, &devdata, SPDRP_FRIENDLYNAME, NULL,
  115. (PBYTE)fname, sizeof(fname), NULL);
  116. if (bSuccess) {
  117. // Add an entry to the array
  118. SSerInfo si;
  119. si.strDevPath = strDevPath;
  120. si.strFriendlyName = fname;
  121. asi.Add(si);
  122. }
  123. }
  124. else {
  125. strErr.Format(_T("SetupDiGetDeviceInterfaceDetail failed. (err=%lx)"),
  126. GetLastError());
  127. throw strErr;
  128. }
  129. }
  130. else {
  131. DWORD err = GetLastError();
  132. if (err != ERROR_NO_MORE_ITEMS) {
  133. strErr.Format(_T("SetupDiEnumDeviceInterfaces failed. (err=%lx)"), err);
  134. throw strErr;
  135. }
  136. }
  137. }
  138. }
  139. catch (CString strCatchErr) {
  140. strErr = strCatchErr;
  141. }
  142. if (pDetData != NULL)
  143. delete [] (char*)pDetData;
  144. if (hDevInfo != INVALID_HANDLE_VALUE)
  145. SetupDiDestroyDeviceInfoList(hDevInfo);
  146. if (!strErr.IsEmpty())
  147. throw strErr;
  148. }
  149. #endif /* OS_WINDOWS */