//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1997. // // File: L A N . C P P // // Contents: Implementation of LAN connection objects // // Notes: // // Author: danielwe 2 Oct 1997 // //---------------------------------------------------------------------------- #include "pch.h" #pragma hdrstop #include #include #include "lan.h" #include "lancmn.h" #include "nccom.h" #include "ncmisc.h" #include "ncnetcon.h" #include "sensapip.h" // For SensNotifyNetconEvent #include "ncstring.h" #include "ncras.h" #include "naming.h" #include "wzcsvc.h" #include "cobase.h" #include "gpnla.h" #include "ncperms.h" #include "nmpolicy.h" LONG g_CountLanConnectionObjects; extern CGroupPolicyNetworkLocationAwareness* g_pGPNLA; static const WCHAR c_szConnName[] = L"Name"; static const WCHAR c_szShowIcon[] = L"ShowIcon"; static const WCHAR c_szAutoConnect[] = L"AutoConnect"; extern const WCHAR c_szRegKeyInterfacesFromInstance[]; extern const WCHAR c_szRegValueUpperRange[]; static const WCHAR c_chComma = L','; extern const WCHAR c_szBiNdisAtm[]; static const DWORD c_cchMaxConnNameLen = 256; static const CLSID CLSID_LanConnectionUi = {0x7007ACC5,0x3202,0x11D1,{0xAA,0xD2,0x00,0x80,0x5F,0xC1,0x27,0x0E}}; typedef DWORD (APIENTRY *PFNSENSNOTIFY) (PSENS_NOTIFY_NETCON pEvent); #define NETCFG_S_NOTEXIST 0x00000002 // // CComObject overrides // //+--------------------------------------------------------------------------- // // Member: CLanConnection::CreateInstance // // Purpose: Static function to create an instance of a LAN connection // object // // Arguments: // hdi [in] Device installer device info // deid [in] Device installer device info // riid [in] Initial interface to query for // ppv [out] Returns the new interface pointer // // Returns: S_OK if success, otherwise OLE or Win32 error code // // Author: danielwe 2 Oct 1997 // // Notes: // HRESULT CLanConnection::CreateInstance(HDEVINFO hdi, const SP_DEVINFO_DATA &deid, PCWSTR pszPnpId, REFIID riid, LPVOID *ppv) { HRESULT hr = E_OUTOFMEMORY; CLanConnection * pObj; pObj = new CComObject; if (pObj) { // Initialize our members. // pObj->m_hkeyConn = NULL; pObj->m_hdi = hdi; pObj->m_deid = deid; // Do the standard CComCreator::CreateInstance stuff. // pObj->SetVoid (NULL); pObj->InternalFinalConstructAddRef(); hr = pObj->FinalConstruct(); pObj->InternalFinalConstructRelease(); if (SUCCEEDED(hr)) { hr = pObj->HrInitialize(pszPnpId); if (SUCCEEDED(hr)) { hr = pObj->GetUnknown()->QueryInterface(riid, ppv); } } if (FAILED(hr)) { delete pObj; } } else { SetupDiDestroyDeviceInfoList(hdi); } TraceError("CLanConnection::CreateInstance", hr); return hr; } BOOL VerifyUniqueConnectionName(CIntelliName *pIntelliName, PCWSTR pszPotentialName, NETCON_MEDIATYPE *pncm, NETCON_SUBMEDIATYPE *pncms) { HRESULT hr = S_OK; DWORD dwSuffix = 2; HKEY hkey; BOOL fDupFound = FALSE; hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, L"System\\CurrentControlSet\\" L"Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}", KEY_READ, &hkey); if (S_OK == hr) { FILETIME ft; DWORD dwIndex = 0; WCHAR szKeyName[MAX_PATH]; DWORD cchName = celems(szKeyName); while (!fDupFound && (S_OK == (hr = HrRegEnumKeyEx(hkey, dwIndex, szKeyName, &cchName, NULL, NULL, &ft))) ) { HKEY hkeyConn; WCHAR szSubKey[MAX_PATH]; wsprintfW(szSubKey, L"%s\\Connection", szKeyName); hr = HrRegOpenKeyEx(hkey, szSubKey, KEY_READ, &hkeyConn); if (S_OK == hr) { tstring strName; hr = HrRegQueryString(hkeyConn, c_szConnName, &strName); if (S_OK == hr) { if (!lstrcmpiW(pszPotentialName, strName.c_str())) { fDupFound = TRUE; CLSID guidName; if (SUCCEEDED(CLSIDFromString(szKeyName, &guidName))) { hr = pIntelliName->HrGetPseudoMediaTypes(guidName, pncm, pncms); if (FAILED(hr)) { *pncm = NCM_LAN; *pncms = NCSM_LAN; } } else { AssertSz(FALSE, "This doesn't look like a GUID."); } break; } else { dwIndex++; } } else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) { // If value doesn't exist, that's ok. This is a new // connection. hr = S_OK; dwIndex++; } RegCloseKey(hkeyConn); } else { if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) { // If key doesn't exist, that's ok. This is not a // connection. hr = S_OK; dwIndex++; } } cchName = celems(szKeyName); } RegCloseKey(hkey); } return fDupFound; } //+--------------------------------------------------------------------------- // // Member: CLanConnection::HrInitialize // // Purpose: Initializes the connection object for the first time. // // Arguments: // (none) // // Returns: S_OK if success, Win32 or OLE error code otherwise // // Author: danielwe 4 Nov 1997 // // Notes: This function is only called when the object is created for // the very first time and has no identity. // HRESULT CLanConnection::HrInitialize( PCWSTR pszPnpId) { HRESULT hr = S_OK; GUID guid; AssertSz(m_hdi, "We should have a component at this point!"); Assert(pszPnpId); hr = HrGetInstanceGuid(m_hdi, m_deid, &guid); if (S_OK == hr) { // Open the main connection key. If it doesn't exist, we'll create it // here. hr = HrOpenConnectionKey(&guid, NULL, KEY_READ_WRITE, OCCF_CREATE_IF_NOT_EXIST, pszPnpId, &m_hkeyConn); if (SUCCEEDED(hr)) { tstring strName; // First see if a name already exists for this connection hr = HrRegQueryString(m_hkeyConn, c_szConnName, &strName); if (FAILED(hr)) { // no name? if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) { //$ REVIEW (danielwe) 30 Oct 1997: If I can be assured // that get_Name is never called before Rename, I // don't need this function to be called. // Note: (danielwe) 31 Oct 1997: This could result in // duplicate names, but we cannot check for duplicates // without recursing infinitely // Set default connection name CIntelliName IntelliName(_Module.GetResourceInstance(), VerifyUniqueConnectionName); GUID gdDevice; LPWSTR szNewName = NULL; hr = HrGetInstanceGuid(m_hdi, m_deid, &gdDevice); Assert(SUCCEEDED(hr)); if (SUCCEEDED(hr)) { BOOL fNetworkBridge; hr = HrIsConnectionNetworkBridge(&fNetworkBridge); if (SUCCEEDED(hr) && fNetworkBridge) { hr = IntelliName.GenerateName(gdDevice, NCM_BRIDGE, 0, NULL, &szNewName); } else { hr = IntelliName.GenerateName(gdDevice, NCM_LAN, 0, NULL, &szNewName); } if (SUCCEEDED(hr)) { hr = HrRegSetSz(m_hkeyConn, c_szConnName, szNewName); CoTaskMemFree(szNewName); } } Assert(SUCCEEDED(hr)); } } } } if (SUCCEEDED(hr)) { m_fInitialized = TRUE; } TraceError("CLanConnection::HrInitialize", hr); return hr; } //+--------------------------------------------------------------------------- // // Member: CLanConnection::HrOpenRegistryKeys // // Purpose: Opens the registry keys that this LAN connection object will // use // // Arguments: // guid [in] Guid of adapter that this connection uses // // Returns: S_OK if success, Win32 error otherwise // // Author: danielwe 11 Nov 1997 // // Notes: Keys are expected to exist and this will fail if either do // not // HRESULT CLanConnection::HrOpenRegistryKeys(const GUID &guid) { HRESULT hr = S_OK; AssertSz(!m_hkeyConn, "Don't call this more than once " "on the same connection object!"); // This should only be called from HrLoad so these keys had better be // there. hr = HrOpenConnectionKey(&guid, NULL, KEY_READ_WRITE, OCCF_NONE, NULL, &m_hkeyConn); TraceError("CLanConnection::HrOpenRegistryKeys", hr); return hr; } //+--------------------------------------------------------------------------- // // Member: CLanConnection::HrLoad // // Purpose: Implements the bulk of IPersistNetConnection::Load. // // Arguments: // guid [in] GUID from which to receive identity // // Returns: S_OK if success, OLE or Win32 error code otherwise // // Author: danielwe 4 Nov 1997 // // Notes: // HRESULT CLanConnection::HrLoad(const GUID &guid) { HRESULT hr = S_OK; hr = HrLoadDevInfoFromGuid(guid); if (SUCCEEDED(hr)) { hr = HrOpenRegistryKeys(guid); if (SUCCEEDED(hr)) { // No need to call HrInitialize because this object should // already be created properly at a previous time m_fInitialized = TRUE; } } TraceError("CLanConnection::HrLoad", hr); return hr; } //+--------------------------------------------------------------------------- // // Member: CLanConnection::~CLanConnection // // Purpose: Called when the connection object is released for the last // time. // // Arguments: // (none) // // Returns: Nothing // // Author: danielwe 3 Oct 1997 // // Notes: // CLanConnection::~CLanConnection() { RegSafeCloseKey(m_hkeyConn); SetupDiDestroyDeviceInfoListSafe(m_hdi); InterlockedDecrement(&g_CountLanConnectionObjects); CoTaskMemFree(m_pHNetProperties); } // // INetConnection // //+--------------------------------------------------------------------------- // // Member: CLanConnection::Rename // // Purpose: Changes the name of the connection // // Arguments: // pszName [in] New connection name (must be valid) // // Returns: S_OK if success, OLE error code otherwise // // Author: danielwe 2 Oct 1997 // // Notes: // STDMETHODIMP CLanConnection::Rename(PCWSTR pszName) { HRESULT hr = S_OK; if (!pszName) { hr = E_POINTER; } else if (!*pszName) { hr = E_INVALIDARG; } else if (!m_fInitialized) { hr = E_UNEXPECTED; } else if (!FIsValidConnectionName(pszName)) { // Bad connection name hr = E_INVALIDARG; } else { AssertSz(m_hkeyConn, "Why don't I have a connection key?"); // Get the current name for this connection tstring strName; hr = HrRegQueryString(m_hkeyConn, c_szConnName, &strName); if (S_OK == hr) { // Only do something if names are different if (lstrcmpiW(pszName, strName.c_str())) { hr = HrPutName(pszName); } } } TraceError("CLanConnection::Rename", hr); return hr; } //+--------------------------------------------------------------------------- // // Member: CLanConnection::HrPutName // // Purpose: Sets the connection name using the given name // // Arguments: // pszName [in] New name for connection // // Returns: S_OK if success, OLE error code otherwise // // Author: danielwe 31 Oct 1997 // // Notes: Doesn't check if name is already set to this // HRESULT CLanConnection::HrPutName(PCWSTR pszName) { HRESULT hr = S_OK; GUID guid; // Get my device guid first hr = GetDeviceGuid(&guid); if (S_OK == hr) { hr = HrIsConnectionNameUnique(guid, pszName); if (S_OK == hr) { hr = HrRegSetSz(m_hkeyConn, c_szConnName, pszName); if (S_OK == hr) { LanEventNotify(CONNECTION_RENAMED, NULL, pszName, &guid); } } else if (S_FALSE == hr) { hr = HRESULT_FROM_WIN32(ERROR_DUP_NAME); } } TraceErrorOptional("CLanConnection::HrPutName", hr, (hr == HRESULT_FROM_WIN32(ERROR_DUP_NAME))); return hr; } //+--------------------------------------------------------------------------- // // Member: CLanConnection::FIsMediaPresent // // Purpose: Determines as best as can be basically whether the cable is // plugged in to the network card. // // Arguments: // (none) // // Returns: TRUE if cable is plugged in, FALSE if not // // Author: danielwe 22 Sep 1998 // // Notes: This function returns TRUE by default. // BOOL CLanConnection::FIsMediaPresent() { BOOL fRet = TRUE; GUID guid; if (S_OK == GetDeviceGuid(&guid)) { fRet = ::FIsMediaPresent(&guid); } return fRet; } //+--------------------------------------------------------------------------- // // Member: CLanConnection::GetStatus // // Purpose: Returns the status of this LAN connection // // Arguments: // pStatus [out] Returns status value // // Returns: S_OK if success, OLE or Win32 error code otherwise // // Author: danielwe 3 Oct 1997 // // Notes: // HRESULT CLanConnection::GetStatus(NETCON_STATUS *pStatus) { HRESULT hr; if (!pStatus) { hr = E_POINTER; } else if (!m_fInitialized) { hr = E_UNEXPECTED; } else { GUID guid; hr = GetDeviceGuid(&guid); if (S_OK == hr) { hr = HrGetDevInstStatus(m_deid.DevInst, &guid, pStatus); } } TraceError("CLanConnection::GetStatus", hr); return hr; } //+--------------------------------------------------------------------------- // // Member: CLanConnection::GetDeviceName // // Purpose: Returns the name of the device being used by this connection // // Arguments: // ppszwDeviceName [out] Receives device name // // Returns: S_OK if success, OLE error code otherwise // // Author: danielwe 2 Oct 1997 // // Notes: Returned string must be freed with CoTaskMemFree. // HRESULT CLanConnection::GetDeviceName(PWSTR* ppszwDeviceName) { Assert (ppszwDeviceName); Assert(m_hdi); // Initialize the output parameter. *ppszwDeviceName = NULL; PWSTR szDesc; HRESULT hr = HrSetupDiGetDeviceName(m_hdi, &m_deid, &szDesc); if (SUCCEEDED(hr)) { hr = HrCoTaskMemAllocAndDupSz (szDesc, ppszwDeviceName); delete [] reinterpret_cast(szDesc); } TraceError("CLanConnection::GetDeviceName", hr); return hr; } //+--------------------------------------------------------------------------- // // Member: CLanConnection::GetCharacteristics // // Purpose: Returns the characteristics of this connection type // // Arguments: // pdwFlags [out] Returns characteristics flags // // Returns: S_OK if successful, OLE or Win32 error code otherwise // // Author: danielwe 3 Oct 1997 // // Notes: // HRESULT CLanConnection::GetCharacteristics(NETCON_MEDIATYPE ncm, DWORD* pdwFlags) { Assert (pdwFlags); *pdwFlags = NCCF_ALL_USERS | NCCF_ALLOW_RENAME; DWORD dwValue; HRESULT hr = HrRegQueryDword(m_hkeyConn, c_szShowIcon, &dwValue); if (SUCCEEDED(hr) && dwValue) { *pdwFlags |= NCCF_SHOW_ICON; } BOOL fShared; hr = HrIsConnectionIcsPublic(&fShared); if(SUCCEEDED(hr) && TRUE == fShared) { *pdwFlags |= NCCF_SHARED; } BOOL fBridged; hr = HrIsConnectionBridged(&fBridged); if(SUCCEEDED(hr) && TRUE == fBridged) { *pdwFlags |= NCCF_BRIDGED; } BOOL bFirewalled; hr = HrIsConnectionFirewalled(&bFirewalled); if(SUCCEEDED(hr) && TRUE == bFirewalled) { *pdwFlags |= NCCF_FIREWALLED; } if(NCM_BRIDGE == ncm) { hr = HrEnsureValidNlaPolicyEngine(); if(SUCCEEDED(hr)) { BOOL fHasPermission; hr = m_pNetMachinePolicies->VerifyPermission(NCPERM_AllowNetBridge_NLA, &fHasPermission); if(SUCCEEDED(hr) && fHasPermission) { *pdwFlags |= NCCF_ALLOW_REMOVAL; } } } hr = S_OK; TraceError("CLanConnection::GetCharacteristics", hr); return hr; } //+--------------------------------------------------------------------------- // // Member: CLanConnection::GetUiObjectClassId // // Purpose: Returns the CLSID of the object that handles UI for this // connection type // // Arguments: // pclsid [out] Returns CLSID of UI object // // Returns: S_OK if success, OLE error code otherwise // // Author: danielwe 6 Oct 1997 // // Notes: // STDMETHODIMP CLanConnection::GetUiObjectClassId(CLSID *pclsid) { HRESULT hr = S_OK; // Validate parameters. // if (!pclsid) { hr = E_POINTER; } else if (!m_fInitialized) { hr = E_UNEXPECTED; } else { *pclsid = CLSID_LanConnectionUi; } TraceError("CLanConnection::GetUiObjectClassId", hr); return hr; } static const WCHAR c_szLibPath[] = L"sens.dll"; static const CHAR c_szaFunction[] = "SensNotifyNetconEvent"; //+--------------------------------------------------------------------------- // // Member: CLanConnection::HrCallSens // // Purpose: Calls the external SENS notification DLL to let it know that // we connected or disconnected. // // Arguments: // fConnect [in] TRUE if connecting, FALSE if disconnecting // // Returns: S_OK if success, Win32 error code otherwise // // Author: danielwe 16 Jun 1998 // // Notes: // HRESULT CLanConnection::HrCallSens(BOOL fConnect) { HRESULT hr = S_OK; HMODULE hmod; PFNSENSNOTIFY pfnSensNotifyNetconEvent; hr = HrLoadLibAndGetProc(c_szLibPath, c_szaFunction, &hmod, reinterpret_cast(&pfnSensNotifyNetconEvent)); if (SUCCEEDED(hr)) { DWORD dwErr; SENS_NOTIFY_NETCON snl = {0}; snl.eType = fConnect ? SENS_NOTIFY_LAN_CONNECT : SENS_NOTIFY_LAN_DISCONNECT; snl.pINetConnection = this; TraceTag(ttidLanCon, "Calling SENS to notify of %s.", fConnect ? "connect" : "disconnect"); dwErr = pfnSensNotifyNetconEvent(&snl); if (dwErr != ERROR_SUCCESS) { hr = HRESULT_FROM_WIN32(dwErr); } else { TraceTag(ttidLanCon, "Successfully notified SENS."); } FreeLibrary(hmod); } TraceError("CLanConnection::HrCallSens", hr); return hr; } //+--------------------------------------------------------------------------- // // Member: CLanConnection::HrConnectOrDisconnect // // Purpose: Connects or disconnects this LAN connection // // Arguments: // fConnect [in] TRUE if connect, FALSE if disconnect // // Returns: S_OK if success, OLE or Win32 error code otherwise // // Author: danielwe 4 Dec 1997 // // Notes: // HRESULT CLanConnection::HrConnectOrDisconnect(BOOL fConnect) { HRESULT hr = S_OK; if (!m_hdi) { hr = E_UNEXPECTED; } else if (!m_fInitialized) { hr = E_UNEXPECTED; } else { // Before attempting to connect, check media state. If it is // disconnected, return error code that indicates that network is // not present because the cable is unplugged. // if (fConnect) { if (!FIsMediaPresent()) { hr = HRESULT_FROM_WIN32(ERROR_NOT_CONNECTED); } } if (SUCCEEDED(hr)) { hr = HrSetupDiSendPropertyChangeNotification(m_hdi, &m_deid, fConnect ? DICS_ENABLE : DICS_DISABLE, DICS_FLAG_CONFIGSPECIFIC, 0); if (SUCCEEDED(hr)) { NETCON_STATUS status; hr = GetStatus(&status); if (SUCCEEDED(hr)) { if (fConnect) { int nSecondsToWait = 5; HRESULT hrRetry = S_OK; while ((nSecondsToWait) && SUCCEEDED(hrRetry) && ((NCS_CONNECTING == status) || (NCS_MEDIA_DISCONNECTED == status) || (NCS_INVALID_ADDRESS == status))) { //#300520: check a few more times since the connection is // still coming up Sleep(1000); hrRetry = GetStatus(&status); nSecondsToWait --; } if (status != NCS_CONNECTED) { // did not connect successfully hr = HRESULT_FROM_WIN32(ERROR_RETRY); TraceError("HrConnectOrDisconnect - failed to " "connect!", hr); } } else { if (status != NCS_DISCONNECTED) { // did not disconnect successfully hr = HRESULT_FROM_WIN32(ERROR_RETRY); TraceError("HrConnectOrDisconnect - failed to " "disconnect!", hr); } } } if (SUCCEEDED(hr)) { hr = HrCallSens(fConnect); if (FAILED(hr)) { TraceTag(ttidLanCon, "Failed to notify SENS on %s. " "Non-fatal 0x%08X", fConnect ? "connect" : "disconnect", hr); hr = S_OK; } } } } } TraceError("CLanConnection::HrConnectOrDisconnect", hr); return hr; } //+--------------------------------------------------------------------------- // // Member: CLanConnection::Connect // // Purpose: Activates the current LAN connection by telling its underlying // adapter to activate itself. // // Arguments: // (none) // // Returns: S_OK if success, OLE or Win32 error code otherwise // // Author: danielwe 14 Oct 1997 // // Notes: Causes auto-connect value of TRUE to be written for this // connection in the current hardware profile. // STDMETHODIMP CLanConnection::Connect() { HRESULT hr = S_OK; hr = HrConnectOrDisconnect(TRUE); TraceError("CLanConnection::Connect", hr); return hr; } //+--------------------------------------------------------------------------- // // Member: CLanConnection::Disconnect // // Purpose: Deactivates the current LAN connection by telling its // underlying adapter to deactivate itself. // // Arguments: // (none) // // Returns: S_OK if success, OLE or Win32 error code otherwise // // Author: danielwe 14 Oct 1997 // // Notes: Causes auto-connect value of FALSE to be written for this // connection in the current hardware profile. // STDMETHODIMP CLanConnection::Disconnect() { HRESULT hr = S_OK; hr = HrConnectOrDisconnect(FALSE); TraceError("CLanConnection::Disconnect", hr); return hr; } //+--------------------------------------------------------------------------- // // Member: CLanConnection::Delete // // Purpose: Delete the LAN connection. This not allowed. // // Arguments: // (none) // // Returns: E_UNEXPECTED; // // Author: shaunco 21 Jan 1998 // // Notes: This function is not expected to ever be called. // STDMETHODIMP CLanConnection::Delete() { HRESULT hr; NETCON_PROPERTIES* pProperties; hr = GetProperties(&pProperties); if(SUCCEEDED(hr)) { if(NCM_BRIDGE == pProperties->MediaType) { IHNetConnection *pHNetConnection; IHNetBridge* pNetBridge; Assert(m_fInitialized); hr = HrGetIHNetConnection(&pHNetConnection); if (SUCCEEDED(hr)) { hr = pHNetConnection->GetControlInterface( IID_IHNetBridge, reinterpret_cast(&pNetBridge) ); ReleaseObj(pHNetConnection); AssertSz(SUCCEEDED(hr), "Unable to retrieve IHNetBridge"); } if(SUCCEEDED(hr)) { hr = pNetBridge->Destroy(); ReleaseObj(pNetBridge); } } else { hr = E_FAIL; // can't delete anything but NCM_BRIDGE } FreeNetconProperties(pProperties); } return hr; } STDMETHODIMP CLanConnection::Duplicate ( PCWSTR pszDuplicateName, INetConnection** ppCon) { return E_NOTIMPL; } //+--------------------------------------------------------------------------- // // Member: CLanConnection::GetProperties // // Purpose: Get all of the properties associated with the connection. // Returning all of them at once saves us RPCs vs. returning // each one individually. // // Arguments: // ppProps [out] Returned block of properties. // // Returns: S_OK or an error. // // Author: shaunco 1 Feb 1998 // // Notes: // STDMETHODIMP CLanConnection::GetProperties ( NETCON_PROPERTIES** ppProps) { HRESULT hr = S_OK; // Validate parameters. // if (!ppProps) { hr = E_POINTER; } else if (!m_fInitialized) { hr = E_UNEXPECTED; } else { // Initialize the output parameter. // *ppProps = NULL; NETCON_PROPERTIES* pProps; NETCON_STATUS ncStatus; hr = HrCoTaskMemAlloc (sizeof (NETCON_PROPERTIES), reinterpret_cast(&pProps)); if (SUCCEEDED(hr)) { HRESULT hrT; ZeroMemory (pProps, sizeof (NETCON_PROPERTIES)); // guidId // hrT = GetDeviceGuid(&pProps->guidId); if (FAILED(hrT)) { hr = hrT; } // pszwName // tstring strName; hrT = HrRegQueryString(m_hkeyConn, c_szConnName, &strName); if (SUCCEEDED(hrT)) { hrT = HrCoTaskMemAllocAndDupSz (strName.c_str(), &pProps->pszwName); } if (FAILED(hrT)) { hr = hrT; } // pszwDeviceName // PWSTR szDesc; hrT = HrSetupDiGetDeviceName(m_hdi, &m_deid, &szDesc); if (SUCCEEDED(hrT)) { hrT = HrCoTaskMemAllocAndDupSz (szDesc, &pProps->pszwDeviceName); delete [] reinterpret_cast(szDesc); } if (FAILED(hrT)) { hr = hrT; } // Status // hrT = GetStatus (&pProps->Status); if (FAILED(hrT)) { hr = hrT; } // Get additional Status information from 802.1X // if ((NCS_CONNECTED == pProps->Status) || (NCS_INVALID_ADDRESS == pProps->Status) || (NCS_MEDIA_DISCONNECTED == pProps->Status)) { hrT = WZCQueryGUIDNCSState(&pProps->guidId, &ncStatus); if (S_OK == hrT) { pProps->Status = ncStatus; } } // Type // BOOL fNetworkBridge; hrT = HrIsConnectionNetworkBridge(&fNetworkBridge); if(SUCCEEDED(hrT) && TRUE == fNetworkBridge) { pProps->MediaType = NCM_BRIDGE; } else { pProps->MediaType = NCM_LAN; } // dwCharacter // hrT = GetCharacteristics (pProps->MediaType, &pProps->dwCharacter); if (FAILED(hrT)) { hr = hrT; } // clsidThisObject // pProps->clsidThisObject = CLSID_LanConnection; // clsidUiObject // pProps->clsidUiObject = CLSID_LanConnectionUi; // Assign the output parameter or cleanup if we had any failures. // if (SUCCEEDED(hr)) { *ppProps = pProps; } else { Assert (NULL == *ppProps); FreeNetconProperties (pProps); } } } TraceError ("CLanConnection::GetProperties", hr); return hr; } // // INetLanConnection // //+--------------------------------------------------------------------------- // // Member: CLanConnection::GetInfo // // Purpose: Returns information about this connection // // Arguments: // dwMask [in] Flags that control which fields to return. Use // LCIF_ALL to get all fields. // pLanConInfo [out] Structure that holds returned information // // Returns: S_OK if success, OLE error code otherwise // // Author: danielwe 6 Oct 1997 // // Notes: Caller should delete the szwConnName value. // STDMETHODIMP CLanConnection::GetInfo(DWORD dwMask, LANCON_INFO* pLanConInfo) { HRESULT hr = S_OK; if (!pLanConInfo) { hr = E_POINTER; } else if (!m_hdi) { hr = E_UNEXPECTED; } else if (!m_fInitialized) { hr = E_UNEXPECTED; } else { ZeroMemory(pLanConInfo, sizeof(LANCON_INFO)); if (dwMask & LCIF_COMP) { GUID guid; hr = HrGetInstanceGuid(m_hdi, m_deid, &guid); pLanConInfo->guid = guid; } if (dwMask & LCIF_NAME) { hr = GetDeviceName(&pLanConInfo->szwConnName); } if (dwMask & LCIF_ICON) { if (SUCCEEDED(hr)) { DWORD dwValue; hr = HrRegQueryDword(m_hkeyConn, c_szShowIcon, &dwValue); // OK if value not there. Default to FALSE always. // if (S_OK == hr) { pLanConInfo->fShowIcon = !!(dwValue); } else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr) { hr = NETCFG_S_NOTEXIST; } } } } // Mask S_FALSE if it slipped thru. if (S_FALSE == hr) { hr = S_OK; } TraceError("CLanConnection::GetInfo", hr); return hr; } //+--------------------------------------------------------------------------- // // Member: CLanConnection::SetInfo // // Purpose: Sets information about this connection. // // Arguments: // dwMask [in] Flags that control which fields to set // pLanConInfo [in] Structure containing information to set // // Returns: S_OK if success, OLE or Win32 error code otherwise // // Author: danielwe 6 Oct 1997 // // Notes: The guid member can only be set if the object is not yet // initialized. // The AutoConnect value is never set because it is set only upon // connect or disconnect. // If szwConnName is NULL, it is left unchanged. // STDMETHODIMP CLanConnection::SetInfo(DWORD dwMask, const LANCON_INFO* pLanConInfo) { HRESULT hr = S_OK; if (!pLanConInfo) { hr = E_POINTER; } else if (!m_fInitialized) { // If we're not yet initialized, the only thing we will allow is the // flag that gets us initialized if (dwMask != LCIF_COMP) { hr = E_UNEXPECTED; } else { hr = HrLoad(pLanConInfo->guid); if (SUCCEEDED(hr)) { WCHAR szPnpId[MAX_DEVICE_ID_LEN]; hr = HrSetupDiGetDeviceInstanceId(m_hdi, &m_deid, szPnpId, MAX_DEVICE_ID_LEN, NULL); if (S_OK == hr) { hr = HrInitialize(szPnpId); } } } } else { if (dwMask & LCIF_NAME) { AssertSz(pLanConInfo->szwConnName, "If you're going to set it, set it!"); // Set connection name hr = Rename(pLanConInfo->szwConnName); } if (dwMask & LCIF_ICON) { if (SUCCEEDED(hr)) { // Set ShowIcon value hr = HrRegSetDword(m_hkeyConn, c_szShowIcon, pLanConInfo->fShowIcon); } } if (SUCCEEDED(hr)) { LanEventNotify(CONNECTION_MODIFIED, this, NULL, NULL); } } TraceError("CLanConnection::SetInfo", hr); return hr; } //+--------------------------------------------------------------------------- // // Member: CLanConnection::GetDeviceGuid // // Purpose: Returns the instance GUID of the device being used by this // connection // // Arguments: // pguid [out] Receives GUID of device // // Returns: S_OK if success, NetCfg error code otherwise // // Author: danielwe 2 Oct 1997 // // Notes: // STDMETHODIMP CLanConnection::GetDeviceGuid(GUID *pguid) { HRESULT hr; AssertSz(m_hdi, "No component?!"); if (!pguid) { hr = E_POINTER; } else if (!m_fInitialized) { hr = E_UNEXPECTED; } else { hr = HrGetInstanceGuid(m_hdi, m_deid, pguid); } TraceError("CLanConnection::GetDeviceGuid", hr); return hr; } //+--------------------------------------------------------------------------- // IPersistNetConnection // //+--------------------------------------------------------------------------- // // Member: CLanConnection::GetClassID // // Purpose: Returns the CLSID of LAN connection objects // // Arguments: // pclsid [out] Returns CLSID to caller // // Returns: S_OK if success, OLE error otherwise // // Author: danielwe 4 Nov 1997 // // Notes: // STDMETHODIMP CLanConnection::GetClassID(CLSID* pclsid) { HRESULT hr = S_OK; // Validate parameters. // if (!pclsid) { hr = E_POINTER; } else { *pclsid = CLSID_LanConnection; } TraceError("CLanConnection::GetClassID", hr); return hr; } //+--------------------------------------------------------------------------- // // Member: CLanConnection::GetSizeMax // // Purpose: Returns the maximum size of the persistence data // // Arguments: // pcbSize [out] Returns size // // Returns: S_OK if success, OLE error otherwise // // Author: danielwe 4 Nov 1997 // // Notes: // STDMETHODIMP CLanConnection::GetSizeMax(ULONG *pcbSize) { HRESULT hr = S_OK; // Validate parameters. // if (!pcbSize) { hr = E_POINTER; } else if (!m_fInitialized) { hr = E_UNEXPECTED; } else { *pcbSize = sizeof(GUID); } TraceError("CLanConnection::GetSizeMax", hr); return hr; } //+--------------------------------------------------------------------------- // // Member: CLanConnection::Load // // Purpose: Allows the connection object to initialize (restore) itself // from previously persisted data // // Arguments: // pbBuf [in] Private data to use for restoring // cbSize [in] Size of data // // Returns: S_OK if success, OLE error otherwise // // Author: danielwe 4 Nov 1997 // // Notes: // STDMETHODIMP CLanConnection::Load(const BYTE *pbBuf, ULONG cbSize) { HRESULT hr = E_INVALIDARG; // Validate parameters. // if (!pbBuf) { hr = E_POINTER; } else if (cbSize != sizeof(GUID)) { hr = E_INVALIDARG; } // We can only accept one call on this method and only if we're not // already initialized. // else if (m_fInitialized) { hr = E_UNEXPECTED; } else { GUID guid; CopyMemory(&guid, pbBuf, sizeof(GUID)); hr = HrLoad(guid); } TraceError("CLanConnection::Load", hr); return hr; } //+--------------------------------------------------------------------------- // // Member: CLanConnection::Save // // Purpose: Provides the caller with data to use in restoring this object // at a later time. // // Arguments: // pbBuf [out] Returns data to use for restoring // cbSize [in] Size of data buffer // // Returns: S_OK if success, OLE error otherwise // // Author: danielwe 4 Nov 1997 // // Notes: // STDMETHODIMP CLanConnection::Save(BYTE *pbBuf, ULONG cbSize) { HRESULT hr; // Validate parameters. // if (!pbBuf) { hr = E_POINTER; } else if (!m_fInitialized || !m_hdi) { hr = E_UNEXPECTED; } else { GUID guid; hr = HrGetInstanceGuid(m_hdi, m_deid, &guid); if (S_OK == hr) { CopyMemory(pbBuf, &guid, cbSize); } } TraceError("CLanConnection::Save", hr); return hr; } // // Private functions // extern const WCHAR c_szRegValueNetCfgInstanceId[]; //+--------------------------------------------------------------------------- // // Function: HrGetInstanceGuid // // Purpose: Given device info, returns the NetCfg instance GUID of the // connection. // // Arguments: // hdi [in] SetupAPI data // deid [in] SetupAPI data // pguid [out] GUID of netcfg component // // Returns: S_OK if success, Win32 or SetupAPI error otherwise // // Author: danielwe 7 Jan 1998 // // Notes: // HRESULT HrGetInstanceGuid(HDEVINFO hdi, const SP_DEVINFO_DATA &deid, LPGUID pguid) { HRESULT hr; HKEY hkey; Assert(pguid); hr = HrSetupDiOpenDevRegKey(hdi, const_cast(&deid), DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_READ, &hkey); if (S_OK == hr) { WCHAR szGuid[c_cchGuidWithTerm]; DWORD cbBuf = sizeof(szGuid); hr = HrRegQuerySzBuffer(hkey, c_szRegValueNetCfgInstanceId, szGuid, &cbBuf); if (S_OK == hr) { IIDFromString(szGuid, pguid); } RegCloseKey(hkey); } TraceError("HrInstanceGuidFromDeid", hr); return hr; } static const WCHAR c_szKeyFmt[] = L"%s\\%s\\%s\\Connection"; extern const WCHAR c_szRegKeyComponentClasses[]; extern const WCHAR c_szRegValuePnpInstanceId[]; //+--------------------------------------------------------------------------- // // Function: HrLoadDevInfoFromGuid // // Purpose: Given a NetCfg instance GUID, loads the m_hdi and m_deid // members from the device installer. // // Arguments: // guid [in] GUID of connection // // Returns: S_OK if success, Win32 or SetupAPI error otherwise // // Author: danielwe 7 Jan 1998 // // Notes: // HRESULT CLanConnection::HrLoadDevInfoFromGuid(const GUID &guid) { HRESULT hr = S_OK; SP_DEVINFO_DATA deid = {0}; HKEY hkeyNetCfg; WCHAR szRegPath[c_cchMaxRegKeyLengthWithNull]; WCHAR szGuid[c_cchGuidWithTerm]; WCHAR szClassGuid[c_cchGuidWithTerm]; StringFromGUID2(GUID_DEVCLASS_NET, szClassGuid, c_cchGuidWithTerm); StringFromGUID2(guid, szGuid, c_cchGuidWithTerm); wsprintfW(szRegPath, c_szKeyFmt, c_szRegKeyComponentClasses, szClassGuid, szGuid); // Open the Control\Network\{CLASS}\{Instance GUID} key // hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, szRegPath, KEY_READ, &hkeyNetCfg); if (SUCCEEDED(hr)) { tstring strInstanceId; hr = HrRegQueryString(hkeyNetCfg, c_szRegValuePnpInstanceId, &strInstanceId); if (SUCCEEDED(hr)) { hr = HrSetupDiCreateDeviceInfoList(&GUID_DEVCLASS_NET, NULL, &m_hdi); if (SUCCEEDED(hr)) { hr = HrSetupDiOpenDeviceInfo(m_hdi, strInstanceId.c_str(), NULL, 0, &m_deid); } } RegCloseKey(hkeyNetCfg); } TraceError("HrLoadDevInfoFromGuid", hr); return hr; } //+--------------------------------------------------------------------------- // // Function: HrIsAtmAdapterFromHkey // // Purpose: Determines if the given HKEY describes an ATM physical adapter // // Arguments: // hkey [in] HKEY under Control\Class\{GUID}\ (aka driver key) // // Returns: S_OK if device is ATM physical adapter, S_FALSE if not, // Win32 error otherwise // // Author: tongl 10 Dec 1998 // // Notes: // HRESULT CLanConnection::HrIsAtmAdapterFromHkey(HKEY hkey) { HRESULT hr = S_OK; WCHAR szBuf[256]; DWORD cbBuf = sizeof(szBuf); list lstr; list::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_szBiNdisAtm)) { fMatch = TRUE; break; } } DeleteColString(&lstr); } RegCloseKey(hkeyInterfaces); } if (SUCCEEDED(hr)) { if (fMatch) { hr = S_OK; } else { hr = S_FALSE; } } TraceError("HrIsAtmAdapterFromHkey", (hr == S_FALSE) ? S_OK : hr); return hr; } //+--------------------------------------------------------------------------- // // Function: HrIsAtmElanFromHkey // // Purpose: Determines if the given HKEY describes an ATM ELAN adapter // // Arguments: // hkey [in] HKEY under Control\Class\{GUID}\ (aka driver key) // // Returns: S_OK if device is ELAN capable, S_FALSE if not, Win32 error // otherwise // // Author: tongl 21 Oct 1998 // // Notes: // HRESULT CLanConnection::HrIsAtmElanFromHkey(HKEY hkey) { HRESULT hr; // pszInfId should have enough characters to hold "ms_atmelan". // If the registry value is bigger than that, we know we don't have // a match. // WCHAR pszInfId [24]; DWORD cbInfId = sizeof(pszInfId); hr = HrRegQuerySzBuffer(hkey, L"ComponentId", pszInfId, &cbInfId); if ((S_OK != hr) || (0 != _wcsicmp(pszInfId, L"ms_atmelan"))) { hr = S_FALSE; } Assert ((S_OK == hr) || (S_FALSE == hr)); TraceError("HrIsAtmElanFromHkey", (hr == S_FALSE) ? S_OK : hr); return hr; } //+--------------------------------------------------------------------------- // // Function: HrIsConnectionBridged // // Purpose: Determines if connection is a member of a brigde // // Arguments: // pfBridged [in] A boolean for the result // // Returns: S_OK if pfBridged is valid // S_FALSE if pfBridged can't currently be determined // Error otherwise // // Author: kenwic 11 July 2000 // // Notes: // HRESULT CLanConnection::HrIsConnectionBridged(BOOL* pfBridged) { *pfBridged = FALSE; HRESULT hResult = S_OK; hResult = HrEnsureHNetPropertiesCached(); if (S_OK == hResult) { *pfBridged = m_pHNetProperties->fPartOfBridge; } return hResult; } //+--------------------------------------------------------------------------- // // Function: HrIsConnectionFirewalled // // Purpose: Determines if connection is firewalled // // Arguments: // pfFirewalled [in] A boolean for the result // // Returns: S_OK if pfFirewalled is valid // S_FALSE if pfFirewalled can't currently be determined // Error otherwise // // Author: kenwic 11 July 2000 // // Notes: // HRESULT CLanConnection::HrIsConnectionFirewalled(BOOL* pfFirewalled) { HRESULT hr = S_OK; BOOL fHasPermission = FALSE; *pfFirewalled = FALSE; // A Connection is only firewalled if the firewall is currently running, so // we return FALSE if the permission denies the firewall from running. hr = HrEnsureValidNlaPolicyEngine(); TraceHr(ttidError, FAL, hr, (S_FALSE == hr), "CRasConnectionBase::HrIsConnectionFirewalled calling HrEnsureValidNlaPolicyEngine", hr); if (SUCCEEDED(hr)) { hr = m_pNetMachinePolicies->VerifyPermission(NCPERM_PersonalFirewallConfig, &fHasPermission); if (SUCCEEDED(hr) && fHasPermission) { hr = HrEnsureHNetPropertiesCached(); if (S_OK == hr) { *pfFirewalled = m_pHNetProperties->fFirewalled; } } } return hr; } //+--------------------------------------------------------------------------- // // Function: HrIsConnectionNetworkBridge // // Purpose: Determines if a brigde // // Arguments: // pfNetworkBridge [in] A boolean for the result // // Returns: S_OK if pfNetworkBridge is valid // S_FALSE if pfNetworkBridge can't currently be determined // Error otherwise // // Author: kenwic 11 July 2000 // // Notes: // static const WCHAR c_szNetworkBridgeComponentId[] = L"ms_bridgemp"; extern const WCHAR c_szRegValueComponentId[]; HRESULT CLanConnection::HrIsConnectionNetworkBridge(BOOL* pfNetworkBridge) { *pfNetworkBridge = FALSE; HRESULT hr = S_OK; HKEY hkey; hr = HrSetupDiOpenDevRegKey(m_hdi, const_cast(&m_deid), DICS_FLAG_GLOBAL, 0, DIREG_DRV, KEY_READ, &hkey); if (S_OK == hr) { WCHAR szComponentId[60]; // if it's bigger than this, it's not the bridge, but make it big to shut up the tracing DWORD cbBuf = sizeof(szComponentId); hr = HrRegQuerySzBuffer(hkey, c_szRegValueComponentId, szComponentId, &cbBuf); if (S_OK == hr || HRESULT_FROM_WIN32(ERROR_MORE_DATA) == hr) { if(0 == lstrcmp(szComponentId, c_szNetworkBridgeComponentId)) { *pfNetworkBridge = TRUE; } hr = S_OK; } RegCloseKey(hkey); } TraceError("HrIsConnectionNetworkBridge", hr); return hr; } //+--------------------------------------------------------------------------- // // Function: HrIsConnectionIcsPublic // // Purpose: Determines if connection is shared (ICS public) // // Arguments: // pfIcsPublic [out] A boolean for the result // // Returns: S_OK if pfIcsPublic is valid // S_FALSE if pfIcsPublic can't currently be determined // Error otherwise // // Author: jonburs 31 July 2000 // // Notes: // HRESULT CLanConnection::HrIsConnectionIcsPublic(BOOL* pfIcsPublic) { Assert(NULL != pfIcsPublic); *pfIcsPublic = FALSE; HRESULT hResult = S_OK; hResult = HrEnsureHNetPropertiesCached(); if (S_OK == hResult) { *pfIcsPublic = m_pHNetProperties->fIcsPublic; } return hResult; } //+--------------------------------------------------------------------------- // // Function: HrEnsureHNetPropertiesCached // // Purpose: Makes sure home networking properties are up-to-date // // Arguments: // // Returns: S_OK if m_pHNetProperties is now valid (success) // S_FALSE if it's not currently possible to update the properties // (e.g., recursive attempt to update) // // Author: jonburs 16 August 2000 // // Notes: // HRESULT CLanConnection::HrEnsureHNetPropertiesCached(VOID) { HRESULT hr = S_OK; Assert(TRUE == m_fInitialized); if (!m_fHNetPropertiesCached || m_lHNetModifiedEra != g_lHNetModifiedEra) { // // Our cached properties are possibly out of date. Check // to see that this is not a recursive entry // if (0 == InterlockedExchange(&m_lUpdatingHNetProperties, 1)) { IHNetConnection *pHNetConn; HNET_CONN_PROPERTIES *pProps; hr = HrGetIHNetConnection(&pHNetConn); if (SUCCEEDED(hr)) { hr = pHNetConn->GetProperties(&pProps); ReleaseObj(pHNetConn); if (SUCCEEDED(hr)) { // // Store new properties, and free old. Note that CoTaskMemFree // properly handles NULL input. // pProps = reinterpret_cast( InterlockedExchangePointer( reinterpret_cast(&m_pHNetProperties), reinterpret_cast(pProps) ) ); CoTaskMemFree(pProps); // // Update our era, and note that we have valid properties // InterlockedExchange(&m_lHNetModifiedEra, g_lHNetModifiedEra); m_fHNetPropertiesCached = TRUE; hr = S_OK; } } else { // // If we don't yet have a record of this connection w/in the // home networking store, HrGetIHNetConnection will fail (as // we ask it not to create new entries). We therefore convert // failure to S_FALSE, which means we can't retrieve this info // right now. // hr = S_FALSE; } // // We're no longer updating our properties // InterlockedExchange(&m_lUpdatingHNetProperties, 0); } else { // // Update is alredy going on (possibly an earlier call on // the same thread). Return S_FALSE. // hr = S_FALSE; } } return hr; } //+--------------------------------------------------------------------------- // // Function: HrGetIHNetConnection // // Purpose: Retrieves the IHNetConnection for this connection // // Arguments: // // Returns: S_OK on success; error otherwise // // Author: jonburs 16 August 2000 // // Notes: // HRESULT CLanConnection::HrGetIHNetConnection(IHNetConnection **ppHNetConnection) { HRESULT hr; IHNetCfgMgr *pCfgMgr; GUID guid; Assert(ppHNetConnection); hr = GetDeviceGuid(&guid); if (SUCCEEDED(hr)) { hr = HrGetHNetCfgMgr(&pCfgMgr); } if (SUCCEEDED(hr)) { hr = pCfgMgr->GetIHNetConnectionForGuid( &guid, TRUE, FALSE, ppHNetConnection ); ReleaseObj(pCfgMgr); } return hr; } //+--------------------------------------------------------------------------- // // Function: ShowIcon // // Purpose: Sets the Icon state for the systray, fires an event to notify // NetShell of the Change // // Arguments: // // Returns: S_OK on success; error otherwise // // Author: ckotze 25 September 2000 // // Notes: // HRESULT CLanConnection::ShowIcon(const BOOL bShowIcon) { HRESULT hr; LANCON_INFO lcInfo; hr = GetInfo(LCIF_ICON, &lcInfo); if (SUCCEEDED(hr)) { lcInfo.fShowIcon = bShowIcon; hr = SetInfo(LCIF_ICON, &lcInfo); } return hr; } //+--------------------------------------------------------------------------- // // Function: IconStateChanged // // Purpose: Fires an event to notify NetShell of a Change occuring in an // incoming connection. // // Arguments: // // Returns: S_OK on success; error otherwise // // Author: ckotze 25 September 2000 // // Notes: // inline HRESULT CLanConnection::IconStateChanged() { return E_NOTIMPL; } //+--------------------------------------------------------------------------- // // Member: CLanConnection::GetProperties // // Purpose: Get all of the properties associated with the connection. // Returning all of them at once saves us RPCs vs. returning // each one individually. // // Arguments: // ppProps [out] Returned block of properties. // // Returns: S_OK or an error. // // Author: shaunco 1 Feb 1998 // // Notes: // HRESULT CLanConnection::GetPropertiesEx(NETCON_PROPERTIES_EX** ppConnectionPropertiesEx) { HRESULT hr = S_OK; *ppConnectionPropertiesEx = NULL; if (!m_fInitialized) { hr = E_UNEXPECTED; } else { NETCON_PROPERTIES* pProps; NETCON_PROPERTIES_EX* pPropsEx = reinterpret_cast(CoTaskMemAlloc(sizeof(NETCON_PROPERTIES_EX))); if (pPropsEx) { ZeroMemory(pPropsEx, sizeof(NETCON_PROPERTIES_EX)); hr = GetProperties(&pProps); if (SUCCEEDED(hr)) { hr = HrBuildPropertiesExFromProperties(pProps, pPropsEx, dynamic_cast(this)); if (SUCCEEDED(hr)) { if (NCM_LAN == pPropsEx->ncMediaType) { CIntelliName inName(NULL, NULL); NETCON_MEDIATYPE ncm; NETCON_SUBMEDIATYPE ncsm; hr = inName.HrGetPseudoMediaTypes(pPropsEx->guidId, &ncm, &ncsm); if (FAILED(hr)) { hr = HrGetPseudoMediaTypeFromConnection(pPropsEx->guidId, &ncsm); TraceError("HrGetPseudoMediaTypeFromConnection failed.", hr); hr = S_OK; } pPropsEx->ncSubMediaType = ncsm; if (NCSM_WIRELESS == ncsm) { LANCON_INFO LanConInfo; hr = GetInfo(LCIF_ICON, &LanConInfo); if (NETCFG_S_NOTEXIST == hr) { LanConInfo.fShowIcon = TRUE; hr = SetInfo(LCIF_ICON, &LanConInfo); TraceError("SetInfo", hr); pPropsEx->dwCharacter |= NCCF_SHOW_ICON; hr = S_OK; } } } else { pPropsEx->ncSubMediaType = NCSM_NONE; } if (SUCCEEDED(hr)) { *ppConnectionPropertiesEx = pPropsEx; } } FreeNetconProperties(pProps); } if (FAILED(hr)) { *ppConnectionPropertiesEx = NULL; HrFreeNetConProperties2(pPropsEx); } } else { hr = E_OUTOFMEMORY; } } TraceError ("CLanConnection::GetPropertiesEx", hr); return hr; } HRESULT CLanConnection::HrEnsureValidNlaPolicyEngine() { HRESULT hr = S_FALSE; // Assume we already have the object if (!m_pNetMachinePolicies) { hr = CoCreateInstance(CLSID_NetGroupPolicies, NULL, CLSCTX_INPROC, IID_INetMachinePolicies, reinterpret_cast(&m_pNetMachinePolicies)); } return hr; }