BOOL CEnumerateSerial::UsingSetupAPI2(CSimpleArray<UINT>& ports, CSimpleArray<CString>& friendlyNames) #endif { //Make sure we clear out any elements which may already be in the array(s) #if defined CENUMERATESERIAL_USE_STL ports.clear(); friendlyNames.clear(); #else ports.RemoveAll(); friendlyNames.RemoveAll(); #endif //Get the function pointers to "SetupDiGetClassDevs", "SetupDiGetClassDevs", "SetupDiEnumDeviceInfo", "SetupDiOpenDevRegKey" //and "SetupDiDestroyDeviceInfoList" in setupapi.dll CAutoHModule setupAPI(LoadLibraryFromSystem32(_T("SETUPAPI.DLL"))); if (setupAPI == NULL) return FALSE; SETUPDIOPENDEVREGKEY* lpfnLPSETUPDIOPENDEVREGKEY = reinterpret_cast<SETUPDIOPENDEVREGKEY*>(GetProcAddress(setupAPI, "SetupDiOpenDevRegKey")); #if defined _UNICODE SETUPDICLASSGUIDSFROMNAME* lpfnSETUPDICLASSGUIDSFROMNAME = reinterpret_cast<SETUPDICLASSGUIDSFROMNAME*>(GetProcAddress(setupAPI, "SetupDiClassGuidsFromNameW")); SETUPDIGETCLASSDEVS* lpfnSETUPDIGETCLASSDEVS = reinterpret_cast<SETUPDIGETCLASSDEVS*>(GetProcAddress(setupAPI, "SetupDiGetClassDevsW")); SETUPDIGETDEVICEREGISTRYPROPERTY* lpfnSETUPDIGETDEVICEREGISTRYPROPERTY = reinterpret_cast<SETUPDIGETDEVICEREGISTRYPROPERTY*>(GetProcAddress(setupAPI, "SetupDiGetDeviceRegistryPropertyW")); #else SETUPDICLASSGUIDSFROMNAME* lpfnSETUPDICLASSGUIDSFROMNAME = reinterpret_cast<SETUPDICLASSGUIDSFROMNAME*>(GetProcAddress(setupAPI, "SetupDiClassGuidsFromNameA")); SETUPDIGETCLASSDEVS* lpfnSETUPDIGETCLASSDEVS = reinterpret_cast<SETUPDIGETCLASSDEVS*>(GetProcAddress(setupAPI, "SetupDiGetClassDevsA")); SETUPDIGETDEVICEREGISTRYPROPERTY* lpfnSETUPDIGETDEVICEREGISTRYPROPERTY = reinterpret_cast<SETUPDIGETDEVICEREGISTRYPROPERTY*>(GetProcAddress(setupAPI, "SetupDiGetDeviceRegistryPropertyA")); #endif SETUPDIDESTROYDEVICEINFOLIST* lpfnSETUPDIDESTROYDEVICEINFOLIST = reinterpret_cast<SETUPDIDESTROYDEVICEINFOLIST*>(GetProcAddress(setupAPI, "SetupDiDestroyDeviceInfoList")); SETUPDIENUMDEVICEINFO* lpfnSETUPDIENUMDEVICEINFO = reinterpret_cast<SETUPDIENUMDEVICEINFO*>(GetProcAddress(setupAPI, "SetupDiEnumDeviceInfo")); if ((lpfnLPSETUPDIOPENDEVREGKEY == NULL) || (lpfnSETUPDICLASSGUIDSFROMNAME == NULL) || (lpfnSETUPDIDESTROYDEVICEINFOLIST == NULL) || (lpfnSETUPDIENUMDEVICEINFO == NULL) || (lpfnSETUPDIGETCLASSDEVS == NULL) || (lpfnSETUPDIGETDEVICEREGISTRYPROPERTY == NULL)) { //Set the error to report setupAPI.m_dwError = ERROR_CALL_NOT_IMPLEMENTED; return FALSE; } //First need to convert the name "Ports" to a GUID using SetupDiClassGuidsFromName DWORD dwGuids = 0; lpfnSETUPDICLASSGUIDSFROMNAME(_T("Ports"), NULL, 0, &dwGuids); if (dwGuids == 0) { //Set the error to report setupAPI.m_dwError = GetLastError(); return FALSE; } //Allocate the needed memory ATL::CHeapPtr<GUID> pGuids; if (!pGuids.Allocate(dwGuids)) { //Set the error to report setupAPI.m_dwError = ERROR_OUTOFMEMORY; return FALSE; } //Call the function again if (!lpfnSETUPDICLASSGUIDSFROMNAME(_T("Ports"), pGuids, dwGuids, &dwGuids)) { //Set the error to report setupAPI.m_dwError = GetLastError(); return FALSE; } //Now create a "device information set" which is required to enumerate all the ports HDEVINFO hDevInfoSet = lpfnSETUPDIGETCLASSDEVS(pGuids, NULL, NULL, DIGCF_PRESENT); if (hDevInfoSet == INVALID_HANDLE_VALUE) { //Set the error to report setupAPI.m_dwError = GetLastError(); return FALSE; } //Finally do the enumeration BOOL bMoreItems = TRUE; int nIndex = 0; SP_DEVINFO_DATA devInfo; while (bMoreItems) { //Enumerate the current device devInfo.cbSize = sizeof(SP_DEVINFO_DATA); bMoreItems = lpfnSETUPDIENUMDEVICEINFO(hDevInfoSet, nIndex, &devInfo); if (bMoreItems) { //Did we find a serial port for this device BOOL bAdded = FALSE; //Get the registry key which stores the ports settings HKEY hDeviceKey = lpfnLPSETUPDIOPENDEVREGKEY(hDevInfoSet, &devInfo, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE); if (hDeviceKey) { int nPort = 0; if (QueryRegistryPortName(hDeviceKey, nPort)) { #if defined CENUMERATESERIAL_USE_STL ports.push_back(nPort); #else ports.Add(nPort); #endif bAdded = TRUE; } //Close the key now that we are finished with it RegCloseKey(hDeviceKey); } //If the port was a serial port, then also try to get its friendly name if (bAdded) { TCHAR szFriendlyName[1024]; szFriendlyName[0] = _T('\0'); DWORD dwSize = sizeof(szFriendlyName); DWORD dwType = 0; if (lpfnSETUPDIGETDEVICEREGISTRYPROPERTY(hDevInfoSet, &devInfo, SPDRP_DEVICEDESC, &dwType, reinterpret_cast<PBYTE>(szFriendlyName), dwSize, &dwSize) && (dwType == REG_SZ)) { #if defined CENUMERATESERIAL_USE_STL friendlyNames.push_back(szFriendlyName); #else friendlyNames.Add(szFriendlyName); #endif } else { #if defined CENUMERATESERIAL_USE_STL friendlyNames.push_back(_T("")); #else friendlyNames.Add(_T("")); #endif } } } ++nIndex; } //Free up the "device information set" now that we are finished with it lpfnSETUPDIDESTROYDEVICEINFOLIST(hDevInfoSet); //Return the success indicator return TRUE; }
BOOL CEnumerateSerial::EnumeratePorts() { int SPDRPlist[] = { SPDRP_DEVICEDESC, SPDRP_FRIENDLYNAME, SPDRP_MFG, SPDRP_LOCATION_INFORMATION, SPDRP_PHYSICAL_DEVICE_OBJECT_NAME, -1}; // Clear anything from previous enumerate... ResetPortList(); // Dynamically get pointers to device installation library (setupapi.dll) // in case it isn't installed... // SetupDiOpenDevRegKey // SetupDiEnumDeviceInfo // SetupDiDestroyDeviceInfoList // SetupDiGetClassDevs // SetupDiClassGuidsFromName // SetupDiGetDeviceRegistryProperty CLoadLib setupAPI(_T("SETUPAPI.DLL")); if (setupAPI == NULL) return FALSE; #define SETUPPROC(x,y) x* lpfn##x = reinterpret_cast<x*>(GetProcAddress(setupAPI,y)) SETUPPROC(SETUPDIOPENDEVREGKEY,"SetupDiOpenDevRegKey"); SETUPPROC(SETUPDIENUMDEVICEINFO, "SetupDiEnumDeviceInfo"); SETUPPROC(SETUPDIDESTROYDEVICEINFOLIST, "SetupDiDestroyDeviceInfoList"); #if defined _UNICODE SETUPPROC(SETUPDIGETCLASSDEVS, "SetupDiGetClassDevsW"); SETUPPROC(SETUPDICLASSGUIDSFROMNAME, "SetupDiClassGuidsFromNameW"); SETUPPROC(SETUPDIGETDEVICEREGISTRYPROPERTY, "SetupDiGetDeviceRegistryPropertyW"); #else SETUPPROC(SETUPDIGETCLASSDEVS, "SetupDiGetClassDevsA"); SETUPPROC(SETUPDICLASSGUIDSFROMNAME, "SetupDiClassGuidsFromNameA"); SETUPPROC(SETUPDIGETDEVICEREGISTRYPROPERTY, "SetupDiGetDeviceRegistryPropertyA"); #endif if ((lpfnSETUPDIOPENDEVREGKEY == NULL) || (lpfnSETUPDIENUMDEVICEINFO == NULL) || (lpfnSETUPDIGETDEVICEREGISTRYPROPERTY == NULL) || (lpfnSETUPDIGETCLASSDEVS == NULL) || (lpfnSETUPDICLASSGUIDSFROMNAME == NULL) || (lpfnSETUPDIDESTROYDEVICEINFOLIST == NULL)) { SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } // First need to convert the name "Ports" to a GUID using SetupDiClassGuidsFromName... DWORD dwGuids = 0; lpfnSETUPDICLASSGUIDSFROMNAME(_T("Ports"), NULL, 0, &dwGuids); if (dwGuids == 0) return FALSE; // Allocate the needed memory... CHeapPtr<GUID> GuidArray; GUID *pGuids = (GUID*)GuidArray.Allocate(sizeof(GUID) * dwGuids); if (pGuids==NULL) { SetLastError(ERROR_OUTOFMEMORY); return FALSE; } // Call the function again... if (!lpfnSETUPDICLASSGUIDSFROMNAME(_T("Ports"), pGuids, dwGuids, &dwGuids)) return FALSE; // Now create a "device information set" which is required to enumerate all the ports... HDEVINFO hDevInfoSet = lpfnSETUPDIGETCLASSDEVS(pGuids, NULL, NULL, DIGCF_PRESENT); if (hDevInfoSet == INVALID_HANDLE_VALUE) return FALSE; // Finally do the enumeration... int nIndex = 0; SP_DEVINFO_DATA devInfo; CHeapPtr<TCHAR> tempstr(256); CSerialPortInfo *portinfo = NULL; // Enumerate the current device... devInfo.cbSize = sizeof(SP_DEVINFO_DATA); while (lpfnSETUPDIENUMDEVICEINFO(hDevInfoSet, nIndex, &devInfo)) { portinfo = NULL; // Get the registry key which stores the ports settings... HKEY hDeviceKey = lpfnSETUPDIOPENDEVREGKEY(hDevInfoSet, &devInfo, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE); if (hDeviceKey) { tempstr.FillZero(); DWORD dwSize = tempstr.SizeOf(); DWORD dwType = 0; // Read name of port. If formatted as "COMxx" then allocate a port slot... if ((RegQueryValueEx(hDeviceKey, _T("PortName"), NULL, &dwType, reinterpret_cast<LPBYTE>((TCHAR*)tempstr), &dwSize) == ERROR_SUCCESS) && (dwType == REG_SZ)) if (_tcslen(tempstr) > 3) if ((_tcsnicmp(tempstr, _T("COM"), 3) == 0) && IsNumber(&(tempstr[3]))) portinfo = AddPort(_ttoi(&(tempstr[3]))); // Close the key now that we are finished with it... RegCloseKey(hDeviceKey); } // If a serial port, then try getting additional useful descriptive info... if (portinfo) { for (int i=0; SPDRPlist[i]>=0; i++) { tempstr.FillZero(); DWORD dwSize = tempstr.SizeOf(); DWORD dwType = 0; if (lpfnSETUPDIGETDEVICEREGISTRYPROPERTY(hDevInfoSet, &devInfo, SPDRPlist[i], &dwType, reinterpret_cast<PBYTE>((TCHAR*)tempstr), dwSize, &dwSize) && (dwType == REG_SZ)) switch (SPDRPlist[i]) { case SPDRP_MFG : portinfo->SetManufacturer(tempstr); break; case SPDRP_DEVICEDESC : portinfo->SetDeviceDesc(tempstr); break; case SPDRP_FRIENDLYNAME : portinfo->SetFriendlyName(tempstr); break; case SPDRP_LOCATION_INFORMATION : portinfo->SetLocationInfo(tempstr); break; case SPDRP_PHYSICAL_DEVICE_OBJECT_NAME : portinfo->SetPhysLocation(tempstr); break; } } // Get COM port properties... HANDLE hPort = ::CreateFile(portinfo->GetPortDeviceName(), GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0); if (hPort != INVALID_HANDLE_VALUE) { COMMPROP cp; GetCommProperties(hPort, &cp); portinfo->SetCommProp(cp); TRACE ("Port %d: CommProp: maxbaud=%08x settablebaud=%08x\n",portinfo->GetPortNum(),cp.dwMaxBaud,cp.dwSettableBaud); CloseHandle(hPort); } } ++nIndex; } // Free up the "device information set" now that we are finished with it lpfnSETUPDIDESTROYDEVICEINFOLIST(hDevInfoSet); // Return the success indicator return TRUE; }