|
|
//
// NicEnum.cpp
//
// NIC enumeration code, taken from JetNet (hardware group) and repurposed
// for the Home Networking Wizard.
//
// History:
//
// 2/02/1999 KenSh Created for JetNet
// 9/28/1999 KenSh Repurposed for Home Networking Wizard
//
#include "stdafx.h"
#include "NetConn.h"
#include "nconnwrap.h"
#include "TheApp.h"
// Local functions
//
HRESULT WINAPI DetectHardwareEx(const NETADAPTER* pAdapter); BOOL WINAPI IsNetAdapterEnabled(LPCSTR pszEnumKey);
// EnumNetAdapters (public)
//
// Enumerates all network adapters installed on the system, allocates a structure
// big enough to hold the information, and returns the number of adapters found.
// Use NetConnFree() to free the allocated memory.
//
// History:
//
// 3/15/1999 KenSh Created
// 3/25/1999 KenSh Added code to get Enum key for each adapter
// 9/29/1999 KenSh Changed JetNetAlloc to NetConnAlloc
//
int WINAPI EnumNetAdapters(NETADAPTER** pprgNetAdapters) { CRegistry reg(HKEY_LOCAL_MACHINE, _T("System\\CurrentControlSet\\Services\\Class\\Net"), KEY_READ, FALSE);
DWORD cAdapters = 0; DWORD iKey;
RegQueryInfoKey(reg.m_hKey, NULL, NULL, NULL, &cAdapters, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
NETADAPTER* prgNetAdapters = (NETADAPTER*)NetConnAlloc(sizeof(NETADAPTER) * cAdapters); if (prgNetAdapters == NULL) { cAdapters = 0; goto done; }
ZeroMemory(prgNetAdapters, sizeof(NETADAPTER) * cAdapters);
for (iKey = 0; iKey < cAdapters; iKey++) { NETADAPTER* pAdapter = &prgNetAdapters[iKey]; pAdapter->bError = NICERR_NONE; pAdapter->bWarning = NICWARN_NONE; pAdapter->bNetSubType = SUBTYPE_NONE;
lstrcpy(pAdapter->szClassKey, _T("Net\\")); static const int cchNet = _countof(_T("Net\\")) - 1; DWORD cbPnpID = _countof(pAdapter->szClassKey) - cchNet; if (ERROR_SUCCESS != RegEnumKeyEx(reg.m_hKey, iKey, pAdapter->szClassKey + cchNet, &cbPnpID, NULL, NULL, NULL, NULL)) { pAdapter->bError = NICERR_BANGED; continue; }
CRegistry reg2; if (!reg2.OpenKey(reg.m_hKey, pAdapter->szClassKey + cchNet, KEY_READ)) { pAdapter->bError = NICERR_BANGED; continue; }
// VERIFIED: Win95 gold, Win98 gold
reg2.QueryStringValue(_T("DriverDesc"), pAdapter->szDisplayName, _countof(pAdapter->szDisplayName));
CRegistry reg3; if (!reg3.OpenKey(reg2.m_hKey, _T("Ndi"), KEY_READ)) { pAdapter->bError = NICERR_BANGED; continue; }
if (reg2.QueryStringValue(_T("DisableWarning"), NULL, NULL)) { pAdapter->bWarning = NICWARN_WARNING; }
// VERIFIED: Win95 gold, Win98 gold
reg2.QueryStringValue(_T("InfPath"), pAdapter->szInfFileName, _countof(pAdapter->szInfFileName));
// VERIFIED: Win95 gold, Win98 gold
reg3.QueryStringValue(_T("DeviceId"), pAdapter->szDeviceID, _countof(pAdapter->szDeviceID));
// Get the name of the driver provider, not the manufacturer
// We will replace with actual mfr name, if any, when we open the enum key
reg2.QueryStringValue(_T("ProviderName"), pAdapter->szManufacturer, _countof(pAdapter->szManufacturer));
// Check for supported interfaces to determine the network type
CRegistry reg4; TCHAR szLower[60]; szLower[0] = _T('\0'); if (reg4.OpenKey(reg3.m_hKey, _T("Interfaces"), KEY_READ)) { // REVIEW: should we check LowerRange instead?
reg4.QueryStringValue(_T("Lower"), szLower, _countof(szLower)); }
// Figure out the network adapter type (NIC, Dial-Up, etc.)
// Default is NETTYPE_LAN (which is automatically set since it's 0)
if (strstr(szLower, _T("vcomm"))) { pAdapter->bNetType = NETTYPE_DIALUP; } else if (strstr(szLower, _T("pptp"))) { pAdapter->bNetType = NETTYPE_PPTP; } else if (strstr(szLower, _T("isdn"))) { pAdapter->bNetType = NETTYPE_ISDN; } else if (strstr(szLower, _T("NabtsIp")) || strstr(szLower, _T("nabtsip"))) { pAdapter->bNetType = NETTYPE_TV; pAdapter->bNicType = NIC_VIRTUAL; } else { TCHAR szBuf[80];
// Check for IrDA adapter
// VERIFIED: Win98 OSR1
if (reg3.QueryStringValue(_T("NdiInstaller"), szBuf, _countof(szBuf))) { LPTSTR pchComma = strchr(szBuf, ','); if (pchComma != NULL) { *pchComma = _T('\0'); if (!lstrcmpi(szBuf, _T("ir_ndi.dll"))) { pAdapter->bNetType = NETTYPE_IRDA; } } } }
// Determine if card is ISA, PCI, PCMCIA, etc.
if (pAdapter->szDeviceID[0] == _T('*')) { if (strstr(szLower, _T("ethernet"))) { if (0 == memcmp(pAdapter->szDeviceID, _T("*AOL"), 4)) { pAdapter->bNicType = NIC_VIRTUAL; pAdapter->bNetSubType = SUBTYPE_AOL; } else { pAdapter->bNicType = NIC_UNKNOWN; } } else { pAdapter->bNicType = NIC_VIRTUAL; } } else if (0 == memcmp(pAdapter->szDeviceID, _T("PCMCIA\\"), _lengthof("PCMCIA\\"))) { pAdapter->bNicType = NIC_PCMCIA; } else if (0 == memcmp(pAdapter->szDeviceID, _T("PCI\\"), _lengthof("PCI\\"))) { pAdapter->bNicType = NIC_PCI; } else if (0 == memcmp(pAdapter->szDeviceID, _T("ISAPNP\\"), _lengthof("ISAPNP\\"))) { pAdapter->bNicType = NIC_ISA; } else if (0 == memcmp(pAdapter->szDeviceID, _T("USB\\"), _lengthof("USB\\"))) { pAdapter->bNicType = NIC_USB; } else if (0 == memcmp(pAdapter->szDeviceID, _T("LPTENUM\\"), _lengthof("LPTENUM\\"))) { pAdapter->bNicType = NIC_PARALLEL; } else if (0 == memcmp(pAdapter->szDeviceID, _T("MF\\"), _lengthof("MF\\"))) { pAdapter->bNicType = NIC_MF; } else if (0 == memcmp(pAdapter->szDeviceID, _T("V1394\\"), _lengthof("V1394\\"))) { pAdapter->bNicType = NIC_1394; } else if (0 == lstrcmpi(pAdapter->szDeviceID, _T("ICSHARE"))) { pAdapter->bNicType = NIC_VIRTUAL; pAdapter->bNetSubType = SUBTYPE_ICS; }
// TODO: remove this code, replace with IcsIsExternalAdapter and IcsIsInternalAdapter
// Check if this adapter is used by ICS
{ pAdapter->bIcsStatus = ICS_NONE; LPCSTR pszAdapterNumber = pAdapter->szClassKey + cchNet;
TCHAR szBuf[10]; CRegistry regIcs;
if (regIcs.OpenKey(HKEY_LOCAL_MACHINE, _T("System\\CurrentControlSet\\Services\\ICSharing\\Settings\\General"), KEY_QUERY_VALUE)) { if (regIcs.QueryStringValue(_T("ExternalAdapterReg"), szBuf, _countof(szBuf))) { if (0 == lstrcmp(szBuf, pszAdapterNumber)) { pAdapter->bIcsStatus = ICS_EXTERNAL; } }
// TODO: allow > 1 internal adapter
if (regIcs.QueryStringValue(_T("InternalAdapterReg"), szBuf, _countof(szBuf))) { if (0 == lstrcmp(szBuf, pszAdapterNumber)) { pAdapter->bIcsStatus = ICS_INTERNAL; } } } } }
// Snip out any adapters that turned out to be invalid
cAdapters = iKey; if (cAdapters == 0) { NetConnFree(prgNetAdapters); prgNetAdapters = NULL; goto done; }
//
// Walk the registry Enum key to find full enum key for each adapter
//
if (reg.OpenKey(HKEY_LOCAL_MACHINE, _T("Enum"), KEY_READ)) { TCHAR szSubKey[MAX_PATH]; DWORD cbSubKey; TCHAR szDevEnumKey[MAX_PATH]; int cchDevEnumKey1; // length of "PCI\"
int cchDevEnumKey2; // length of "PCI\VEN_10B7&DEV_9050&SUBSYS_00000000&REV_00\"
for (DWORD iEnumKey = 0; ; iEnumKey++) { cbSubKey = _countof(szSubKey); if (ERROR_SUCCESS != RegEnumKeyEx(reg.m_hKey, iEnumKey, szSubKey, &cbSubKey, NULL, NULL, NULL, NULL)) break;
// Start building DevEnumKey e.g. "PCI\"
lstrcpy(szDevEnumKey, szSubKey); cchDevEnumKey1 = (int)cbSubKey; szDevEnumKey[cchDevEnumKey1++] = _T('\\');
CRegistry reg2; if (!reg2.OpenKey(reg.m_hKey, szSubKey, KEY_READ)) // e.g. "Enum\PCI"
continue;
for (DWORD iEnumKey2 = 0; ; iEnumKey2++) { cbSubKey = _countof(szSubKey); if (ERROR_SUCCESS != RegEnumKeyEx(reg2.m_hKey, iEnumKey2, szSubKey, &cbSubKey, NULL, NULL, NULL, NULL)) break;
// Continue building DevEnumKey e.g. "PCI\VEN_10B7&DEV_9050&SUBSYS_00000000&REV_00\"
lstrcpy(szDevEnumKey + cchDevEnumKey1, szSubKey); cchDevEnumKey2 = cchDevEnumKey1 + (int)cbSubKey; szDevEnumKey[cchDevEnumKey2++] = _T('\\');
CRegistry reg3; if (!reg3.OpenKey(reg2.m_hKey, szSubKey, KEY_READ)) // e.g. "Enum\PCI\VEN_10B7&DEV_9050&SUBSYS_00000000&REV_00"
continue;
for (DWORD iEnumKey3 = 0; ; iEnumKey3++) { cbSubKey = _countof(szSubKey); if (ERROR_SUCCESS != RegEnumKeyEx(reg3.m_hKey, iEnumKey3, szSubKey, &cbSubKey, NULL, NULL, NULL, NULL)) break;
// Finish building DevEnumKey e.g. "PCI\VEN_10B7&DEV_9050&SUBSYS_00000000&REV_00\407000"
lstrcpy(szDevEnumKey + cchDevEnumKey2, szSubKey);
CRegistry regLeaf; if (!regLeaf.OpenKey(reg3.m_hKey, szSubKey, KEY_READ)) // e.g. "Enum\PCI\VEN_10B7&DEV_9050&SUBSYS_00000000&REV_00\407000"
continue;
if (!regLeaf.QueryStringValue(_T("Driver"), szSubKey, _countof(szSubKey))) continue;
//
// See if the device matches one of our NICs
//
for (DWORD iAdapter = 0; iAdapter < cAdapters; iAdapter++) { NETADAPTER* pAdapter = &prgNetAdapters[iAdapter]; if (0 != lstrcmpi(szSubKey, pAdapter->szClassKey)) continue; // doesn't match
lstrcpy(pAdapter->szEnumKey, _T("Enum\\")); lstrcpyn(pAdapter->szEnumKey + 5, szDevEnumKey, _countof(pAdapter->szEnumKey) - 5);
if (regLeaf.QueryStringValue(_T("Mfg"), szSubKey, _countof(szSubKey))) lstrcpyn(pAdapter->szManufacturer, szSubKey, _countof(pAdapter->szManufacturer));
if (regLeaf.QueryStringValue(_T("DeviceDesc"), szSubKey, _countof(szSubKey))) { lstrcpyn(pAdapter->szDisplayName, szSubKey, _countof(pAdapter->szDisplayName)); // Detect more special types of adapters here
if (pAdapter->bNetType == NETTYPE_DIALUP) { if (strstr(pAdapter->szDisplayName, _T("VPN")) || strstr(pAdapter->szDisplayName, _T("#2"))) { pAdapter->bNetSubType = SUBTYPE_VPN; } } } break; // found a match, so stop looking
} } } } }
// For all adapters that we think are present, check to see if they're
// actually present
DWORD iAdapter; for (iAdapter = 0; iAdapter < cAdapters; iAdapter++) { NETADAPTER* pAdapter = &prgNetAdapters[iAdapter]; GetNetAdapterDevNode(pAdapter);
// No enum key -> bad (JetNet bug 1234)
if (pAdapter->szEnumKey[0] == _T('\0')) { pAdapter->bError = NICERR_CORRUPT; }
// REVIEW: could still check if "broken" adapters are present
if (pAdapter->bNicType != NIC_VIRTUAL && pAdapter->bError == NICERR_NONE) { HRESULT hrDetect = DetectHardwareEx(pAdapter);
if (hrDetect == S_FALSE) { pAdapter->bError = NICERR_MISSING; } else if (hrDetect == S_OK) { // Is the adapter disabled?
if (!IsNetAdapterEnabled(pAdapter->szEnumKey)) { pAdapter->bError = NICERR_DISABLED; } else if (IsNetAdapterBroken(pAdapter)) { pAdapter->bError = NICERR_BANGED; } } } }
done: *pprgNetAdapters = prgNetAdapters; return (int)cAdapters; }
// Gets the name of the VxD from the registry, e.g. "3c19250.sys".
// Returns S_OK if the name was retrieved.
// Returns E_FAIL if the name was not retrieved, and sets pszBuf to an empty string.
HRESULT WINAPI GetNetAdapterDeviceVxDs(const NETADAPTER* pAdapter, LPSTR pszBuf, int cchBuf) { CRegistry reg(HKEY_LOCAL_MACHINE, _T("System\\CurrentControlSet\\Services\\Class"), KEY_READ, FALSE); if (reg.OpenSubKey(pAdapter->szClassKey, KEY_READ)) { if (reg.QueryStringValue(_T("DeviceVxDs"), pszBuf, cchBuf)) { return S_OK; } }
*pszBuf = '\0'; return E_FAIL; }
// Returns S_OK if the NIC is present, S_FALSE if not, or an error code if the test failed
HRESULT WINAPI DetectHardware(LPCSTR pszDeviceID) { // Just thunk down to the 16-bit version which uses DiGetClassDevs
HRESULT hr = FindClassDev16(NULL, _T("Net"), pszDeviceID); return hr; }
HRESULT WINAPI DetectHardwareEx(const NETADAPTER* pAdapter) { // Hack: always assume IRDA adapters are present, since HW detection doesn't
// work on them -ks 8/8/99
// TODO: see if this is fixed in the updated DetectHardware() -ks 9/28/1999
// if (pAdapter->bNetType == NETTYPE_IRDA)
// return S_OK;
// Hack: always assume unknown NIC types are present, since HW detection
// doesn't work on them (JetNet bug 1264 - Intel AnyPoint Parallel Port Adapter)
// TODO: see if this is fixed in the updated DetectHardware() -ks 9/28/1999
// if (pAdapter->bNicType == NIC_UNKNOWN)
// return S_OK;
// Hack: work around Millennium bug 123237, which says that hardware detection
// fails for NICs using the Dc21x4.sys driver. I never got a chance to track
// down the cause of the failure, so I'm cheating instead. -ks 1/13/2000
TCHAR szBuf[100]; GetNetAdapterDeviceVxDs(pAdapter, szBuf, _countof(szBuf)); if (0 == lstrcmpi(szBuf, _T("dc21x4.sys"))) return S_OK;
return DetectHardware(pAdapter->szDeviceID); }
BOOL OpenConfigKey(CRegistry& reg, LPCSTR pszSubKey, REGSAM dwAccess) { if (reg.OpenKey(HKEY_LOCAL_MACHINE, "System\\CurrentControlSet\\Control\\IDConfigDB", KEY_QUERY_VALUE)) { TCHAR szConfigNumber[20]; if (reg.QueryStringValue("CurrentConfig", szConfigNumber, _countof(szConfigNumber))) { TCHAR szRegKey[300]; wsprintf(szRegKey, "Config\\%s\\%s", szConfigNumber, pszSubKey); if (reg.OpenKey(HKEY_LOCAL_MACHINE, szRegKey, dwAccess)) { return TRUE; } } }
return FALSE; }
BOOL WINAPI IsNetAdapterEnabled(LPCSTR pszEnumKey) { BOOL bEnabled = TRUE; // assume enabled if reg keys are missing
CRegistry reg; if (OpenConfigKey(reg, pszEnumKey, KEY_QUERY_VALUE)) { DWORD dwDisabled; if (reg.QueryDwordValue("CSConfigFlags", &dwDisabled)) { bEnabled = (dwDisabled == 0); } }
return bEnabled; }
|