Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

719 lines
19 KiB

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1997.
//
// File: E N U M . C P P
//
// Contents: Implementation of LAN connection enumerator object
//
// Notes:
//
// Author: danielwe 2 Oct 1997
//
//----------------------------------------------------------------------------
#include "pch.h"
#pragma hdrstop
#include "enuml.h"
#include "lan.h"
#include "lancmn.h"
#include "ncnetcfg.h"
#include "ncreg.h"
#include "ncsetup.h"
LONG g_CountLanConnectionEnumerators;
HRESULT CLanConnectionManagerEnumConnection::CreateInstance(
NETCONMGR_ENUM_FLAGS Flags,
REFIID riid,
LPVOID *ppv)
{
HRESULT hr = E_OUTOFMEMORY;
CLanConnectionManagerEnumConnection* pObj;
Assert(ppv);
*ppv = NULL;
pObj = new CComObject<CLanConnectionManagerEnumConnection>;
if (pObj)
{
// Do the standard CComCreator::CreateInstance stuff.
//
pObj->SetVoid(NULL);
pObj->InternalFinalConstructAddRef();
hr = pObj->FinalConstruct();
pObj->InternalFinalConstructRelease();
if (SUCCEEDED(hr))
{
hr = pObj->QueryInterface(riid, ppv);
}
if (FAILED(hr))
{
delete pObj;
}
}
TraceError("CLanConnectionManagerEnumConnection::CreateInstance", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CLanConnectionManagerEnumConnection::~CLanConnectionManagerEnumConnection
//
// Purpose: Called when the enumeration object is released for the last
// time.
//
// Arguments:
// (none)
//
// Returns: Nothing
//
// Author: danielwe 2 Oct 1997
//
// Notes:
//
CLanConnectionManagerEnumConnection::~CLanConnectionManagerEnumConnection()
{
SetupDiDestroyDeviceInfoListSafe(m_hdi);
InterlockedDecrement(&g_CountLanConnectionEnumerators);
}
//+---------------------------------------------------------------------------
// IEnumNetConnection
//
//+---------------------------------------------------------------------------
//
// Member: CLanConnectionManagerEnumConnection::Next
//
// Purpose: Retrieves the next celt LAN connection objects
//
// Arguments:
// celt [in] Number to retrieve
// rgelt [out] Array of INetConnection objects retrieved
// pceltFetched [out] Returns Number in array
//
// Returns: S_OK if succeeded, OLE or Win32 error otherwise
//
// Author: danielwe 2 Oct 1997
//
// Notes:
//
STDMETHODIMP CLanConnectionManagerEnumConnection::Next(ULONG celt,
INetConnection **rgelt,
ULONG *pceltFetched)
{
HRESULT hr = S_OK;
// Validate parameters.
//
if (!rgelt || (!pceltFetched && (1 != celt)))
{
hr = E_POINTER;
goto done;
}
// Initialize output parameters.
//
if (pceltFetched)
{
*pceltFetched = 0;
}
// Handle the request for zero elements. Also do nothing if the enumerator
// was created without valid parameters.
//
if (0 == celt || FIsDebugFlagSet(dfidSkipLanEnum))
{
hr = S_FALSE;
goto done;
}
hr = HrNextOrSkip(celt, rgelt, pceltFetched);
done:
TraceError("CLanConnectionManagerEnumConnection::Next",
(hr == S_FALSE) ? S_OK : hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CLanConnectionManagerEnumConnection::Skip
//
// Purpose: Skips over celt number of connections
//
// Arguments:
// celt [in] Number of connections to skip
//
// Returns: S_OK if successful, otherwise Win32 error
//
// Author: danielwe 2 Oct 1997
//
// Notes:
//
STDMETHODIMP CLanConnectionManagerEnumConnection::Skip(ULONG celt)
{
HRESULT hr = S_OK;
hr = HrNextOrSkip(celt, NULL, NULL);
TraceError("CLanConnectionManagerEnumConnection::Skip",
(hr == S_FALSE) ? S_OK : hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CLanConnectionManagerEnumConnection::Reset
//
// Purpose: Resets the enumerator to the beginning
//
// Arguments:
// (none)
//
// Returns: S_OK
//
// Author: danielwe 2 Oct 1997
//
// Notes:
//
STDMETHODIMP CLanConnectionManagerEnumConnection::Reset()
{
HRESULT hr;
m_dwIndex = 0;
// refresh so that we have a new view of what adapters are installed
// each time reset is called
//
SetupDiDestroyDeviceInfoListSafe(m_hdi);
hr = HrSetupDiGetClassDevs(&GUID_DEVCLASS_NET, NULL, NULL,
DIGCF_PRESENT, &m_hdi);
TraceError("CLanConnectionManagerEnumConnection::Reset", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Member: CLanConnectionManagerEnumConnection::Clone
//
// Purpose: Creates a new enumeration object pointing at the same location
// as this object
//
// Arguments:
// ppenum [out] New enumeration object
//
// Returns: S_OK if successful, otherwise OLE or Win32 error
//
// Author: danielwe 19 Mar 1998
//
// Notes:
//
STDMETHODIMP CLanConnectionManagerEnumConnection::Clone(IEnumNetConnection **ppenum)
{
HRESULT hr = E_OUTOFMEMORY;
// Validate parameters.
//
if (!ppenum)
{
hr = E_POINTER;
}
else
{
CLanConnectionManagerEnumConnection * pObj;
// Initialize output parameter.
//
*ppenum = NULL;
pObj = new CComObject <CLanConnectionManagerEnumConnection>;
if (pObj)
{
hr = S_OK;
CExceptionSafeComObjectLock EsLock (this);
// Copy our internal state.
//
pObj->m_dwIndex = m_dwIndex;
// Return the object with a ref count of 1 on this
// interface.
pObj->m_dwRef = 1;
*ppenum = pObj;
}
}
TraceError ("CLanConnectionManagerEnumConnection::Clone", hr);
return hr;
}
//
// Helper functions
//
//+---------------------------------------------------------------------------
//
// Member: CLanConnectionManagerEnumConnection::HrCreateLanConnectionInstance
//
// Purpose: Helper function to create a LAN connection object instance
//
// Arguments:
// deid [in] Device info data
// rgelt [in] Array of connection objects
// ulEntry [in] Index of connection object
//
// Returns: S_OK if success, Win32 or OLE error otherwise
//
// Author: danielwe 8 Jan 1998
//
// Notes:
//
HRESULT CLanConnectionManagerEnumConnection::HrCreateLanConnectionInstance(
SP_DEVINFO_DATA &deid,
INetConnection **rgelt,
ULONG ulEntry)
{
HRESULT hr;
WCHAR szPnpId[MAX_DEVICE_ID_LEN];
hr = HrSetupDiGetDeviceInstanceId(m_hdi, &deid, szPnpId,
MAX_DEVICE_ID_LEN, NULL);
if (S_OK == hr)
{
HDEVINFO hdiCopy;
SP_DEVINFO_DATA deidCopy;
hr = HrSetupDiCreateDeviceInfoList(&GUID_DEVCLASS_NET,
NULL, &hdiCopy);
if (S_OK == hr)
{
BOOL fDestroyCopy = TRUE;
hr = HrSetupDiOpenDeviceInfo(hdiCopy, szPnpId,
NULL, DIOD_INHERIT_CLASSDRVS, &deidCopy);
if (S_OK == hr)
{
fDestroyCopy = FALSE;
hr = CLanConnection::CreateInstance(hdiCopy,
deidCopy,
szPnpId,
IID_INetConnection,
reinterpret_cast<LPVOID *>
(rgelt + ulEntry));
}
// CLanConnection::CreateInstance() will hand off the hdiCopy. So
// even if that fails, we don't want to destroy hdiCopy anymore.
//
if (fDestroyCopy)
{
// If we fail to continue, free the copy we just made
//
(VOID) SetupDiDestroyDeviceInfoList(hdiCopy);
}
}
}
TraceError("CLanConnectionManagerEnumConnection::"
"HrCreateLanConnectionInstance", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: FIsHidden
//
// Purpose: Returns TRUE if the given hkey references the device instance
// of a hidden adapter (virtual or otherwise)
//
// Arguments:
// hkey [in] HKEY of device instance for adapter (i.e. {GUID}\0000)
//
// Returns: TRUE if it is hidden, FALSE if not
//
// Author: danielwe 17 Apr 1998
//
// Notes:
//
BOOL FIsHidden(HKEY hkey)
{
DWORD dwCharacter;
if (S_OK == HrRegQueryDword(hkey, L"Characteristics", &dwCharacter))
{
return !!(dwCharacter & NCF_HIDDEN);
}
return FALSE;
}
//+---------------------------------------------------------------------------
//
// Function: FIsHiddenElan
//
// Purpose: Returns TRUE if the given hkey references the device instance
// of a hidden ELAN adapter (when the physical ATM adapter is not
// available)
//
// Arguments:
// hdi [in] HDEVINFO structure for this adapter
// hkey [in] HKEY of device instance for adapter (i.e. {GUID}\0000)
//
//
// Returns: TRUE if it is hidden, FALSE if not
//
// Author: tongl 9/10/98
//
// Notes:
//
BOOL FIsHiddenElan(HDEVINFO hdi, HKEY hkey)
{
BOOL fRet = FALSE;
HRESULT hr;
PWSTR pszAtmAdapterPnpId;
hr = HrRegQuerySzWithAlloc(hkey, L"AtmAdapterPnpId", &pszAtmAdapterPnpId);
if (S_OK == hr)
{
SP_DEVINFO_DATA deid;
hr = HrSetupDiOpenDeviceInfo(hdi, pszAtmAdapterPnpId, NULL, 0, &deid);
if (S_OK == hr)
{
// Elan should be hidden if the physical adapter is not functioning
// and is hidden in the folder
fRet = !FIsFunctioning(&deid);
}
MemFree(pszAtmAdapterPnpId);
}
return fRet;
}
//+---------------------------------------------------------------------------
//
// Member: CLanConnectionManagerEnumConnection::HrNextOrSkip
//
// Purpose: Helper function to handle the ::Next or ::Skip method
// implementation
//
// Arguments:
// celt [in] Number of items to advance
// rgelt [in] Array in which to place connection objects
// pceltFetched [out] Returns number of items fetched
//
// Returns: S_OK if success, OLE or Win32 error otherwise
//
// Author: danielwe 8 Jan 1998
//
// Notes:
//
HRESULT CLanConnectionManagerEnumConnection::HrNextOrSkip(
ULONG celt,
INetConnection **rgelt,
ULONG *pceltFetched)
{
HRESULT hr = S_OK;
SP_DEVINFO_DATA deid = {0};
ULONG ulEntry = 0;
if (rgelt)
{
// Important to initialize rgelt so that in case we fail, we can
// release only what we put in rgelt.
//
ZeroMemory(rgelt, sizeof (*rgelt) * celt);
}
Assert(celt > 0);
if (!m_hdi)
{
hr = HrSetupDiGetClassDevs(&GUID_DEVCLASS_NET, NULL, NULL,
DIGCF_PRESENT, &m_hdi);
}
while (celt &&
SUCCEEDED(hr) &&
SUCCEEDED(hr = HrSetupDiEnumDeviceInfo(m_hdi,m_dwIndex, &deid)))
{
HKEY hkey;
m_dwIndex++;
hr = HrSetupDiOpenDevRegKey(m_hdi, &deid, DICS_FLAG_GLOBAL, 0,
DIREG_DRV, KEY_READ, &hkey);
if (SUCCEEDED(hr))
{
hr = HrIsLanCapableAdapterFromHkey(hkey);
if (S_OK == hr)
{
if (FIsFunctioning(&deid) && FIsValidNetCfgDevice(hkey) &&
!FIsHidden(hkey) && !FIsHiddenElan(m_hdi, hkey))
{
// On Skip, don't create an instance
//
if (rgelt)
{
hr = HrCreateLanConnectionInstance(deid, rgelt,
ulEntry);
}
ulEntry++;
celt--;
}
}
RegCloseKey(hkey);
}
else
{
// skip device entirely if error trying to open it
hr = S_OK;
}
}
if (HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr)
{
hr = S_OK;
}
if (SUCCEEDED(hr))
{
TraceTag (ttidLanCon, "Enumerated %lu LAN connections", ulEntry);
if (pceltFetched)
{
*pceltFetched = ulEntry;
}
// If celt is positive then we couldn't satisfy the request completely
hr = (celt > 0) ? S_FALSE : S_OK;
}
else
{
// For any failures, we need to release what we were about to return.
// Set any output parameters to NULL.
//
if (rgelt)
{
for (ULONG ulIndex = 0; ulIndex < ulEntry; ulIndex++)
{
ReleaseObj(rgelt[ulIndex]);
rgelt[ulIndex] = NULL;
}
}
if (pceltFetched)
{
*pceltFetched = 0;
}
}
TraceError("CLanConnectionManagerEnumConnection::HrNextOrSkip",
(hr == S_FALSE) ? S_OK : hr);
return hr;
}
//
// Private helper functions
//
extern const WCHAR c_szRegKeyInterfacesFromInstance[];
extern const WCHAR c_szRegValueUpperRange[];
extern const WCHAR c_szRegValueLowerRange[];
static const WCHAR c_chComma = L',';
extern const WCHAR c_szBiNdis4[];
extern const WCHAR c_szBiNdis5[];
extern const WCHAR c_szBiNdis5Ip[];
extern const WCHAR c_szBiNdisAtm[];
extern const WCHAR c_szBiNdis1394[];
extern const WCHAR c_szBiNdisBda[];
extern const WCHAR c_szBiLocalTalk[];
//+---------------------------------------------------------------------------
//
// Function: HrIsLanCapableAdapterFromHkey
//
// Purpose: Determines if the given HKEY describes a LAN capable adapter
//
// Arguments:
// hkey [in] HKEY under Control\Class\{GUID}\<instance> (aka driver key)
//
// Returns: S_OK if device is LAN capable, S_FALSE if not, Win32 error
// otherwise
//
// Author: danielwe 7 Jan 1998
//
// Notes:
//
HRESULT HrIsLanCapableAdapterFromHkey(HKEY hkey)
{
HRESULT hr = S_OK;
WCHAR szBuf[256];
DWORD cbBuf = sizeof(szBuf);
list<tstring *> lstr;
list<tstring *>::iterator lstrIter;
BOOL fMatch = FALSE;
HKEY hkeyInterfaces;
hr = HrRegOpenKeyEx(hkey, c_szRegKeyInterfacesFromInstance,
KEY_READ, &hkeyInterfaces);
if (SUCCEEDED(hr))
{
hr = HrRegQuerySzBuffer(hkeyInterfaces, c_szRegValueUpperRange,
szBuf, &cbBuf);
if (SUCCEEDED(hr))
{
ConvertStringToColString(szBuf, c_chComma, lstr);
for (lstrIter = lstr.begin(); lstrIter != lstr.end(); lstrIter++)
{
// See if it matches one of these
if (!lstrcmpiW((*lstrIter)->c_str(), c_szBiNdis4) ||
!lstrcmpiW((*lstrIter)->c_str(), c_szBiNdis5) ||
!lstrcmpiW((*lstrIter)->c_str(), c_szBiNdis5Ip) ||
!lstrcmpiW((*lstrIter)->c_str(), c_szBiNdisAtm) ||
!lstrcmpiW((*lstrIter)->c_str(), c_szBiNdis1394) ||
!lstrcmpiW((*lstrIter)->c_str(), c_szBiNdisBda))
{
fMatch = TRUE;
break;
}
}
DeleteColString(&lstr);
}
if (!fMatch)
{
cbBuf = sizeof(szBuf);
hr = HrRegQuerySzBuffer(hkeyInterfaces, c_szRegValueLowerRange,
szBuf, &cbBuf);
if (SUCCEEDED(hr))
{
ConvertStringToColString(szBuf, c_chComma, lstr);
for (lstrIter = lstr.begin(); lstrIter != lstr.end(); lstrIter++)
{
// See if it matches one of these
if (!lstrcmpiW((*lstrIter)->c_str(), c_szBiLocalTalk))
{
fMatch = TRUE;
break;
}
}
DeleteColString(&lstr);
}
}
RegCloseKey(hkeyInterfaces);
}
else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
{
hr = S_OK;
}
if (SUCCEEDED(hr))
{
if (fMatch)
{
hr = S_OK;
}
else
{
hr = S_FALSE;
}
}
TraceHr (ttidError, FAL, hr, S_FALSE == hr,
"HrIsLanCapableAdapterFromHkey");
return hr;
}
static const WCHAR c_szKeyFmt[] = L"%s\\%s\\%s";
extern const WCHAR c_szRegValueNetCfgInstanceId[];
extern const WCHAR c_szRegKeyComponentClasses[];
extern const WCHAR c_szRegValueInstallerAction[];
//+---------------------------------------------------------------------------
//
// Function: FIsValidNetCfgDevice
//
// Purpose: Determines if the given HKEY is that of a valid NetCfg adapter
//
// Arguments:
// hkey [in] HKEY under Control\Class\{GUID}\<instance> (aka driver key)
//
// Returns: TRUE if valid, FALSE otherwise
//
// Author: danielwe 7 Jan 1998
//
// Notes:
//
BOOL FIsValidNetCfgDevice(HKEY hkey)
{
HRESULT hr;
WCHAR szGuid[c_cchGuidWithTerm + 1];
DWORD cbBuf = sizeof(szGuid);
hr = HrRegQuerySzBuffer(hkey, c_szRegValueNetCfgInstanceId,
szGuid, &cbBuf);
return (S_OK == hr);
}
//+---------------------------------------------------------------------------
//
// Function: FIsFunctioning
//
// Purpose: Determines if the given dev node is a functioning device
//
// Arguments:
// pdeid [in] Dev info data for device
//
// Returns: TRUE if device is functioning, FALSE if not
//
// Author: danielwe 2 Sep 1998
//
// Notes: "Functioning" means the device is enabled and started with
// no problem codes, or it is disabled and stopped with no
// problem codes.
//
BOOL FIsFunctioning(SP_DEVINFO_DATA * pdeid)
{
ULONG ulStatus;
ULONG ulProblem;
CONFIGRET cfgRet;
cfgRet = CM_Get_DevNode_Status_Ex(&ulStatus, &ulProblem, pdeid->DevInst,
0, NULL);
if (CR_SUCCESS == cfgRet)
{
TraceTag(ttidLanCon, "CM_Get_DevNode_Status_Ex (enum): ulProblem "
"= 0x%08X, ulStatus = 0x%08X.",
ulProblem, ulStatus);
return FIsDeviceFunctioning(ulProblem);
}
// By default return FALSE
return FALSE;
}