From 4fd845dc19767a54b46fc4313474bb124aa3e8de Mon Sep 17 00:00:00 2001 From: micio Date: Sun, 22 May 2016 15:35:21 +0000 Subject: [PATCH] Bazaar/Serial : better com port enumeration using registry git-svn-id: svn://ultimatepp.org/upp/trunk@9869 f0d560ea-af0d-0410-9eb7-867de7ffcac7 --- bazaar/Serial/Serial.h | 2 +- bazaar/Serial/SerialWindows.cpp | 516 +++++++++++++++++++++----------- 2 files changed, 344 insertions(+), 174 deletions(-) diff --git a/bazaar/Serial/Serial.h b/bazaar/Serial/Serial.h index e290ddf26..d1cfd8f53 100644 --- a/bazaar/Serial/Serial.h +++ b/bazaar/Serial/Serial.h @@ -26,7 +26,7 @@ class Serial // default baud rates static dword stdBauds[]; static int stdBaudsCount; - + protected: public: diff --git a/bazaar/Serial/SerialWindows.cpp b/bazaar/Serial/SerialWindows.cpp index e18b3f182..d83ab8b9e 100644 --- a/bazaar/Serial/SerialWindows.cpp +++ b/bazaar/Serial/SerialWindows.cpp @@ -4,7 +4,10 @@ #include typedef DWORD REGSAM; + +#ifdef USE_SETUPAPI #include +#endif NAMESPACE_UPP @@ -16,7 +19,7 @@ dword Serial::stdBauds[] = 38400, 57600, 115200, 128000, 256000 }; -int Serial::stdBaudsCount = sizeof(Serial::stdBauds) / sizeof(dword); +int Serial::stdBaudsCount = sizeof ( Serial::stdBauds ) / sizeof ( dword ); // constructor Serial::Serial() @@ -26,12 +29,12 @@ Serial::Serial() fd = INVALID_HANDLE_VALUE; } -Serial::Serial(String const &port, unsigned long speed, byte parity, byte bits, byte stopBits) +Serial::Serial ( String const &port, unsigned long speed, byte parity, byte bits, byte stopBits ) { isError = false; errCode = Ok; fd = INVALID_HANDLE_VALUE; - Open(port, speed, parity, bits, stopBits); + Open ( port, speed, parity, bits, stopBits ); } // destructor @@ -41,11 +44,12 @@ Serial::~Serial() } // open the port -bool Serial::Open(String const &port, dword speed, byte parity, byte bits, byte stopBits) +bool Serial::Open ( String const &port, dword speed, byte parity, byte bits, byte stopBits ) { // open the device - fd = CreateFile("\\\\.\\" + port, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0); - if(fd == INVALID_HANDLE_VALUE) + fd = CreateFile ( "\\\\.\\" + port, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0 ); + + if ( fd == INVALID_HANDLE_VALUE ) { isError = true; errCode = DeviceError; @@ -53,15 +57,17 @@ bool Serial::Open(String const &port, dword speed, byte parity, byte bits, byte } DCB dcb; + char dcbSz[50]; COMMTIMEOUTS cmt; // clear dcb and set length - FillMemory(&dcb, sizeof(dcb), 0); - dcb.DCBlength = sizeof(dcb); + FillMemory ( &dcb, sizeof ( dcb ), 0 ); + dcb.DCBlength = sizeof ( dcb ); // check baud is valid - if(GetStandardBaudRates().Find(speed) < 0) + + if ( GetStandardBaudRates().Find ( speed ) < 0 ) { Close(); isError = true; @@ -71,33 +77,38 @@ bool Serial::Open(String const &port, dword speed, byte parity, byte bits, byte // check parity */ char cParity; - switch (parity) + + switch ( parity ) { + case ParityNone : cParity = 'n'; break; - + case ParityEven : cParity = 'e'; break; - + case ParityOdd : cParity = 'o'; break; - + case ParityMark : + case ParitySpace : + default: - { - Close(); - isError = true; - errCode = InvalidParity; - return false; - } + { + Close(); + isError = true; + errCode = InvalidParity; + return false; + } } // check data bits - if (bits < 5 || bits > 8) + + if ( bits < 5 || bits > 8 ) { Close(); isError = true; @@ -106,7 +117,8 @@ bool Serial::Open(String const &port, dword speed, byte parity, byte bits, byte } // check stop bits - if (stopBits < 1 || stopBits > 2) + + if ( stopBits < 1 || stopBits > 2 ) { Close(); isError = true; @@ -115,8 +127,9 @@ bool Serial::Open(String const &port, dword speed, byte parity, byte bits, byte } // build dcb - sprintf_s(dcbSz, 49, "%d,%c,%d,%d", speed, cParity, bits, stopBits); - if (!BuildCommDCB(dcbSz, &dcb)) + sprintf_s ( dcbSz, 49, "%d,%c,%d,%d", speed, cParity, bits, stopBits ); + + if ( !BuildCommDCB ( dcbSz, &dcb ) ) { Close(); isError = true; @@ -124,8 +137,48 @@ bool Serial::Open(String const &port, dword speed, byte parity, byte bits, byte return false; } + /* + dcb.BaudRate = speed; + if(stopBits == 1) + dcb.StopBits = ONESTOPBIT; + else + dcb.StopBits = TWOSTOPBITS; + switch(parity) + { + case ParityNone: + dcb.Parity = PARITY_NONE; + break; + case ParityEven: + dcb.Parity = PARITY_EVEN; + break; + case ParityOdd: + dcb.Parity = PARITY_ODD; + break; + default: + break; + } + switch(bits) + { + case 5: + dcb.ByteSize = DATABITS_5; + break; + case 7: + dcb.ByteSize = DATABITS_7; + break; + case 8: + dcb.ByteSize = DATABITS_8; + break; + default: + break; + } + dcb.fDtrControl = 0; + dcb.fRtsControl = 0; + */ + + // set dcb to serial port */ - if(!SetCommState(fd, &dcb)) + + if ( !SetCommState ( fd, &dcb ) ) { Close(); isError = true; @@ -134,7 +187,8 @@ bool Serial::Open(String const &port, dword speed, byte parity, byte bits, byte } // set input and output bufffer sizes - if(!SetupComm(fd, 1024, 1024)) + + if ( !SetupComm ( fd, 1024, 1024 ) ) { Close(); isError = true; @@ -144,241 +198,284 @@ bool Serial::Open(String const &port, dword speed, byte parity, byte bits, byte // set timeouts to 0 -- non blocking cmt.ReadIntervalTimeout = MAXDWORD; + cmt.ReadTotalTimeoutMultiplier = 0; + cmt.ReadTotalTimeoutConstant = 0; + cmt.WriteTotalTimeoutMultiplier = 0; + cmt.WriteTotalTimeoutConstant = MAXDWORD; - if (!SetCommTimeouts(fd, &cmt)) + + if ( !SetCommTimeouts ( fd, &cmt ) ) { Close(); isError = true; errCode = DeviceError; return false; } - + return true; } // close the port -void Serial::Close(void) +void Serial::Close ( void ) { - if(fd == INVALID_HANDLE_VALUE) + if ( fd == INVALID_HANDLE_VALUE ) return; // cancel pending i/o - CancelIo(fd); + CancelIo ( fd ); // close the device - CloseHandle(fd); + CloseHandle ( fd ); + fd = INVALID_HANDLE_VALUE; } // flush data -bool Serial::FlushInput(void) +bool Serial::FlushInput ( void ) { - return PurgeComm(fd, PURGE_RXCLEAR); + return PurgeComm ( fd, PURGE_RXCLEAR ); } -bool Serial::FlushOutput(void) +bool Serial::FlushOutput ( void ) { - return PurgeComm(fd, PURGE_TXCLEAR); + return PurgeComm ( fd, PURGE_TXCLEAR ); } -bool Serial::FlushAll(void) +bool Serial::FlushAll ( void ) { - return PurgeComm(fd, PURGE_RXCLEAR) & PurgeComm(fd, PURGE_TXCLEAR); + return PurgeComm ( fd, PURGE_RXCLEAR ) & PurgeComm ( fd, PURGE_TXCLEAR ); } // read a single byte, block 'timeout' milliseconds -bool Serial::Read(byte &c, uint32_t timeout) +bool Serial::Read ( byte &c, uint32_t timeout ) { char buf[1]; unsigned long count = 0; - - uint32_t tim = (uint32_t)msecs() + timeout; - for(;;) + + uint32_t tim = ( uint32_t ) msecs() + timeout; + + for ( ;; ) { count = 0; - ReadFile(fd, buf, 1, &count, NULL); - if(!count) + ReadFile ( fd, buf, 1, &count, NULL ); + + if ( !count ) { - if((uint32_t)msecs() > tim) + if ( ( uint32_t ) msecs() > tim ) return false; + continue; } - c = (byte)buf[0]; + + c = ( byte ) buf[0]; + return true; - } + } } -bool Serial::Read(char &c, uint32_t timeout) +bool Serial::Read ( char &c, uint32_t timeout ) { char buf[1]; unsigned long count = 0; - - uint32_t tim = (uint32_t)msecs() + timeout; - for(;;) + + uint32_t tim = ( uint32_t ) msecs() + timeout; + + for ( ;; ) { count = 0; - ReadFile(fd, buf, 1, &count, NULL); - if(!count) + ReadFile ( fd, buf, 1, &count, NULL ); + + if ( !count ) { - if((uint32_t)msecs() > tim) + if ( ( uint32_t ) msecs() > tim ) return false; + continue; } + c = buf[0]; + return true; - } + } } // write a single byte -bool Serial::Write(char c, uint32_t timeout) +bool Serial::Write ( char c, uint32_t timeout ) { unsigned long count = 0; - if(!timeout) + + if ( !timeout ) { - WriteFile(fd, &c, 1, &count, NULL); + WriteFile ( fd, &c, 1, &count, NULL ); return count == 1; } + else { uint32_t tim = msecs() + timeout; - for(;;) + + for ( ;; ) { - WriteFile(fd, &c, 1, &count, NULL); - if(count == 1) + WriteFile ( fd, &c, 1, &count, NULL ); + if ( count == 1 ) return true; - if((uint32_t)msecs() > tim) + + if ( ( uint32_t ) msecs() > tim ) break; } + return false; } } - + // read data, requested amount, blocks 'timeout' milliseconds // if reqSize == 0 just read all available data, waiting for 'timeout' if != 0 -String Serial::Read(size_t reqSize, uint32_t timeout) +String Serial::Read ( size_t reqSize, uint32_t timeout ) { char buf[1001]; String res; unsigned long count = 0; unsigned long n; - uint32_t tim = (uint32_t)msecs() + timeout; - if(reqSize) + uint32_t tim = ( uint32_t ) msecs() + timeout; + + if ( reqSize ) { - n = min(reqSize, (size_t)1000); - while(reqSize) + n = min ( reqSize, ( size_t ) 1000 ); + + while ( reqSize ) { count = 0; - ReadFile(fd, buf, n, &count, NULL); - if(!count) + ReadFile ( fd, buf, n, &count, NULL ); + + if ( !count ) { - if((uint32_t)msecs() > tim) + if ( ( uint32_t ) msecs() > tim ) break; + continue; } - tim = (uint32_t)msecs() + timeout; - if(count) + + tim = ( uint32_t ) msecs() + timeout; + + if ( count ) { reqSize -= count; - res.Cat(buf, count); + res.Cat ( buf, count ); } - n = min(reqSize, (size_t)1000); + + n = min ( reqSize, ( size_t ) 1000 ); } } + else { - for(;;) + for ( ;; ) { count = 0; - ReadFile(fd, buf, 1000, &count, NULL); - if(!count) + ReadFile ( fd, buf, 1000, &count, NULL ); + + if ( !count ) { - if((uint32_t)msecs() > tim) + if ( ( uint32_t ) msecs() > tim ) break; + continue; } - tim = (uint32_t)msecs() + timeout; - if(count) - res.Cat(buf, count); + + tim = ( uint32_t ) msecs() + timeout; + + if ( count ) + res.Cat ( buf, count ); } } + return res; } // writes data -bool Serial::Write(String const &data, uint32_t timeout) +bool Serial::Write ( String const &data, uint32_t timeout ) { unsigned long count = 0; int dLen = data.GetCount(); - if(!timeout) + + if ( !timeout ) { - WriteFile(fd, ~data, dLen, &count, NULL); + WriteFile ( fd, ~data, dLen, &count, NULL ); return count == dLen; } uint32_t tim = msecs() + timeout; + const char *dPos = ~data; - for(;;) + + for ( ;; ) { - WriteFile(fd, dPos, dLen, &count, NULL); - if(count == dLen) + WriteFile ( fd, dPos, dLen, &count, NULL ); + if ( count == dLen ) return true; - if(count > 0) + + if ( count > 0 ) { dPos += count; dLen -= count; continue; } - if((uint32_t)msecs() >= tim) + + if ( ( uint32_t ) msecs() >= tim ) break; } + return false; } // check if opened -bool Serial::IsOpened(void) const +bool Serial::IsOpened ( void ) const { return fd != INVALID_HANDLE_VALUE; } /////////////////////////////////////////////////////////////////////////////////////////////////////// +#ifdef USE_SETUPAPI + +// ENUMERATE PORTS USING SETUPAPI #ifndef GUID_DEVINTERFACE_COMPORT -DEFINE_GUID(GUID_DEVINTERFACE_COMPORT, 0x86E0D1E0L, 0x8089, 0x11D0, 0x9C, 0xE4, 0x08, 0x00, 0x3E, 0x30, 0x1F, 0x73); +DEFINE_GUID ( GUID_DEVINTERFACE_COMPORT, 0x86E0D1E0L, 0x8089, 0x11D0, 0x9C, 0xE4, 0x08, 0x00, 0x3E, 0x30, 0x1F, 0x73 ); #endif -typedef HKEY(__stdcall SETUPDIOPENDEVREGKEY)(HDEVINFO, PSP_DEVINFO_DATA, DWORD, DWORD, DWORD, REGSAM); -typedef BOOL (__stdcall SETUPDICLASSGUIDSFROMNAME)(LPCTSTR, LPGUID, DWORD, PDWORD); -typedef BOOL (__stdcall SETUPDIDESTROYDEVICEINFOLIST)(HDEVINFO); -typedef BOOL (__stdcall SETUPDIENUMDEVICEINFO)(HDEVINFO, DWORD, PSP_DEVINFO_DATA); -typedef HDEVINFO(__stdcall SETUPDIGETCLASSDEVS)(LPGUID, LPCTSTR, HWND, DWORD); -typedef BOOL (__stdcall SETUPDIGETDEVICEREGISTRYPROPERTY)(HDEVINFO, PSP_DEVINFO_DATA, DWORD, PDWORD, PBYTE, DWORD, PDWORD); +typedef HKEY ( __stdcall SETUPDIOPENDEVREGKEY ) ( HDEVINFO, PSP_DEVINFO_DATA, DWORD, DWORD, DWORD, REGSAM ); +typedef BOOL ( __stdcall SETUPDICLASSGUIDSFROMNAME ) ( LPCTSTR, LPGUID, DWORD, PDWORD ); +typedef BOOL ( __stdcall SETUPDIDESTROYDEVICEINFOLIST ) ( HDEVINFO ); +typedef BOOL ( __stdcall SETUPDIENUMDEVICEINFO ) ( HDEVINFO, DWORD, PSP_DEVINFO_DATA ); +typedef HDEVINFO ( __stdcall SETUPDIGETCLASSDEVS ) ( LPGUID, LPCTSTR, HWND, DWORD ); +typedef BOOL ( __stdcall SETUPDIGETDEVICEREGISTRYPROPERTY ) ( HDEVINFO, PSP_DEVINFO_DATA, DWORD, PDWORD, PBYTE, DWORD, PDWORD ); class CAutoHModule { public: - CAutoHModule() : m_hModule(NULL), m_dwError(ERROR_SUCCESS) {} + CAutoHModule() : m_hModule ( NULL ), m_dwError ( ERROR_SUCCESS ) {} - explicit CAutoHModule(HMODULE hModule) : m_hModule(hModule), m_dwError(GetLastError()) {} + explicit CAutoHModule ( HMODULE hModule ) : m_hModule ( hModule ), m_dwError ( GetLastError() ) {} - explicit CAutoHModule(HMODULE hModule, DWORD dwError) : m_hModule(hModule), m_dwError(dwError) {} + explicit CAutoHModule ( HMODULE hModule, DWORD dwError ) : m_hModule ( hModule ), m_dwError ( dwError ) {} ~CAutoHModule() { - if (m_hModule != NULL) + if ( m_hModule != NULL ) { - FreeLibrary(m_hModule); + FreeLibrary ( m_hModule ); m_hModule = NULL; } - SetLastError(m_dwError); + SetLastError ( m_dwError ); } operator HMODULE() @@ -390,25 +487,25 @@ class CAutoHModule DWORD m_dwError; }; -static HMODULE LoadLibraryFromSystem32(LPCTSTR lpFileName) +static HMODULE LoadLibraryFromSystem32 ( LPCTSTR lpFileName ) { //Get the Windows System32 directory TCHAR szFullPath[_MAX_PATH]; - szFullPath[0] = _T('\0'); + szFullPath[0] = _T ( '\0' ); - if (::GetSystemDirectory(szFullPath, _countof(szFullPath)) == 0) + if ( ::GetSystemDirectory ( szFullPath, _countof ( szFullPath ) ) == 0 ) return NULL; //Setup the full path and delegate to LoadLibrary #pragma warning(suppress: 6102) //There is a bug with the SAL annotation of GetSystemDirectory in the Windows 8.1 SDK - _tcscat_s(szFullPath, _countof(szFullPath), _T("\\")); + _tcscat_s ( szFullPath, _countof ( szFullPath ), _T ( "\\" ) ); - _tcscat_s(szFullPath, _countof(szFullPath), lpFileName); + _tcscat_s ( szFullPath, _countof ( szFullPath ), lpFileName ); - return LoadLibrary(szFullPath); + return LoadLibrary ( szFullPath ); } -static BOOL RegQueryValueString(HKEY kKey, LPCTSTR lpValueName, LPTSTR& pszValue) +static BOOL RegQueryValueString ( HKEY kKey, LPCTSTR lpValueName, LPTSTR& pszValue ) { //Initialize the output parameter pszValue = NULL; @@ -416,42 +513,42 @@ static BOOL RegQueryValueString(HKEY kKey, LPCTSTR lpValueName, LPTSTR& pszValue //First query for the size of the registry value DWORD dwType = 0; DWORD dwDataSize = 0; - LONG nError = RegQueryValueEx(kKey, lpValueName, NULL, &dwType, NULL, &dwDataSize); + LONG nError = RegQueryValueEx ( kKey, lpValueName, NULL, &dwType, NULL, &dwDataSize ); - if (nError != ERROR_SUCCESS) + if ( nError != ERROR_SUCCESS ) { - SetLastError(nError); + SetLastError ( nError ); return FALSE; } //Ensure the value is a string - if (dwType != REG_SZ) + if ( dwType != REG_SZ ) { - SetLastError(ERROR_INVALID_DATA); + SetLastError ( ERROR_INVALID_DATA ); return FALSE; } //Allocate enough bytes for the return value - DWORD dwAllocatedSize = dwDataSize + sizeof(TCHAR); //+sizeof(TCHAR) is to allow us to NULL terminate the data if it is not null terminated in the registry + DWORD dwAllocatedSize = dwDataSize + sizeof ( TCHAR ); //+sizeof(TCHAR) is to allow us to NULL terminate the data if it is not null terminated in the registry - pszValue = reinterpret_cast(LocalAlloc(LMEM_FIXED, dwAllocatedSize)); + pszValue = reinterpret_cast ( LocalAlloc ( LMEM_FIXED, dwAllocatedSize ) ); - if (pszValue == NULL) + if ( pszValue == NULL ) return FALSE; //Recall RegQueryValueEx to return the data - pszValue[0] = _T('\0'); + pszValue[0] = _T ( '\0' ); DWORD dwReturnedSize = dwAllocatedSize; - nError = RegQueryValueEx(kKey, lpValueName, NULL, &dwType, reinterpret_cast(pszValue), &dwReturnedSize); + nError = RegQueryValueEx ( kKey, lpValueName, NULL, &dwType, reinterpret_cast ( pszValue ), &dwReturnedSize ); - if (nError != ERROR_SUCCESS) + if ( nError != ERROR_SUCCESS ) { - LocalFree(pszValue); + LocalFree ( pszValue ); pszValue = NULL; - SetLastError(nError); + SetLastError ( nError ); return FALSE; } @@ -459,63 +556,63 @@ static BOOL RegQueryValueString(HKEY kKey, LPCTSTR lpValueName, LPTSTR& pszValue //has been updated in the registry with a non null terminator between the two calls to ReqQueryValueEx above. Rather than //return a potentially non-null terminated block of data, just fail the method call - if (dwReturnedSize >= dwAllocatedSize) + if ( dwReturnedSize >= dwAllocatedSize ) { - SetLastError(ERROR_INVALID_DATA); + SetLastError ( ERROR_INVALID_DATA ); return FALSE; } //NULL terminate the data if it was not returned NULL terminated because it is not stored null terminated in the registry - if (pszValue[dwReturnedSize/sizeof(TCHAR) - 1] != _T('\0')) - pszValue[dwReturnedSize/sizeof(TCHAR)] = _T('\0'); + if ( pszValue[dwReturnedSize/sizeof ( TCHAR ) - 1] != _T ( '\0' ) ) + pszValue[dwReturnedSize/sizeof ( TCHAR ) ] = _T ( '\0' ); return TRUE; } -static BOOL IsNumeric(LPCSTR pszString, BOOL bIgnoreColon) +static BOOL IsNumeric ( LPCSTR pszString, BOOL bIgnoreColon ) { - size_t nLen = strlen(pszString); + size_t nLen = strlen ( pszString ); - if (nLen == 0) + if ( nLen == 0 ) return FALSE; //What will be the return value from this function (assume the best) BOOL bNumeric = TRUE; - for (size_t i = 0; i < nLen && bNumeric; i++) + for ( size_t i = 0; i < nLen && bNumeric; i++ ) { - bNumeric = (isdigit(static_cast(pszString[i])) != 0); + bNumeric = ( isdigit ( static_cast ( pszString[i] ) ) != 0 ); - if (bIgnoreColon && (pszString[i] == ':')) + if ( bIgnoreColon && ( pszString[i] == ':' ) ) bNumeric = TRUE; } return bNumeric; } -static BOOL IsNumeric(LPCWSTR pszString, BOOL bIgnoreColon) +static BOOL IsNumeric ( LPCWSTR pszString, BOOL bIgnoreColon ) { - size_t nLen = wcslen(pszString); + size_t nLen = wcslen ( pszString ); - if (nLen == 0) + if ( nLen == 0 ) return FALSE; //What will be the return value from this function (assume the best) BOOL bNumeric = TRUE; - for (size_t i = 0; i < nLen && bNumeric; i++) + for ( size_t i = 0; i < nLen && bNumeric; i++ ) { - bNumeric = (iswdigit(pszString[i]) != 0); + bNumeric = ( iswdigit ( pszString[i] ) != 0 ); - if (bIgnoreColon && (pszString[i] == L':')) + if ( bIgnoreColon && ( pszString[i] == L':' ) ) bNumeric = TRUE; } return bNumeric; } -static BOOL QueryRegistryPortName(HKEY hDeviceKey, int& nPort) +static BOOL QueryRegistryPortName ( HKEY hDeviceKey, int& nPort ) { //What will be the return value from the method (assume the worst) BOOL bAdded = FALSE; @@ -523,48 +620,48 @@ static BOOL QueryRegistryPortName(HKEY hDeviceKey, int& nPort) //Read in the name of the port LPTSTR pszPortName = NULL; - if (RegQueryValueString(hDeviceKey, _T("PortName"), pszPortName)) + if ( RegQueryValueString ( hDeviceKey, _T ( "PortName" ), pszPortName ) ) { //If it looks like "COMX" then //add it to the array which will be returned - size_t nLen = _tcslen(pszPortName); + size_t nLen = _tcslen ( pszPortName ); - if (nLen > 3) + if ( nLen > 3 ) { - if ((_tcsnicmp(pszPortName, _T("COM"), 3) == 0) && IsNumeric((pszPortName + 3), FALSE)) + if ( ( _tcsnicmp ( pszPortName, _T ( "COM" ), 3 ) == 0 ) && IsNumeric ( ( pszPortName + 3 ), FALSE ) ) { //Work out the port number - nPort = _ttoi(pszPortName + 3); + nPort = _ttoi ( pszPortName + 3 ); bAdded = TRUE; } } - LocalFree(pszPortName); + LocalFree ( pszPortName ); } return bAdded; } // get a list of all serial ports -ArrayMap Serial::GetSerialPorts(void) +ArrayMap Serial::GetSerialPorts ( void ) { ArrayMap res; //Get the various function pointers we require from setupapi.dll - CAutoHModule setupAPI(LoadLibraryFromSystem32(_T("SETUPAPI.DLL"))); + CAutoHModule setupAPI ( LoadLibraryFromSystem32 ( _T ( "SETUPAPI.DLL" ) ) ); - if (setupAPI == NULL) + if ( setupAPI == NULL ) return res; - SETUPDIOPENDEVREGKEY* lpfnSETUPDIOPENDEVREGKEY = reinterpret_cast(GetProcAddress(setupAPI, "SetupDiOpenDevRegKey")); + SETUPDIOPENDEVREGKEY* lpfnSETUPDIOPENDEVREGKEY = reinterpret_cast ( GetProcAddress ( setupAPI, "SetupDiOpenDevRegKey" ) ); /* #if defined _UNICODE */ - SETUPDIGETCLASSDEVS* lpfnSETUPDIGETCLASSDEVS = reinterpret_cast(GetProcAddress(setupAPI, "SetupDiGetClassDevsW")); + SETUPDIGETCLASSDEVS* lpfnSETUPDIGETCLASSDEVS = reinterpret_cast ( GetProcAddress ( setupAPI, "SetupDiGetClassDevsW" ) ); - SETUPDIGETDEVICEREGISTRYPROPERTY* lpfnSETUPDIGETDEVICEREGISTRYPROPERTY = reinterpret_cast(GetProcAddress(setupAPI, "SetupDiGetDeviceRegistryPropertyW")); + SETUPDIGETDEVICEREGISTRYPROPERTY* lpfnSETUPDIGETDEVICEREGISTRYPROPERTY = reinterpret_cast ( GetProcAddress ( setupAPI, "SetupDiGetDeviceRegistryPropertyW" ) ); /* #else @@ -574,12 +671,12 @@ ArrayMap Serial::GetSerialPorts(void) #endif */ - SETUPDIDESTROYDEVICEINFOLIST* lpfnSETUPDIDESTROYDEVICEINFOLIST = reinterpret_cast(GetProcAddress(setupAPI, "SetupDiDestroyDeviceInfoList")); + SETUPDIDESTROYDEVICEINFOLIST* lpfnSETUPDIDESTROYDEVICEINFOLIST = reinterpret_cast ( GetProcAddress ( setupAPI, "SetupDiDestroyDeviceInfoList" ) ); - SETUPDIENUMDEVICEINFO* lpfnSETUPDIENUMDEVICEINFO = reinterpret_cast(GetProcAddress(setupAPI, "SetupDiEnumDeviceInfo")); + SETUPDIENUMDEVICEINFO* lpfnSETUPDIENUMDEVICEINFO = reinterpret_cast ( GetProcAddress ( setupAPI, "SetupDiEnumDeviceInfo" ) ); - if ((lpfnSETUPDIOPENDEVREGKEY == NULL) || (lpfnSETUPDIDESTROYDEVICEINFOLIST == NULL) || - (lpfnSETUPDIENUMDEVICEINFO == NULL) || (lpfnSETUPDIGETCLASSDEVS == NULL) || (lpfnSETUPDIGETDEVICEREGISTRYPROPERTY == NULL)) + if ( ( lpfnSETUPDIOPENDEVREGKEY == NULL ) || ( lpfnSETUPDIDESTROYDEVICEINFOLIST == NULL ) || + ( lpfnSETUPDIENUMDEVICEINFO == NULL ) || ( lpfnSETUPDIGETCLASSDEVS == NULL ) || ( lpfnSETUPDIGETDEVICEREGISTRYPROPERTY == NULL ) ) { //Set the error to report setupAPI.m_dwError = ERROR_CALL_NOT_IMPLEMENTED; @@ -590,9 +687,9 @@ ArrayMap Serial::GetSerialPorts(void) //Now create a "device information set" which is required to enumerate all the ports GUID guid = GUID_DEVINTERFACE_COMPORT; - HDEVINFO hDevInfoSet = lpfnSETUPDIGETCLASSDEVS(&guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); + HDEVINFO hDevInfoSet = lpfnSETUPDIGETCLASSDEVS ( &guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE ); - if (hDevInfoSet == INVALID_HANDLE_VALUE) + if ( hDevInfoSet == INVALID_HANDLE_VALUE ) { //Set the error to report setupAPI.m_dwError = GetLastError(); @@ -607,50 +704,50 @@ ArrayMap Serial::GetSerialPorts(void) SP_DEVINFO_DATA devInfo; - while (bMoreItems) + while ( bMoreItems ) { //Enumerate the current device - devInfo.cbSize = sizeof(SP_DEVINFO_DATA); - bMoreItems = lpfnSETUPDIENUMDEVICEINFO(hDevInfoSet, nIndex, &devInfo); + devInfo.cbSize = sizeof ( SP_DEVINFO_DATA ); + bMoreItems = lpfnSETUPDIENUMDEVICEINFO ( hDevInfoSet, nIndex, &devInfo ); - if (bMoreItems) + if ( bMoreItems ) { //Did we find a serial port for this device BOOL bAdded = FALSE; String port, friendly; //Get the registry key which stores the ports settings - HKEY hDeviceKey = lpfnSETUPDIOPENDEVREGKEY(hDevInfoSet, &devInfo, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE); + HKEY hDeviceKey = lpfnSETUPDIOPENDEVREGKEY ( hDevInfoSet, &devInfo, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE ); - if (hDeviceKey != INVALID_HANDLE_VALUE) + if ( hDeviceKey != INVALID_HANDLE_VALUE ) { int nPort = 0; - if (QueryRegistryPortName(hDeviceKey, nPort)) + if ( QueryRegistryPortName ( hDeviceKey, nPort ) ) { - port = Format("COM%d", nPort); + port = Format ( "COM%d", nPort ); bAdded = TRUE; } //Close the key now that we are finished with it - RegCloseKey(hDeviceKey); + RegCloseKey ( hDeviceKey ); } //If the port was a serial port, then also try to get its friendly name - if (bAdded) + if ( bAdded ) { TCHAR szFriendlyName[1024]; - szFriendlyName[0] = _T('\0'); - DWORD dwSize = sizeof(szFriendlyName); + szFriendlyName[0] = _T ( '\0' ); + DWORD dwSize = sizeof ( szFriendlyName ); DWORD dwType = 0; - if (lpfnSETUPDIGETDEVICEREGISTRYPROPERTY(hDevInfoSet, &devInfo, SPDRP_DEVICEDESC, &dwType, reinterpret_cast(szFriendlyName), dwSize, &dwSize) && (dwType == REG_SZ)) + if ( lpfnSETUPDIGETDEVICEREGISTRYPROPERTY ( hDevInfoSet, &devInfo, SPDRP_DEVICEDESC, &dwType, reinterpret_cast ( szFriendlyName ), dwSize, &dwSize ) && ( dwType == REG_SZ ) ) friendly = szFriendlyName; else friendly = ""; - res.Add(port, friendly); + res.Add ( port, friendly ); } } @@ -658,11 +755,84 @@ ArrayMap Serial::GetSerialPorts(void) } //Free up the "device information set" now that we are finished with it - lpfnSETUPDIDESTROYDEVICEINFOLIST(hDevInfoSet); + lpfnSETUPDIDESTROYDEVICEINFOLIST ( hDevInfoSet ); return res; } +#else + +// ENUMERATE PORTS BY REGISTI ENTRIES + +// get a list of all serial ports +ArrayMap Serial::GetSerialPorts ( void ) +{ + ArrayMap res; + + 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 + TCHAR *valueName = (TCHAR *)malloc(dwMaxValueNameSizeInBytes + 1); + TCHAR *valueData = (TCHAR *)malloc(dwMaxValueDataSizeInChars + 1); + + //Enumerate all the values underneath HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM + DWORD dwIndex = 0; + DWORD dwType; + DWORD dwValueNameSize = dwMaxValueNameSizeInChars; + DWORD dwDataSize = dwMaxValueDataSizeInBytes; + memset (valueName, 0, dwMaxValueNameSizeInBytes ); + memset (valueData, 0, dwMaxValueDataSizeInBytes ); + TCHAR* szValueName = valueName; + BYTE* byValue = (BYTE *)valueData; + 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 ( byValue ); + res.Add(szPort, szPort); + } + + //Prepare for the next time around + dwValueNameSize = dwMaxValueNameSizeInChars; + dwDataSize = dwMaxValueDataSizeInBytes; + memset (valueName, 0, dwMaxValueNameSizeInBytes ); + memset (valueData, 0, dwMaxValueDataSizeInBytes ); + ++dwIndex; + nEnum = RegEnumValue (hSERIALCOMM, dwIndex, szValueName, &dwValueNameSize, NULL, &dwType, byValue, &dwDataSize ); + } + + free(valueName); + free(valueData); + } + + //Close the registry key now that we are finished with it + RegCloseKey ( hSERIALCOMM ); + + if ( dwQueryInfo != ERROR_SUCCESS ) + SetLastError ( dwQueryInfo ); + } + + return res; +} +#endif + END_UPP_NAMESPACE #endif