windows-nt/Source/XPSP1/NT/shell/ext/hnw/nconn32/nicenum.cpp
2020-09-26 16:20:57 +08:00

472 lines
14 KiB
C++

//
// 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;
}