BOOL CEnumerateSerial::UsingGetDefaultCommConfig(CSimpleArray<UINT>& ports) #endif { //Make sure we clear out any elements which may already be in the array #if defined CENUMERATESERIAL_USE_STL ports.clear(); #else ports.RemoveAll(); #endif //Up to 255 COM ports are supported so we iterate through all of them seeing //if we can get the default configuration for (UINT i=1; i<256; i++) { //Form the Raw device name CString sPort; sPort.Format(_T("COM%u"), i); COMMCONFIG cc; DWORD dwSize = sizeof(COMMCONFIG); if (GetDefaultCommConfig(sPort, &cc, &dwSize)) { #if defined CENUMERATESERIAL_USE_STL ports.push_back(i); #else ports.Add(i); #endif } } //Return the success indicator return TRUE; }
BOOL CEnumerateSerial::UsingEnumPorts(CSimpleArray<UINT>& ports) #endif { //Make sure we clear out any elements which may already be in the array #if defined CENUMERATESERIAL_USE_STL ports.clear(); #else ports.RemoveAll(); #endif //Call the first time to determine the size of the buffer to allocate DWORD cbNeeded = 0; DWORD dwPorts = 0; EnumPorts(NULL, 1, NULL, 0, &cbNeeded, &dwPorts); //What will be the return value BOOL bSuccess = FALSE; //Allocate the buffer and recall CAutoHeapAlloc portsBuffer; if (portsBuffer.Allocate(cbNeeded)) { BYTE* pPorts = static_cast<BYTE*>(portsBuffer.m_pData); bSuccess = EnumPorts(NULL, 1, pPorts, cbNeeded, &cbNeeded, &dwPorts); if (bSuccess) { PORT_INFO_1* pPortInfo = reinterpret_cast<PORT_INFO_1*>(pPorts); for (DWORD i=0; i<dwPorts; i++) { //If it looks like "COMX" then //add it to the array which will be returned size_t nLen = _tcslen(pPortInfo->pName); if (nLen > 3) { if ((_tcsnicmp(pPortInfo->pName, _T("COM"), 3) == 0) && IsNumeric(&(pPortInfo->pName[3]), TRUE)) { //Work out the port number int nPort = _ttoi(&(pPortInfo->pName[3])); #if defined CENUMERATESERIAL_USE_STL ports.push_back(nPort); #else ports.Add(nPort); #endif } } pPortInfo++; } } } else SetLastError(ERROR_OUTOFMEMORY); return bSuccess; }
BOOL CEnumerateSerial::UsingCreateFile(CSimpleArray<UINT>& ports) #endif { //Make sure we clear out any elements which may already be in the array #if defined CENUMERATESERIAL_USE_STL ports.clear(); #else ports.RemoveAll(); #endif //Up to 255 COM ports are supported so we iterate through all of them seeing //if we can open them or if we fail to open them, get an access denied or general error error. //Both of these cases indicate that there is a COM port at that number. for (UINT i=1; i<256; i++) { //Form the Raw device name CString sPort; sPort.Format(_T("\\\\.\\COM%u"), i); //Try to open the port BOOL bSuccess = FALSE; CAutoHandle port(CreateFile(sPort, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0)); if (port == INVALID_HANDLE_VALUE) { DWORD dwError = GetLastError(); //Check to see if the error was because some other app had the port open or a general failure if (dwError == ERROR_ACCESS_DENIED || dwError == ERROR_GEN_FAILURE || dwError == ERROR_SHARING_VIOLATION || dwError == ERROR_SEM_TIMEOUT) bSuccess = TRUE; } else { //The port was opened successfully bSuccess = TRUE; } //Add the port number to the array which will be returned if (bSuccess) { #if defined CENUMERATESERIAL_USE_STL ports.push_back(i); #else ports.Add(i); #endif } } //Return the success indicator return TRUE; }
BOOL CEnumerateSerial::UsingWMI(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 //What will be the return value BOOL bSuccess = FALSE; //Create the WBEM locator ATL::CComPtr<IWbemLocator> locator; HRESULT hr = CoCreateInstance(CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, IID_IWbemLocator, reinterpret_cast<void**>(&locator)); if (SUCCEEDED(hr)) { ATL::CComPtr<IWbemServices> services; hr = locator->ConnectServer(_bstr_t("\\\\.\\root\\cimv2"), NULL, NULL, NULL, 0, NULL, NULL, &services); if (SUCCEEDED(hr)) { //Execute the query ATL::CComPtr<IEnumWbemClassObject> classObject; hr = services->CreateInstanceEnum(_bstr_t("Win32_SerialPort"), WBEM_FLAG_RETURN_WBEM_COMPLETE, NULL, &classObject); if (SUCCEEDED(hr)) { bSuccess = TRUE; //Now enumerate all the ports hr = WBEM_S_NO_ERROR; //Final Next will return WBEM_S_FALSE while (hr == WBEM_S_NO_ERROR) { ULONG uReturned = 0; ATL::CComPtr<IWbemClassObject> apObj[10]; hr = classObject->Next(WBEM_INFINITE, 10, reinterpret_cast<IWbemClassObject**>(apObj), &uReturned); if (SUCCEEDED(hr)) { for (ULONG n=0; n<uReturned; n++) { ATL::CComVariant varProperty1; HRESULT hrGet = apObj[n]->Get(L"DeviceID", 0, &varProperty1, NULL, NULL); if (SUCCEEDED(hrGet) && (varProperty1.vt == VT_BSTR) && (wcslen(varProperty1.bstrVal) > 3)) { //If it looks like "COMX" then add it to the array which will be returned if ((_wcsnicmp(varProperty1.bstrVal, L"COM", 3) == 0) && IsNumeric(&(varProperty1.bstrVal[3]), TRUE)) { //Work out the port number int nPort = _wtoi(&(varProperty1.bstrVal[3])); #if defined CENUMERATESERIAL_USE_STL ports.push_back(nPort); #else ports.Add(nPort); #endif //Also get the friendly name of the port ATL::CComVariant varProperty2; if (SUCCEEDED(apObj[n]->Get(L"Name", 0, &varProperty2, NULL, NULL)) && (varProperty2.vt == VT_BSTR)) { #if defined CENUMERATESERIAL_USE_STL #if defined _UNICODE std::wstring szName(varProperty2.bstrVal); #else std::string szName(ATL::CW2A(varProperty2.bstrVal)); #endif friendlyNames.push_back(szName); #else friendlyNames.Add(CString(varProperty2.bstrVal)); #endif } else { #if defined CENUMERATESERIAL_USE_STL friendlyNames.push_back(_T("")); #else friendlyNames.Add(_T("")); #endif } } } } } } } } } return bSuccess; }
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::UsingQueryDosDevice(CSimpleArray<UINT>& ports) #endif { //What will be the return value from this function (assume the worst) BOOL bSuccess = FALSE; //Make sure we clear out any elements which may already be in the array #if defined CENUMERATESERIAL_USE_STL ports.clear(); #else ports.RemoveAll(); #endif //Determine what OS we are running on OSVERSIONINFO osvi; osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); BOOL bGetVer = GetVersionEx(&osvi); //On NT use the QueryDosDevice API if (bGetVer && (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)) { //Use QueryDosDevice to look for all devices of the form COMx. Since QueryDosDevice does //not consitently report the required size of buffer, lets start with a reasonable buffer size //of 4096 characters and go from there int nChars = 4096; BOOL bWantStop = FALSE; while (nChars && !bWantStop) { ATL::CHeapPtr<TCHAR> szDevices; if (szDevices.Allocate(nChars)) { DWORD dwChars = QueryDosDevice(NULL, szDevices, nChars); if (dwChars == 0) { DWORD dwError = GetLastError(); if (dwError == ERROR_INSUFFICIENT_BUFFER) { //Expand the buffer and loop around again nChars *= 2; } else bWantStop = TRUE; } else { bSuccess = TRUE; bWantStop = TRUE; size_t i=0; while (szDevices[i] != _T('\0')) { //Get the current device name TCHAR* pszCurrentDevice = &(szDevices[i]); //If it looks like "COMX" then //add it to the array which will be returned size_t nLen = _tcslen(pszCurrentDevice); if (nLen > 3) { if ((_tcsnicmp(pszCurrentDevice, _T("COM"), 3) == 0) && IsNumeric(&(pszCurrentDevice[3]), FALSE)) { //Work out the port number int nPort = _ttoi(&pszCurrentDevice[3]); #if defined CENUMERATESERIAL_USE_STL ports.push_back(nPort); #else ports.Add(nPort); #endif } } //Go to next device name i += (nLen + 1); } } } else { bWantStop = TRUE; SetLastError(ERROR_OUTOFMEMORY); } } } else SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return bSuccess; }
BOOL CEnumerateSerial::UsingRegistry(CSimpleArray<CString>& ports) #endif { //Make sure we clear out any elements which may already be in the array(s) #if defined CENUMERATESERIAL_USE_STL ports.clear(); #else ports.RemoveAll(); #endif //What will be the return value from this function (assume the worst) BOOL bSuccess = FALSE; HKEY hSERIALCOMM; if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("HARDWARE\\DEVICEMAP\\SERIALCOMM"), 0, KEY_QUERY_VALUE, &hSERIALCOMM) == ERROR_SUCCESS) { //Get the max value name and max value lengths DWORD dwMaxValueNameLen; DWORD dwMaxValueLen; DWORD dwQueryInfo = RegQueryInfoKey(hSERIALCOMM, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &dwMaxValueNameLen, &dwMaxValueLen, NULL, NULL); if (dwQueryInfo == ERROR_SUCCESS) { DWORD dwMaxValueNameSizeInChars = dwMaxValueNameLen + 1; //Include space for the NULL terminator DWORD dwMaxValueNameSizeInBytes = dwMaxValueNameSizeInChars * sizeof(TCHAR); DWORD dwMaxValueDataSizeInChars = dwMaxValueLen/sizeof(TCHAR) + 1; //Include space for the NULL terminator DWORD dwMaxValueDataSizeInBytes = dwMaxValueDataSizeInChars * sizeof(TCHAR); //Allocate some space for the value name and value data ATL::CHeapPtr<TCHAR> szValueName; ATL::CHeapPtr<BYTE> byValue; if (szValueName.Allocate(dwMaxValueNameSizeInChars) && byValue.Allocate(dwMaxValueDataSizeInBytes)) { bSuccess = TRUE; //Enumerate all the values underneath HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM DWORD dwIndex = 0; DWORD dwType; DWORD dwValueNameSize = dwMaxValueNameSizeInChars; DWORD dwDataSize = dwMaxValueDataSizeInBytes; memset(szValueName.m_pData, 0, dwMaxValueNameSizeInBytes); memset(byValue.m_pData, 0, dwMaxValueDataSizeInBytes); LONG nEnum = RegEnumValue(hSERIALCOMM, dwIndex, szValueName, &dwValueNameSize, NULL, &dwType, byValue, &dwDataSize); while (nEnum == ERROR_SUCCESS) { //If the value is of the correct type, then add it to the array if (dwType == REG_SZ) { TCHAR* szPort = reinterpret_cast<TCHAR*>(byValue.m_pData); #if defined CENUMERATESERIAL_USE_STL ports.push_back(szPort); #else ports.Add(szPort); #endif } //Prepare for the next time around dwValueNameSize = dwMaxValueNameSizeInChars; dwDataSize = dwMaxValueDataSizeInBytes; memset(szValueName.m_pData, 0, dwMaxValueNameSizeInBytes); memset(byValue.m_pData, 0, dwMaxValueDataSizeInBytes); ++dwIndex; nEnum = RegEnumValue(hSERIALCOMM, dwIndex, szValueName, &dwValueNameSize, NULL, &dwType, byValue, &dwDataSize); } } else SetLastError(ERROR_OUTOFMEMORY); } //Close the registry key now that we are finished with it RegCloseKey(hSERIALCOMM); if (dwQueryInfo != ERROR_SUCCESS) SetLastError(dwQueryInfo); } return bSuccess; }
BOOL CEnumerateSerial::UsingComDB(CSimpleArray<UINT>& ports) #endif { //Make sure we clear out any elements which may already be in the array(s) #if defined CENUMERATESERIAL_USE_STL ports.clear(); #else ports.RemoveAll(); #endif //What will be the return value from this function (assume the worst) BOOL bSuccess = FALSE; //Get the function pointers to "ComDBOpen", "ComDBClose" & "ComDBGetCurrentPortUsage" in msports.dll CAutoHModule msPorts(LoadLibraryFromSystem32(_T("MSPORTS.DLL"))); if (msPorts == NULL) return FALSE; COMDBOPEN* lpfnLPCOMDBOPEN = reinterpret_cast<COMDBOPEN*>(GetProcAddress(msPorts, "ComDBOpen")); COMDBCLOSE* lpfnLPCOMDBCLOSE = reinterpret_cast<COMDBCLOSE*>(GetProcAddress(msPorts, "ComDBClose")); COMDBGETCURRENTPORTUSAGE* lpfnCOMDBGETCURRENTPORTUSAGE = reinterpret_cast<COMDBGETCURRENTPORTUSAGE*>(GetProcAddress(msPorts, "ComDBGetCurrentPortUsage")); if ((lpfnLPCOMDBOPEN != NULL) && (lpfnLPCOMDBCLOSE != NULL) && (lpfnCOMDBGETCURRENTPORTUSAGE != NULL)) { //First need to open up the DB HCOMDB hComDB; DWORD dwComOpen = lpfnLPCOMDBOPEN(&hComDB); if (dwComOpen == ERROR_SUCCESS) { //Work out the size of the buffer required DWORD dwMaxPortsReported = 0; DWORD dwPortUsage = lpfnCOMDBGETCURRENTPORTUSAGE(hComDB, NULL, 0, CDB_REPORT_BYTES, &dwMaxPortsReported); if (dwPortUsage == ERROR_SUCCESS) { //Allocate some heap space and recall the function ATL::CHeapPtr<BYTE> portBytes; if (portBytes.Allocate(dwMaxPortsReported)) { bSuccess = TRUE; if (lpfnCOMDBGETCURRENTPORTUSAGE(hComDB, portBytes, dwMaxPortsReported, CDB_REPORT_BYTES, &dwMaxPortsReported) == ERROR_SUCCESS) { //Work thro the byte bit array for ports which are in use for (DWORD i=0; i<dwMaxPortsReported; i++) { if (portBytes[i]) { #if defined CENUMERATESERIAL_USE_STL ports.push_back(i + 1); #else ports.Add(i + 1); #endif } } } } else msPorts.m_dwError = ERROR_OUTOFMEMORY; } else msPorts.m_dwError = dwPortUsage; //Close the DB lpfnLPCOMDBCLOSE(hComDB); } else msPorts.m_dwError = dwComOpen; } else msPorts.m_dwError = ERROR_CALL_NOT_IMPLEMENTED; return bSuccess; }
BOOL CEnumerateSerial::UsingWMI(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 //What will be the return value BOOL bSuccess = FALSE; //Create the WBEM locator IWbemLocator* pLocator = NULL; HRESULT hr = CoCreateInstance(CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, IID_IWbemLocator, reinterpret_cast<void**>(&pLocator)); if (SUCCEEDED(hr)) { IWbemServices* pServices = NULL; hr = pLocator->ConnectServer(_bstr_t("\\\\.\\root\\cimv2"), NULL, NULL, NULL, 0, NULL, NULL, &pServices); if (SUCCEEDED(hr)) { //Execute the query IEnumWbemClassObject* pClassObject = NULL; hr = pServices->CreateInstanceEnum(_bstr_t("Win32_SerialPort"), WBEM_FLAG_RETURN_WBEM_COMPLETE, NULL, &pClassObject); if (SUCCEEDED(hr)) { bSuccess = TRUE; //Now enumerate all the ports hr = WBEM_S_NO_ERROR; //Final Next will return WBEM_S_FALSE while (hr == WBEM_S_NO_ERROR) { ULONG uReturned = 0; IWbemClassObject* apObj[10]; memset(apObj, 0, sizeof(apObj)); hr = pClassObject->Next(WBEM_INFINITE, 10, reinterpret_cast<IWbemClassObject**>(apObj), &uReturned); if (SUCCEEDED(hr)) { for (ULONG n=0; n<uReturned; n++) { VARIANT varProperty1; VariantInit(&varProperty1); HRESULT hrGet = apObj[n]->Get(L"DeviceID", 0, &varProperty1, NULL, NULL); if (SUCCEEDED(hrGet) && (varProperty1.vt == VT_BSTR) && (wcslen(varProperty1.bstrVal) > 3)) { //If it looks like "COMX" then add it to the array which will be returned if ((_wcsnicmp(varProperty1.bstrVal, L"COM", 3) == 0) && IsNumeric(&(varProperty1.bstrVal[3]), TRUE)) { //Work out the port number int nPort = _wtoi(&(varProperty1.bstrVal[3])); #if defined CENUMERATESERIAL_USE_STL ports.push_back(nPort); #else ports.Add(nPort); #endif //Also get the friendly name of the port VARIANT varProperty2; VariantInit(&varProperty2); if (SUCCEEDED(apObj[n]->Get(L"Name", 0, &varProperty2, NULL, NULL)) && (varProperty2.vt == VT_BSTR)) { #if defined CENUMERATESERIAL_USE_STL #if defined _UNICODE std::wstring szName(varProperty2.bstrVal); #else CAutoHeapAlloc szAsciiValue; int nLengthA = WideCharToMultiByte(CP_ACP, 0, varProperty2.bstrVal, -1, NULL, 0, NULL, NULL); if (nLengthA) { if (szAsciiValue.Allocate(nLengthA)) WideCharToMultiByte(CP_ACP, 0, varProperty2.bstrVal, -1, static_cast<LPSTR>(szAsciiValue.m_pData), nLengthA, NULL, NULL); } std::string szName(static_cast<LPSTR>(szAsciiValue.m_pData)); #endif friendlyNames.push_back(szName); #else friendlyNames.Add(CString(varProperty2.bstrVal)); #endif } else { #if defined CENUMERATESERIAL_USE_STL friendlyNames.push_back(_T("")); #else friendlyNames.Add(_T("")); #endif } //Free up the variant; VariantClear(&varProperty2); } } //Free up the variant; VariantClear(&varProperty1); //Free up each COM interface apObj[n]->Release(); } } } //Free up the COM interface pClassObject->Release(); } //Free up the COM interface pServices->Release(); } //Free up the COM interface pLocator->Release(); } return bSuccess; }
BOOL CEnumerateSerial::UsingQueryDosDevice(CSimpleArray<UINT>& ports) #endif { //What will be the return value from this function (assume the worst) BOOL bSuccess = FALSE; //Make sure we clear out any elements which may already be in the array #if defined CENUMERATESERIAL_USE_STL ports.clear(); #else ports.RemoveAll(); #endif //On the NT kernel use the QueryDosDevice API OSVERSIONINFOEX osvi; memset(&osvi, 0, sizeof(osvi)); osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); osvi.dwPlatformId = VER_PLATFORM_WIN32_NT; ULONGLONG dwlConditionMask = 0; VER_SET_CONDITION(dwlConditionMask, VER_PLATFORMID, VER_EQUAL); if (VerifyVersionInfo(&osvi, VER_PLATFORMID, dwlConditionMask)) { //Use QueryDosDevice to look for all devices of the form COMx. Since QueryDosDevice does //not consitently report the required size of buffer, lets start with a reasonable buffer size //of 4096 characters and go from there int nChars = 4096; BOOL bWantStop = FALSE; while (nChars && !bWantStop) { CAutoHeapAlloc devices; if (devices.Allocate(nChars * sizeof(TCHAR))) { LPTSTR pszDevices = static_cast<LPTSTR>(devices.m_pData); DWORD dwChars = QueryDosDevice(NULL, pszDevices, nChars); if (dwChars == 0) { DWORD dwError = GetLastError(); if (dwError == ERROR_INSUFFICIENT_BUFFER) { //Expand the buffer and loop around again nChars *= 2; } else bWantStop = TRUE; } else { bSuccess = TRUE; bWantStop = TRUE; size_t i=0; while (pszDevices[i] != _T('\0')) { //Get the current device name TCHAR* pszCurrentDevice = &(pszDevices[i]); //If it looks like "COMX" then //add it to the array which will be returned size_t nLen = _tcslen(pszCurrentDevice); if (nLen > 3) { if ((_tcsnicmp(pszCurrentDevice, _T("COM"), 3) == 0) && IsNumeric(&(pszCurrentDevice[3]), FALSE)) { //Work out the port number int nPort = _ttoi(&pszCurrentDevice[3]); #if defined CENUMERATESERIAL_USE_STL ports.push_back(nPort); #else ports.Add(nPort); #endif } } //Go to next device name i += (nLen + 1); } } } else { bWantStop = TRUE; SetLastError(ERROR_OUTOFMEMORY); } } } else SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return bSuccess; }