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