//============================================================================ // Copyright (C) Microsoft Corporation, 1996 - 1999 // // File: util.cpp // // History: // 03/10/97 Kenn M. Takara Created // // Source code for some of the utility functions in util.h //============================================================================ #include "stdafx.h" #include "mprsnap.h" #include "rtrutilp.h" #include "rtrstr.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif static const GUID GUID_DevClass_Net = {0x4D36E972,0xE325,0x11CE,{0xBF,0xC1,0x08,0x00,0x2B,0xE1,0x03,0x18}}; //---------------------------------------------------------------------------- // Function: ConnectRegistry // // Connects to the registry on the specified machine //---------------------------------------------------------------------------- TFSCORE_API(DWORD) ConnectRegistry( IN LPCTSTR pszMachine, OUT HKEY* phkeyMachine ) { // // if no machine name was specified, connect to the local machine. // otherwise, connect to the specified machine // DWORD dwErr = NO_ERROR; if (IsLocalMachine(pszMachine)) { *phkeyMachine = HKEY_LOCAL_MACHINE; } else { // // Make the connection // dwErr = ::RegConnectRegistry( (LPTSTR)pszMachine, HKEY_LOCAL_MACHINE, phkeyMachine ); } HrReportExit(HRESULT_FROM_WIN32(dwErr), TEXT("ConnectRegistry")); return dwErr; } //---------------------------------------------------------------------------- // Function: DisconnectRegistry // // Disconnects the specified config-handle. The handle is assumed to have been // acquired by calling 'ConnectRegistry'. //---------------------------------------------------------------------------- TFSCORE_API(VOID) DisconnectRegistry( IN HKEY hkeyMachine ) { if (hkeyMachine != HKEY_LOCAL_MACHINE) { ::RegCloseKey(hkeyMachine); } } /*!-------------------------------------------------------------------------- QueryRouterType - Author: KennT ---------------------------------------------------------------------------*/ TFSCORE_API(HRESULT) QueryRouterType(HKEY hkeyMachine, DWORD *pdwRouterType, RouterVersionInfo *pVersion) { Assert(pdwRouterType); Assert(hkeyMachine); DWORD dwErr = ERROR_SUCCESS; HKEY hkey = 0; DWORD dwType; DWORD dwRouterType; DWORD dwSize; RouterVersionInfo versionTemp; LPCTSTR pszRouterTypeKey = NULL; BOOL fFirstTry = TRUE; // If the version structure is not passed in, we have to do it // ourselves // ---------------------------------------------------------------- if (pVersion == NULL) { dwErr = QueryRouterVersionInfo(hkeyMachine, &versionTemp); if ( dwErr != ERROR_SUCCESS ) { goto Error; } pVersion = &versionTemp; } // Windows NT Bug : 137200 // Need to get the router type from a different place depending // on the version. // ---------------------------------------------------------------- // if (pVersion->dwRouterVersion <= 4) if (pVersion->dwOsBuildNo < RASMAN_PPP_KEY_LAST_VERSION) pszRouterTypeKey = c_szRegKeyRasProtocols; else pszRouterTypeKey = c_szRegKeyRemoteAccessParameters; // This is where we perform a retry // ---------------------------------------------------------------- Retry: // Cool, we have a machine registry entry, now get the // path down to the routertype key dwErr = RegOpenKeyEx(hkeyMachine, pszRouterTypeKey, 0, KEY_READ, &hkey); if (dwErr) goto Error; // Ok, at this point we just need to get the RouterType value from // the key dwType = REG_DWORD; dwSize = sizeof(dwRouterType); dwErr = RegQueryValueEx(hkey, c_szRouterType, NULL, &dwType, (LPBYTE) &dwRouterType, &dwSize); if (dwErr) { // Need to retry (look at the RAS/protocols key), for NT5 if ((pVersion->dwRouterVersion >= 5) && fFirstTry) { dwErr = ERROR_SUCCESS; fFirstTry = FALSE; if (hkey) RegCloseKey(hkey); hkey = 0; pszRouterTypeKey = c_szRegKeyRasProtocols; goto Retry; } goto Error; } // Is this the right type? if (dwType != REG_DWORD) { dwErr = ERROR_BADKEY; goto Error; } // We have the right type, now return that value *pdwRouterType = dwRouterType; Error: if (hkey) RegCloseKey(hkey); return HrReportExit(HRESULT_FROM_WIN32(dwErr), TEXT("QueryRouterType")); } //---------------------------------------------------------------------------- // Function: LoadLinkageList // // Loads a list of strings with the adapters to which 'pszService' is bound; // the list is built by examining the 'Linkage' and 'Disabled' subkeys // of the service under HKLM\System\CurrentControlSet\Services. //---------------------------------------------------------------------------- HRESULT LoadLinkageList( LPCTSTR pszMachine, HKEY hkeyMachine, LPCTSTR pszService, CStringList* pLinkageList) { Assert(hkeyMachine); DWORD dwErr; BYTE* pValue = NULL; HKEY hkeyLinkage = NULL, hkeyDisabled = NULL; if (!pszService || !lstrlen(pszService) || !pLinkageList) { return ERROR_INVALID_PARAMETER; } do { TCHAR* psz; CString skey; DWORD dwType, dwSize; BOOL fNt4; dwErr = IsNT4Machine(hkeyMachine, &fNt4); if (dwErr != NO_ERROR) break; //$NT5 : where is the registry key? same as NT4 skey = c_szSystemCCSServices; skey += TEXT('\\'); skey += pszService; skey += TEXT('\\'); skey += c_szLinkage; // // Open the service's 'Linkage' key // dwErr = RegOpenKeyEx( hkeyMachine, skey, 0, KEY_READ, &hkeyLinkage ); if (dwErr != NO_ERROR) { if (dwErr == ERROR_FILE_NOT_FOUND) { dwErr = NO_ERROR; } CheckRegOpenError(dwErr, (LPCTSTR) skey, _T("QueryLinkageList")); break; } // // Retrieve the size of the 'Bind' value // dwErr = RegQueryValueEx( hkeyLinkage, c_szBind, NULL, &dwType, NULL, &dwSize ); if (dwErr != NO_ERROR) { if (dwErr == ERROR_FILE_NOT_FOUND) { dwErr = NO_ERROR; } CheckRegQueryValueError(dwErr, (LPCTSTR) skey, c_szBind, _T("QueryLinkageList")); break; } // // Allocate space for the 'Bind' value // pValue = new BYTE[dwSize + sizeof(TCHAR)]; if (!pValue) { dwErr = ERROR_NOT_ENOUGH_MEMORY; break; } ::ZeroMemory(pValue, dwSize + sizeof(TCHAR)); // // Read the 'Bind' value // dwErr = RegQueryValueEx( hkeyLinkage, c_szBind, NULL, &dwType, pValue, &dwSize ); CheckRegQueryValueError(dwErr, (LPCTSTR) skey, c_szBind, _T("QueryLinkageList")); if (dwErr != NO_ERROR) { break; } // // Convert the 'Bind' multi-string to a list of strings, // leaving out the string "\Device\" which is the prefix // for all the bindings. // for (psz = (TCHAR*)pValue; *psz; psz += lstrlen(psz) + 1) { pLinkageList->AddTail(psz + 8); } delete [] pValue; pValue = NULL; // // Now open the service's 'Disabled' key. // dwErr = RegOpenKeyEx( hkeyLinkage, c_szDisabled, 0, KEY_READ, &hkeyDisabled ); if (dwErr != NO_ERROR) { if (dwErr == ERROR_FILE_NOT_FOUND) { dwErr = NO_ERROR; } CheckRegOpenError(dwErr, c_szDisabled, _T("QueryLinkageList")); break; } // // Retrieve the size of the 'Bind' value // dwErr = RegQueryValueEx( hkeyDisabled, c_szBind, NULL, &dwType, NULL, &dwSize ); if (dwErr != NO_ERROR) { if (dwErr == ERROR_FILE_NOT_FOUND) { dwErr = NO_ERROR; } CheckRegQueryValueError(dwErr, c_szDisabled, c_szBind, _T("QueryLinkageList")); break; } // // Allocate space for the 'Bind' value // pValue = new BYTE[dwSize + sizeof(TCHAR)]; if (!pValue) { dwErr = ERROR_NOT_ENOUGH_MEMORY; break; } ::ZeroMemory(pValue, dwSize + sizeof(TCHAR)); // // Read the 'Bind' value // dwErr = RegQueryValueEx( hkeyDisabled, c_szBind, NULL, &dwType, pValue, &dwSize ); CheckRegQueryValueError(dwErr, c_szDisabled, c_szBind, _T("QueryLinkageList")); if (dwErr != NO_ERROR) { break; } // // Each device in the 'Bind' mulit-string is disabled for the service, // so we will now remove such devices from the string-list built // from the 'Linkage' key. // for (psz = (TCHAR*)pValue; *psz; psz += lstrlen(psz) + 1) { POSITION pos = pLinkageList->Find(psz); if (pos) { pLinkageList->RemoveAt(pos); } } } while(FALSE); if (pValue) { delete [] pValue; } if (hkeyDisabled) { ::RegCloseKey(hkeyDisabled); } if (hkeyLinkage) { ::RegCloseKey(hkeyLinkage); } return dwErr; } /*!-------------------------------------------------------------------------- IsNT4Machine - Author: KennT, WeiJiang ---------------------------------------------------------------------------*/ TFSCORE_API(DWORD) GetNTVersion(HKEY hkeyMachine, DWORD *pdwMajor, DWORD *pdwMinor, DWORD* pdwCurrentBuildNumber) { // Look at the HKLM\Software\Microsoft\Windows NT\CurrentVersion // CurrentVersion = REG_SZ "4.0" CString skey; DWORD dwErr; TCHAR szVersion[64]; TCHAR szCurrentBuildNumber[64]; RegKey regkey; CString strVersion; CString strMajor; CString strMinor; ASSERT(pdwMajor); ASSERT(pdwMinor); ASSERT(pdwCurrentBuildNumber); skey = c_szSoftware; skey += TEXT('\\'); skey += c_szMicrosoft; skey += TEXT('\\'); skey += c_szWindowsNT; skey += TEXT('\\'); skey += c_szCurrentVersion; dwErr = regkey.Open(hkeyMachine, (LPCTSTR) skey, KEY_READ); CheckRegOpenError(dwErr, (LPCTSTR) skey, _T("GetNTVersion")); if (dwErr != ERROR_SUCCESS) return dwErr; // Ok, now try to get the current version value dwErr = regkey.QueryValue( c_szCurrentVersion, szVersion, sizeof(szVersion), FALSE); CheckRegQueryValueError(dwErr, (LPCTSTR) skey, c_szCurrentVersion, _T("GetNTVersion")); if (dwErr != ERROR_SUCCESS) goto Err; // Ok, now try to get the current build number value dwErr = regkey.QueryValue( c_szCurrentBuildNumber, szCurrentBuildNumber, sizeof(szCurrentBuildNumber), FALSE); CheckRegQueryValueError(dwErr, (LPCTSTR) skey, c_szCurrentBuildNumber, _T("GetNTVersion")); if (dwErr != ERROR_SUCCESS) goto Err; strVersion = szVersion; strMajor = strVersion.Left(strVersion.Find(_T('.'))); strMinor = strVersion.Mid(strVersion.Find(_T('.')) + 1); if(pdwMajor) *pdwMajor = _ttol(strMajor); if(pdwMinor) *pdwMinor = _ttol(strMinor); if(pdwCurrentBuildNumber) *pdwCurrentBuildNumber = _ttol(szCurrentBuildNumber); Err: return dwErr; } /*!-------------------------------------------------------------------------- IsNT4Machine - Author: KennT ---------------------------------------------------------------------------*/ TFSCORE_API(DWORD) IsNT4Machine(HKEY hkeyMachine, BOOL *pfNt4) { // Look at the HKLM\Software\Microsoft\Windows NT\CurrentVersion // CurrentVersion = REG_SZ "4.0" DWORD dwMajor = 0; DWORD dwErr = 0; dwErr = GetNTVersion(hkeyMachine, &dwMajor, NULL, NULL); if (dwErr == ERROR_SUCCESS) { *pfNt4 = (dwMajor == 4); } return dwErr; } //---------------------------------------------------------------------------- // Function: FindRmSoftwareKey // // Finds the key for a router-manager in the Software section of the registry. //---------------------------------------------------------------------------- HRESULT FindRmSoftwareKey( HKEY hkeyMachine, DWORD dwTransportId, HKEY* phkrm, LPTSTR* lplpszRm ) { Assert(phkrm); DWORD dwErr; RegKey regkey; HRESULT hr = hrOK; CString stKey; RegKeyIterator regkeyIter; HRESULT hrIter; RegKey regkeyRM; DWORD dwProtocolId; BOOL bFound = FALSE; // // open the key HKLM\Software\Microsoft\Router\RouterManagers // CString skey(c_szSoftware); skey += TEXT('\\'); skey += c_szMicrosoft; skey += TEXT('\\'); skey += c_szRouter; skey += TEXT('\\'); skey += c_szCurrentVersion; skey += TEXT('\\'); skey += c_szRouterManagers; dwErr = regkey.Open(hkeyMachine, (LPCTSTR) skey, KEY_READ); CheckRegOpenError(dwErr, (LPCTSTR) skey, _T("QueryRmSoftwareKey")); CWRg(dwErr); if (lplpszRm) *lplpszRm = NULL; *phkrm = 0; // // Enumerate its subkeys looking for one which has a ProtocolId value // equal to 'dwTransportId'; // CWRg( regkeyIter.Init(®key) ); hrIter = regkeyIter.Next(&stKey); for (; hrIter == hrOK; hrIter = regkeyIter.Next(&stKey)) { // // open the key // dwErr = regkeyRM.Open(regkey, stKey, KEY_READ); CheckRegOpenError(dwErr, stKey, _T("QueryRmSoftwareKey")); if (dwErr != ERROR_SUCCESS) { continue; } // // try to read the ProtocolId value // dwErr = regkeyRM.QueryValue(c_szProtocolId, dwProtocolId); CheckRegQueryValueError(dwErr, stKey, c_szProtocolId, _T("QueryRmSoftwareKey")); // // Break if this is the transport we're looking for, // otherwise close the key and continue // if ((dwErr == ERROR_SUCCESS) && (dwProtocolId == dwTransportId)) break; regkeyRM.Close(); } if (hrIter == hrOK) { // // The transport was found, so save its key-name and key // Assert(((HKEY)regkeyRM) != 0); if (lplpszRm) *lplpszRm = StrDup((LPCTSTR) stKey); bFound = TRUE; *phkrm = regkeyRM.Detach(); } Error: if (FHrSucceeded(hr) && !bFound) { hr = HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS); } return hr; } #ifdef _DEBUG void CheckRegOpenErrorEx(DWORD dwError, LPCTSTR pszSubKey, LPCTSTR pszDesc, LPCTSTR pszFile, int iLineNo) { if (dwError) { CString st; st.Format(_T("RegOpenEx failed(%08lx)\nfile: %s\nline: %d\nDesc: %s\nkey: %s"), dwError, pszFile, iLineNo, pszDesc, pszSubKey); if (AfxMessageBox(st, MB_OKCANCEL) == IDCANCEL) { DebugBreak(); } } } void CheckRegQueryValueErrorEx(DWORD dwError, LPCTSTR pszSubKey, LPCTSTR pszValue, LPCTSTR pszDesc, LPCTSTR pszFile, int iLineNo) { if (dwError) { CString st; st.Format(_T("RegQueryValue failed(%08lx)\nfile: %s\nline: %d\ndesc: %s\nkey: %s\nvalue: %s"), dwError, pszFile, iLineNo, pszDesc, pszSubKey, pszValue); if (AfxMessageBox(st, MB_OKCANCEL) == IDCANCEL) { DebugBreak(); } } } #endif /*!-------------------------------------------------------------------------- SetupFindInterfaceTitle - This function retrieves the title of the given interface. The argument 'LpszIf' should contain the ID of the interface, for instance "EPRO1". Author: KennT ---------------------------------------------------------------------------*/ STDMETHODIMP SetupFindInterfaceTitle(LPCTSTR pszMachine, LPCTSTR pszInterface, LPTSTR *ppszTitle) { HRESULT hr = hrOK; CString stMachine; HDEVINFO hDevInfo = INVALID_HANDLE_VALUE; HKEY hkMachine = NULL; HKEY hkDevice= NULL; CString stPnpInstanceId; RegKey rkNet; RegKey rkNetcard; RegKey rkDevice; RegKey rkConnection; CString stBuffer, stPath; CString stConnection; TCHAR szClassGuid[128]; DWORD dwAction; DWORD dwErr; SP_DEVINFO_DATA DevInfo; stMachine = pszMachine; if (IsLocalMachine(stMachine)) { hDevInfo = SetupDiCreateDeviceInfoList( (LPGUID) &GUID_DevClass_Net, NULL); } else { // Append on the "\\\\" if needed if (StrniCmp((LPCTSTR) stMachine, _T("\\\\"), 2) != 0) { stMachine = _T("\\\\"); stMachine += pszMachine; } hDevInfo = SetupDiCreateDeviceInfoListEx( (LPGUID) &GUID_DevClass_Net, NULL, (LPCTSTR) stMachine, 0); } // Get hkMachine from system // ---------------------------------------------------------------- CWRg( ConnectRegistry( (LPCTSTR) stMachine, &hkMachine) ); // Get the PnpInstanceID // ---------------------------------------------------------------- CWRg( rkNet.Open(hkMachine, c_szNetworkCardsNT5Key, KEY_READ) ); CWRg( rkNetcard.Open(rkNet, pszInterface, KEY_READ) ); dwErr = rkNetcard.QueryValue(c_szPnpInstanceID, stPnpInstanceId); if (dwErr != ERROR_SUCCESS) { RegKey rkConnection; // Need to open another key to get this info. CWRg( rkConnection.Open(rkNetcard, c_szRegKeyConnection, KEY_READ) ); CWRg( rkConnection.QueryValue(c_szPnpInstanceID, stPnpInstanceId) ); } // Get hkDevice from SetupDiOpenDevRegKey // Now get the info for this device // ---------------------------------------------------------------- ::ZeroMemory(&DevInfo, sizeof(DevInfo)); DevInfo.cbSize = sizeof(DevInfo); if (!SetupDiOpenDeviceInfo(hDevInfo, (LPCTSTR) stPnpInstanceId, NULL, 0, &DevInfo)) { CWRg( GetLastError() ); } // Now that we have the info, get the reg key // ---------------------------------------------------------------- hkDevice = SetupDiOpenDevRegKey(hDevInfo, &DevInfo, DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_READ); if ((hkDevice == NULL) || (hkDevice == INVALID_HANDLE_VALUE)) { CWRg( GetLastError() ); } // Attach so that it will get freed up // ---------------------------------------------------------------- rkDevice.Attach( hkDevice ); // Read in the netcfg instance // ---------------------------------------------------------------- CWRg( rkDevice.QueryValue(c_szRegValNetCfgInstanceId, stBuffer) ); // Generate path in registry for lookup StringFromGUID2(GUID_DevClass_Net, szClassGuid, DimensionOf(szClassGuid)); stPath.Format(_T("%s\\%s\\%s\\Connection"), c_szRegKeyComponentClasses, szClassGuid, stBuffer); // Open the key CWRg( rkConnection.Open(hkMachine, stPath, KEY_READ) ); // Read in and store the connections name CWRg( rkConnection.QueryValue(c_szRegValName, stConnection) ); *ppszTitle = StrDup((LPCTSTR) stConnection); Error: if (hDevInfo != INVALID_HANDLE_VALUE) SetupDiDestroyDeviceInfoList(hDevInfo); if (hkMachine) DisconnectRegistry( hkMachine ); return hr; } /*!-------------------------------------------------------------------------- RegFindInterfaceTitle - This function retrieves the title of the given interface. The argument 'LpszIf' should contain the ID of the interface, for instance "EPRO1". Author: KennT ---------------------------------------------------------------------------*/ STDMETHODIMP RegFindInterfaceTitle(LPCTSTR pszMachine, LPCTSTR pszInterface, LPTSTR *ppszTitle) { HRESULT hr = hrOK; DWORD dwErr; HKEY hkeyMachine = NULL; RegKey regkey; RegKeyIterator regkeyIter; HRESULT hrIter; CString stKey; RegKey regkeyCard; CString stServiceName; CString stTitle; BOOL fNT4; LPCTSTR pszKey; CNetcardRegistryHelper ncreghelp; COM_PROTECT_TRY { // // connect to the registry // CWRg( ConnectRegistry(pszMachine, &hkeyMachine) ); CWRg( IsNT4Machine(hkeyMachine, &fNT4) ); // // open HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards // pszKey = fNT4 ? c_szNetworkCardsKey : c_szNetworkCardsNT5Key; CWRg( regkey.Open(hkeyMachine, pszKey, KEY_READ) ); // // enumerate the subkeys, and for each key, // see if it's the one we want // CWRg( regkeyIter.Init(®key) ); hrIter = regkeyIter.Next(&stKey); for (; hrIter == hrOK; hrIter = regkeyIter.Next(&stKey)) { hr = hrOK; // // now open the key // regkeyCard.Close(); dwErr = regkeyCard.Open(regkey, stKey, KEY_READ); if (dwErr != ERROR_SUCCESS) continue; ncreghelp.Initialize(fNT4, regkeyCard, stKey, pszMachine); // // read the ServiceName // //$NT5: the service name is not in the same format as NT4 // this will need to be done differently. if (fNT4) { ncreghelp.ReadServiceName(); if (dwErr != ERROR_SUCCESS) continue; stServiceName = ncreghelp.GetServiceName(); } else stServiceName = pszKey; // // see if it's the one we're looking for // if (StriCmp(pszInterface, (LPCTSTR) stServiceName)) { dwErr = ERROR_INVALID_HANDLE; continue; } // // this is the one; read the title // dwErr = ncreghelp.ReadTitle(); if (dwErr != NO_ERROR) break; stTitle = (LPCTSTR) ncreghelp.GetTitle(); *ppszTitle = StrDup((LPCTSTR) stTitle); } if (dwErr) hr = HRESULT_FROM_WIN32(dwErr); COM_PROTECT_ERROR_LABEL; } COM_PROTECT_CATCH; if (hkeyMachine) DisconnectRegistry(hkeyMachine); return hr; } /*!-------------------------------------------------------------------------- RegFindRtrMgrTitle - This function retrieves the title of the given router-manager. The argument 'dwTransportId' should contain the ID of the router-manager, for instance PID_IP. Author: KennT ---------------------------------------------------------------------------*/ STDMETHODIMP RegFindRtrMgrTitle(LPCTSTR pszMachine, DWORD dwTransportId, LPTSTR *ppszTitle) { HRESULT hr = hrOK; HKEY hkey, hkeyMachine = 0; RegKey regkey; CString stValue; COM_PROTECT_TRY { // // connect to the registry // CWRg( ConnectRegistry(pszMachine, &hkeyMachine) ); // // open the key for the router-manager // under HKLM\Software\Microsoft\Router\RouterManagers // CORg( FindRmSoftwareKey(hkeyMachine, dwTransportId, &hkey, NULL) ); regkey.Attach(hkey); // // Now find the "Title" value // CWRg( regkey.QueryValue( c_szTitle, stValue ) ); // Copy the output data *ppszTitle = StrDup((LPCTSTR) stValue); COM_PROTECT_ERROR_LABEL; } COM_PROTECT_CATCH; if (hkeyMachine) DisconnectRegistry(hkeyMachine); return hr; } /*!-------------------------------------------------------------------------- QueryRouterVersionInfo - Author: KennT ---------------------------------------------------------------------------*/ TFSCORE_API(HRESULT) QueryRouterVersionInfo(HKEY hkeyMachine, RouterVersionInfo *pVerInfo) { // Look at the HKLM\Software\Microsoft\Windows NT\CurrentVersion // CurrentVersion = REG_SZ "4.0" CString skey; DWORD dwErr; TCHAR szData[64]; RegKey regkey; BOOL fNt4; DWORD dwMajorVer, dwMinorVer, dwBuildNumber; DWORD dwConfigured; DWORD dwSPVer = 0; DWORD dwOsFlags = 0; skey = c_szSoftware; skey += TEXT('\\'); skey += c_szMicrosoft; skey += TEXT('\\'); skey += c_szWindowsNT; skey += TEXT('\\'); skey += c_szCurrentVersion; Assert(hkeyMachine != NULL); Assert(hkeyMachine != INVALID_HANDLE_VALUE); dwErr = regkey.Open(hkeyMachine, (LPCTSTR) skey, KEY_READ); CheckRegOpenError(dwErr, (LPCTSTR) skey, _T("IsNT4Machine")); if (dwErr != ERROR_SUCCESS) return HRESULT_FROM_WIN32(dwErr); // Ok, now try to get the current version value dwErr = regkey.QueryValue( c_szCurrentVersion, szData, sizeof(szData), FALSE); CheckRegQueryValueError(dwErr, (LPCTSTR) skey, c_szCurrentVersion, _T("QueryRouterVersionInfo")); if (dwErr == ERROR_SUCCESS) { int nPos; int nLength; CString stData; stData = szData; nPos = stData.Find(_T('.')); nLength = stData.GetLength(); // This assumes that // CurrentVersion : REG_SZ : Major.Minor.XX.XX // ------------------------------------------------------------ // Pick out the major version from the string // ------------------------------------------------------------ dwMajorVer = _ttoi(stData.Left(nPos)); // Pick out the minor version // ------------------------------------------------------------ dwMinorVer = _ttoi(stData.Right(nLength - nPos - 1)); } // Get the build number // ---------------------------------------------------------------- dwErr = regkey.QueryValue( c_szCurrentBuildNumber, szData, sizeof(szData), FALSE); if (dwErr == ERROR_SUCCESS) dwBuildNumber = _ttoi(szData); // If this is an NT4 machine, look for the Software\Microsoft\Router // registry key. If that doesn't exist, then this is a // non-Steelhead router. // ---------------------------------------------------------------- if ((dwErr == ERROR_SUCCESS) && (dwMajorVer < 5)) { RegKey regkeyRouter; dwErr = regkeyRouter.Open(hkeyMachine, c_szRegKeyRouter, KEY_READ); if (dwErr != ERROR_SUCCESS) dwOsFlags |= RouterSnapin_RASOnly; // Ignore the return code dwErr = ERROR_SUCCESS; } // Now get the SP version // ---------------------------------------------------------------- dwErr = regkey.QueryValue( c_szCSDVersion, szData, sizeof(szData), FALSE); if (dwErr == ERROR_SUCCESS) dwSPVer = _ttoi(szData); dwErr = ERROR_SUCCESS; // this could fail, so ignore return code // Look at the router is configured flag // ---------------------------------------------------------------- regkey.Close(); if (ERROR_SUCCESS == regkey.Open(hkeyMachine,c_szRemoteAccessKey) ) { dwErr = regkey.QueryValue( c_szRtrConfigured, dwConfigured); if (dwErr != ERROR_SUCCESS) dwConfigured = FALSE; // Ignore the return code dwErr = ERROR_SUCCESS; } if (dwErr == ERROR_SUCCESS) { pVerInfo->dwRouterVersion = dwMajorVer; pVerInfo->dwOsMajorVersion = dwMajorVer; pVerInfo->dwOsMinorVersion = dwMinorVer; pVerInfo->dwOsServicePack = dwSPVer; pVerInfo->dwOsFlags |= (1 | dwOsFlags); pVerInfo->dwRouterFlags = dwConfigured ? RouterSnapin_IsConfigured : 0; // If this is NT4, then the default is the router is configured if (dwMajorVer <= 4) pVerInfo->dwRouterFlags |= RouterSnapin_IsConfigured; pVerInfo->dwOsBuildNo = dwBuildNumber; } return HRESULT_FROM_WIN32(dwErr); }