//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1998. // // File: C O N N L I S T . C P P // // Contents: Connection list class -- subclass of the stl list<> code. // // Notes: // // Author: jeffspr 19 Feb 1998 // //---------------------------------------------------------------------------- #include "pch.h" #pragma hdrstop #include "foldinc.h" // Standard shell\folder includes #include "ncnetcon.h" #include "ctrayui.h" #include "traymsgs.h" #include "ncerror.h" #include "notify.h" #include "ncperms.h" #include "cmdtable.h" #include "foldres.h" #include "winuserp.h" extern HWND g_hwndTray; const DWORD c_dwInvalidCookie = -1; DWORD CConnectionList::m_dwNotifyThread = NULL; HANDLE CConnectionList::m_hNotifyThread = NULL; // use this for debugging. We don't usually want more than one advise, so for // now I'm going to assert on this being false on advise creation // DWORD g_dwAdvisesActive = 0; CTrayIconData::CTrayIconData(const CTrayIconData& TrayIconData) throw() { m_uiTrayIconId = TrayIconData.m_uiTrayIconId; m_ncs = TrayIconData.m_ncs; m_pcpStat = TrayIconData.m_pcpStat; m_pnseStats = TrayIconData.m_pnseStats; m_pccts = TrayIconData.m_pccts; m_dwLastBalloonMessage = TrayIconData.m_dwLastBalloonMessage; m_pfnBalloonFunction = TrayIconData.m_pfnBalloonFunction; m_szCookie = SysAllocStringByteLen(reinterpret_cast(TrayIconData.m_szCookie), SysStringByteLen(TrayIconData.m_szCookie)); DWORD dwpcpStatCount = 0; DWORD dwpnseStats = 0; DWORD dwpccts = 0; if (m_pcpStat) { dwpcpStatCount = m_pcpStat->AddRef(); } if (m_pnseStats) { dwpnseStats = m_pnseStats->AddRef(); } if (m_pccts) { dwpccts = m_pccts->AddRef(); } AssertSz(dwpcpStatCount < 100, "Possible IConnectionPoint reference leak"); AssertSz(dwpnseStats < 100, "Possible INetStatisticsEngine* reference leak"); AssertSz(dwpccts < 100, "Possible CConnectionTrayStats* reference leak"); TraceTag(ttidConnectionList, "CTrayIconData::CTrayIconData(CTrayIconData&) [%d %d %d]", dwpcpStatCount, dwpnseStats, dwpccts); } CTrayIconData::CTrayIconData(IN UINT uiTrayIconId, IN NETCON_STATUS ncs, IN IConnectionPoint * pcpStat, IN INetStatisticsEngine * pnseStats, IN CConnectionTrayStats * pccts) throw() { m_uiTrayIconId = uiTrayIconId; m_ncs = ncs; m_pcpStat= pcpStat; m_pnseStats = pnseStats; m_pccts = pccts; m_szCookie = NULL; m_dwLastBalloonMessage = BALLOON_NOTHING; m_pfnBalloonFunction = NULL; DWORD dwpcpStatCount = 0; DWORD dwpnseStats = 0; DWORD dwpccts = 0; if (m_pcpStat) { dwpcpStatCount = m_pcpStat->AddRef(); } if (m_pnseStats) { dwpnseStats = m_pnseStats->AddRef(); } if (m_pccts) { dwpccts = m_pccts->AddRef(); } SetBalloonInfo(0, NULL, NULL); AssertSz(dwpcpStatCount < 100, "Possible IConnectionPoint reference leak"); AssertSz(dwpnseStats < 100, "Possible INetStatisticsEngine* reference leak"); AssertSz(dwpccts < 100, "Possible CConnectionTrayStats* reference leak"); #ifdef DBG if (FIsDebugFlagSet(dfidTraceFileFunc)) { TraceTag(ttidConnectionList, "CTrayIconData::CTrayIconData(UINT, BOOL...) [%d %d %d]", dwpcpStatCount, dwpnseStats, dwpccts); } #endif } CTrayIconData::~CTrayIconData() throw() { DWORD dwpcpStatCount = 0; DWORD dwpnseStats = 0; DWORD dwpccts = 0; if (m_pccts) { dwpccts = m_pccts->Release(); } if (m_pcpStat) { dwpcpStatCount = m_pcpStat->Release(); } if (m_pnseStats) { dwpnseStats = m_pnseStats->Release(); } if (m_szCookie) { SysFreeString(m_szCookie); } AssertSz(dwpcpStatCount < 100, "Possible IConnectionPoint reference leak"); AssertSz(dwpnseStats < 100, "Possible INetStatisticsEngine* reference leak"); AssertSz(dwpccts < 100, "Possible CConnectionTrayStats* reference leak"); #ifdef DBG if (FIsDebugFlagSet(dfidTraceFileFunc)) { TraceTag(ttidConnectionList, "CTrayIconData::~CTrayIconData [%d %d %d]", dwpcpStatCount, dwpnseStats, dwpccts); } #endif } HRESULT CTrayIconData::SetBalloonInfo(IN DWORD dwLastBalloonMessage, IN BSTR szCookie, IN FNBALLOONCLICK* pfnBalloonFunction) { m_dwLastBalloonMessage = dwLastBalloonMessage; m_pfnBalloonFunction = pfnBalloonFunction; if (szCookie) { m_szCookie = SysAllocStringByteLen(reinterpret_cast(szCookie), SysStringByteLen(szCookie));; } else { m_szCookie = NULL; } return S_OK; } //+--------------------------------------------------------------------------- // // Member: CConnectionList::Initialize // // Purpose: Initialize class members. // // Arguments: // fTieToTray [in] Use this list for tray support. This should be passed // in as FALSE when the list is being used for temporary // work. // // Returns: // // Author: jeffspr 17 Nov 1998 // // Notes: // VOID CConnectionList::Initialize(IN BOOL fTieToTray, IN BOOL fAdviseOnThis) throw() { TraceFileFunc(ttidConnectionList); m_pcclc = NULL; m_fPopulated = false; m_dwAdviseCookie = c_dwInvalidCookie; m_fTiedToTray = fTieToTray; m_fAdviseOnThis = fAdviseOnThis; #if DBG m_dwCritSecRef = 0; m_dwWriteLockRef = 0; #endif InitializeCriticalSection(&m_csMain); InitializeCriticalSection(&m_csWriteLock); } //+--------------------------------------------------------------------------- // // Member: CConnectionList::Uninitialize // // Purpose: Flush the connection list and do all cleanup // of tray icons and interfaces and such. // // Arguments: // (none) // // Returns: // // Author: jeffspr 24 Sep 1998 // // Notes: Don't make COM calls from this function if fFinalUninitialize is true. It's called from DllMain. // No need for EnsureConPointNotifyRemoved() as it's removed from // CConnectionTray::HrHandleTrayClose VOID CConnectionList::Uninitialize(IN BOOL fFinalUninitialize) throw() { TraceFileFunc(ttidConnectionList); if (fFinalUninitialize) { Assert(FImplies(m_dwNotifyThread, m_hNotifyThread)); if (m_dwNotifyThread && m_hNotifyThread) { PostThreadMessage(m_dwNotifyThread, WM_QUIT, NULL, NULL); if (WAIT_TIMEOUT == WaitForSingleObject(m_hNotifyThread, 30000)) { TraceTag(ttidError, "Timeout waiting for Notify Thread to quit"); } } } FlushConnectionList(); delete m_pcclc; m_pcclc = NULL; Assert(m_dwCritSecRef == 0); Assert(m_dwWriteLockRef == 0); DeleteCriticalSection(&m_csWriteLock); DeleteCriticalSection(&m_csMain); } HRESULT ConnListEntry::SetTrayIconData(IN const CTrayIconData& TrayIconData) { TraceFileFunc(ttidConnectionList); if (m_pTrayIconData) { delete m_pTrayIconData; m_pTrayIconData = NULL; } m_pTrayIconData = new CTrayIconData(TrayIconData); if (!m_pTrayIconData) { return E_OUTOFMEMORY; } return S_OK; } CONST_IFSTRICT CTrayIconData* ConnListEntry::GetTrayIconData() const { return m_pTrayIconData; } BOOL ConnListEntry::HasTrayIconData() const throw() { return (m_pTrayIconData != NULL); } HRESULT ConnListEntry::DeleteTrayIconData() { if (m_pTrayIconData) { delete m_pTrayIconData; m_pTrayIconData = NULL; } return S_OK; } // // Is this the main shell process? (eg the one that owns the desktop window) // // NOTE: if the desktop window has not been created, we assume that this is NOT the // main shell process and return FALSE; // STDAPI_(BOOL) IsMainShellProcess() throw() { static int s_fIsMainShellProcess = -1; if (s_fIsMainShellProcess == -1) { s_fIsMainShellProcess = FALSE; HWND hwndDesktop = GetShellWindow(); if (hwndDesktop) { DWORD dwPid; if (GetWindowThreadProcessId(hwndDesktop, &dwPid)) { if (GetCurrentProcessId() == dwPid) { s_fIsMainShellProcess = TRUE; } } } else { TraceTag(ttidError, "IsMainShellProcess: hwndDesktop does not exist, assuming we are NOT the main shell process"); return FALSE; } if (s_fIsMainShellProcess) { TraceTag(ttidNotifySink, "We are running inside the main explorer process."); } else { TraceTag(ttidNotifySink, "We are NOT running inside the main explorer process."); } } return s_fIsMainShellProcess ? TRUE : FALSE; } //+--------------------------------------------------------------------------- // // Member: CConnectionList::NotifyThread // // Purpose: Create a thread to listen for notifications from netman // // Arguments: // pConnectionList [out] The CConnectionList to be updated by netman events // // Returns: // // Author: deonb 2001 // // Notes: This thread is used in the case where we are running the Connection // folder outside of the context of explorer.exe. In that case we don't // have the explorer tray icon thread to listen to events from netman. // DWORD CConnectionList::NotifyThread(IN OUT LPVOID pConnectionList) throw() { CConnectionList *pThis = reinterpret_cast(pConnectionList); HRESULT hr = CoInitializeEx(NULL, COINIT_DISABLE_OLE1DDE | COINIT_APARTMENTTHREADED); if (SUCCEEDED(hr)) { pThis->EnsureConPointNotifyAdded(); MSG msg; while (GetMessage (&msg, 0, 0, 0)) { DispatchMessage (&msg); } // Don't call EnsureConPointNotifyRemoved() since this function is called from DllMain. // We'll have to rely on Netman to detect by itself that this thread has died. CoUninitialize(); } return SUCCEEDED(hr); } //+--------------------------------------------------------------------------- // // Member: CConnectionList::HrRetrieveConManEntries // // Purpose: Get the connection data from the enumerator, and build the // connection list and tray // // Arguments: // papidlOut [out] Retrieved entry pidl vector // // Returns: // // Author: jeffspr 24 Sep 1998 // // Notes: // HRESULT CConnectionList::HrRetrieveConManEntries( OUT PCONFOLDPIDLVEC& apidlOut) { TraceFileFunc(ttidConnectionList); HRESULT hr = S_OK; DWORD cpidl = 0; NETCFG_TRY ConnListEntry cle; BOOL fLockAcquired = FALSE; // If we haven't yet populated our list, do so. // if (!m_fPopulated) { static LONG lSyncAquired = 0; if (!InterlockedExchange(&lSyncAquired, 1)) { if (!IsMainShellProcess() && (!g_dwAdvisesActive) && (m_fAdviseOnThis) ) { m_hNotifyThread = CreateThread(NULL, STACK_SIZE_SMALL, NotifyThread, this, 0, &m_dwNotifyThread); if (!m_hNotifyThread) { TraceTag(ttidError, "Could not create sink thread"); } } } hr = HrRefreshConManEntries(); if (FAILED(hr)) { goto Exit; } m_fPopulated = true; } if (m_pcclc) { AcquireLock(); fLockAcquired = TRUE; // Get the count of the elements // cpidl = m_pcclc->size(); // Allocate an array to store the pidls that we'll retrieve // ConnListCore::const_iterator clcIter; DWORD dwLoop = 0; // Iterate through the list and build the ppidl array // for (clcIter = m_pcclc->begin(); clcIter != m_pcclc->end(); clcIter++) { Assert(!clcIter->second.empty()); cle = clcIter->second; Assert(!cle.ccfe.empty() ); if (!cle.ccfe.empty()) { // Convert the confoldentry to a pidl, so we can // retrieve the size // PCONFOLDPIDL pConFoldPidlTmp; hr = cle.ccfe.ConvertToPidl(pConFoldPidlTmp); if (FAILED(hr)) { goto Exit; } apidlOut.push_back(pConFoldPidlTmp); } else { hr = E_OUTOFMEMORY; } } // Do NOT do FlushTrayPosts here. It doesn't work, and it causes a deadlock. } Exit: if (fLockAcquired) { ReleaseLock(); } NETCFG_CATCH(hr) TraceHr(ttidError, FAL, hr, FALSE, "CConnectionList::HrRetrieveConManEntries"); return hr; } //+--------------------------------------------------------------------------- // // Member: CConnectionList::HrRemove // // Purpose: Remove a connection from the list based on a pccfe // // Arguments: // pccfe [in] Connection data (so we can find) // pfFlushPosts [out] Whether we should flush the tray icons // // Returns: // // Author: jeffspr 24 Sep 1998 // // Notes: // HRESULT CConnectionList::HrRemove(IN const CONFOLDENTRY& ccfe, OUT BOOL * pfFlushPosts) { TraceFileFunc(ttidConnectionList); HRESULT hr = S_OK; AcquireLock(); ConnListCore::iterator clcIter; if (m_pcclc) { // Iterate through the list looking for the entry with the // matching guid. // for (clcIter = m_pcclc->begin(); clcIter != m_pcclc->end(); clcIter++) { ConnListEntry& cleIter = clcIter->second; if (InlineIsEqualGUID(cleIter.ccfe.GetGuidID(), ccfe.GetGuidID())) { // Remove the entry, then break 'cause the ++ // in the for loop would explode if we didn't // hr = HrRemoveByIter(clcIter, pfFlushPosts); break; } } } ReleaseLock(); TraceHr(ttidError, FAL, hr, FALSE, "CConnectionList::HrRemove"); return hr; } //+--------------------------------------------------------------------------- // // Member: CConnectionList::HrRemoveByIter // // Purpose: Remove a list entry, using the list entry itself as // the search element. // // Arguments: // // Returns: // // Author: jeffspr 10 Apr 1998 // // Notes: // HRESULT CConnectionList::HrRemoveByIter(IN ConnListCore::iterator clcIter, OUT BOOL *pfFlushTrayPosts) { TraceFileFunc(ttidConnectionList); HRESULT hr = S_OK; ConnListEntry& cle = clcIter->second; Assert(!cle.empty()); AcquireLock(); // If there's a tray item for this connection // if (cle.HasTrayIconData() ) { // Since we're deleting the entry, remove the tray // icon associated with this entry. Ignore the return // if (m_fTiedToTray && g_pCTrayUI) { // Set the flag to inform the caller that they will need to flush this stuff. // if (pfFlushTrayPosts) { *pfFlushTrayPosts = TRUE; } CTrayIconData * pTrayIconData = new CTrayIconData(*cle.GetTrayIconData()); cle.DeleteTrayIconData(); TraceTag(ttidSystray, "HrRemoveByIter: Removing tray icon for %S", cle.ccfe.GetName()); PostMessage(g_hwndTray, MYWM_REMOVETRAYICON, reinterpret_cast(pTrayIconData), (LPARAM) 0); } } // release the branding info // // icon path CON_BRANDING_INFO * pcbi = cle.pcbi; if (pcbi) { CoTaskMemFree(pcbi->szwLargeIconPath); CoTaskMemFree(pcbi->szwTrayIconPath); CoTaskMemFree(pcbi); } // menu items CON_TRAY_MENU_DATA * pMenuData = cle.pctmd; if (pMenuData) { DWORD dwCount = pMenuData->dwCount; CON_TRAY_MENU_ENTRY * pMenuEntry = pMenuData->pctme; while (dwCount) { Assert(pMenuEntry); CoTaskMemFree(pMenuEntry->szwMenuText); CoTaskMemFree(pMenuEntry->szwMenuCmdLine); CoTaskMemFree(pMenuEntry->szwMenuParams); dwCount--; pMenuEntry++; } CoTaskMemFree(pMenuData->pctme); CoTaskMemFree(pMenuData); } // Remove the actual element from the list // Assert(m_pcclc); m_pcclc->erase(clcIter); ReleaseLock(); TraceHr(ttidError, FAL, hr, FALSE, "CConnectionList::HrRemoveByIter"); return hr; } //+--------------------------------------------------------------------------- // // Member: CConnectionList::FlushTrayIcons // // Purpose: Remove all of our icons from the tray, since we're about // to either flush the connection list or turn off the tray. // // Arguments: // (none) // // Returns: // // Author: jeffspr 24 Sep 1998 // // Notes: // VOID CConnectionList::FlushTrayIcons() throw() { TraceFileFunc(ttidConnectionList); AssertSz(m_fTiedToTray, "This connection list not allowed to modify tray"); if (!g_pCTrayUI || !m_fTiedToTray) { return; } AcquireLock(); ConnListCore::iterator clcIter; ConnListCore::const_iterator clcNext; BOOL fFlushPosts = FALSE; if (m_pcclc) { // Iterate through the list and build the ppidl array // for (clcIter = m_pcclc->begin(); clcIter != m_pcclc->end(); clcIter = clcNext) { Assert(!clcIter->second.empty()); clcNext = clcIter; clcNext++; ConnListEntry& cle = clcIter->second; // using non-const reference for renaming only (calling cle.DeleteTrayIconData). if ( cle.HasTrayIconData() ) { fFlushPosts = TRUE; CTrayIconData *pTrayIconData = new CTrayIconData(*cle.GetTrayIconData()); cle.DeleteTrayIconData(); TraceTag(ttidSystray, "FlushTrayIcons: Removing tray icon for %S", cle.ccfe.GetName()); PostMessage(g_hwndTray, MYWM_REMOVETRAYICON, (WPARAM) pTrayIconData , (LPARAM) 0); } } } g_pCTrayUI->ResetIconCount(); ReleaseLock(); if (fFlushPosts) { FlushTrayPosts(g_hwndTray); } } //+--------------------------------------------------------------------------- // // Member: CConnectionList::EnsureIconsPresent // // Purpose: Given an existing list, ensure that all of the tray // icons that should be shown are being shown. This needs to // be called when the tray was turned on AFTER enumeration. // // Arguments: // (none) // // Returns: // // Author: jeffspr 24 Sep 1998 // // Notes: // VOID CConnectionList::EnsureIconsPresent() throw() { TraceFileFunc(ttidConnectionList); Assert(m_fTiedToTray); if (!g_pCTrayUI || !m_fTiedToTray) { return; } AcquireLock(); ConnListCore::iterator clcIter; ConnListCore::const_iterator clcNext; if (m_pcclc) { // Iterate through the list and build the ppidl array // for (clcIter = m_pcclc->begin(); clcIter != m_pcclc->end(); clcIter = clcNext) { Assert(!clcIter->second.empty()); clcNext = clcIter; clcNext++; const ConnListEntry& cle = clcIter->second; if ((!cle.HasTrayIconData() ) && cle.ccfe.FShouldHaveTrayIconDisplayed()) { CONFOLDENTRY pccfeDup; HRESULT hr = pccfeDup.HrDupFolderEntry(cle.ccfe); if (SUCCEEDED(hr)) { TraceTag(ttidSystray, "EnsureIconsPresent: Adding tray icon for %S", cle.ccfe.GetName()); PostMessage(g_hwndTray, MYWM_ADDTRAYICON, (WPARAM) pccfeDup.TearOffItemIdList(), (LPARAM) 0); } } } } ReleaseLock(); } //+--------------------------------------------------------------------------- // // Member: CConnectionList::FlushConnectionList // // Purpose: Remove all entries from the connection list // // Arguments: // (none) // // Returns: // // Author: jeffspr 24 Sep 1998 // // Notes: // VOID CConnectionList::FlushConnectionList() throw() { TraceFileFunc(ttidConnectionList); AcquireLock(); ConnListCore::const_iterator clcIter; ConnListCore::const_iterator clcNext; BOOL fFlushTrayPosts = FALSE; TraceTag(ttidConnectionList, "Flushing the connection list"); TraceStack(ttidConnectionList); if (m_pcclc) { // Iterate through the list and build the ppidl array // for (clcIter = m_pcclc->begin(); clcIter != m_pcclc->end(); clcIter = clcNext) { Assert(!clcIter->second.empty()); clcNext = clcIter; clcNext++; (VOID) HrRemoveByIter(clcIter, &fFlushTrayPosts); } if (m_pcclc->size() != 0) { AssertSz(FALSE, "List not clear after deleting all elements in FlushConnectionList"); // Flush the list itself // m_pcclc->clear(); } } // Reset the icon's icon ID count, as we've cleared out all icons // if (g_pCTrayUI && m_fTiedToTray) { g_pCTrayUI->ResetIconCount(); } m_fPopulated = FALSE; ReleaseLock(); // If we need to do the SendMessage to flush any PostMessages to the tray // do so // if (g_pCTrayUI && g_hwndTray && fFlushTrayPosts) { FlushTrayPosts(g_hwndTray); } } //+--------------------------------------------------------------------------- // // Member: CConnectionList::HrRetrieveConManEntries // // Purpose: Retrieve the connection entries from the connection manager // // Arguments: // None // // Returns: // // Author: jeffspr 20 Feb 1998 // // Notes: // HRESULT CConnectionList::HrRefreshConManEntries() { TraceFileFunc(ttidConnectionList); HRESULT hr = S_OK; CONFOLDENTRY ccfe; PCONFOLDPIDL pidlMNCWizard; PCONFOLDPIDL pidlHNWWizard; CComPtr pconMan2; // Create an instance of the connection manager // hr = HrCreateInstance( CLSID_ConnectionManager2, CLSCTX_LOCAL_SERVER | CLSCTX_NO_CODE_DOWNLOAD, &pconMan2); TraceHr(ttidError, FAL, hr, FALSE, "HrCreateInstance"); if (SUCCEEDED(hr)) { HRESULT hrDebug = S_OK; HRESULT hrProp = S_OK; // Iterate through the connections // SAFEARRAY* psaConnectionProperties; HRESULT hrEnumConnections = pconMan2->EnumConnectionProperties(&psaConnectionProperties); if (SUCCEEDED(hrEnumConnections)) { FlushConnectionList(); AcquireWriteLock(); AcquireLock(); if (m_pcclc) { m_pcclc->clear(); // Make sure somebody else didn't come in in between the two calls and added stuff to the list } ReleaseLock(); // Add the wizards to the beginning of the list // PCONFOLDPIDLVEC pcfpvEmpty; NCCS_STATE nccs = NCCS_ENABLED; DWORD dwResourceId; // Add the Make New Connection Wizard, regardless if there were any connections or not // Check for permissions etc. HrGetCommandState(pcfpvEmpty, CMIDM_NEW_CONNECTION, nccs, &dwResourceId, 0xffffffff, NB_FLAG_ON_TOPMENU); if (NCCS_ENABLED == nccs) { hr = HrCreateConFoldPidl(WIZARD_MNC, NULL, pidlMNCWizard); if (SUCCEEDED(hr)) { // Convert the pidl to a ConFoldEntry // hr = pidlMNCWizard.ConvertToConFoldEntry(ccfe); if (SUCCEEDED(hr)) { // Insert the wizard item // // $$NOTE: Let this fall through, even if the Insert of the wizard // didn't work. Yeah, we'd be in a bad position, but we'd be even // worse off if we just left an empty list. Whatever the case, it // would be next to impossible for this to fail. // hr = HrInsert(ccfe); } } } // Now check if we had found any connections if (S_OK == hrEnumConnections) { Assert(psaConnectionProperties); // Add the Network Setup Wizard nccs = NCCS_ENABLED; // Check for permissions etc. HrGetCommandState(pcfpvEmpty, CMIDM_HOMENET_WIZARD, nccs, &dwResourceId, 0xffffffff, NB_FLAG_ON_TOPMENU); if (NCCS_ENABLED == nccs) { hr = HrCreateConFoldPidl(WIZARD_HNW, NULL, pidlHNWWizard); if (SUCCEEDED(hr)) { // Convert the pidl to a ConFoldEntry // hr = pidlHNWWizard.ConvertToConFoldEntry(ccfe); if (SUCCEEDED(hr)) { hr = HrInsert(ccfe); } } } LONG lLBound; LONG lUBound; m_fPopulated = TRUE; hr = SafeArrayGetLBound(psaConnectionProperties, 1, &lLBound); if (SUCCEEDED(hr)) { hr = SafeArrayGetUBound(psaConnectionProperties, 1, &lUBound); if (SUCCEEDED(hr)) { for (LONG i = lLBound; i <= lUBound; i++) { CComVariant varRecord; hr = SafeArrayGetElement(psaConnectionProperties, &i, reinterpret_cast(&varRecord)); if (FAILED(hr)) { SafeArrayDestroy(psaConnectionProperties); break; } Assert( (VT_ARRAY | VT_VARIANT) == varRecord.vt); if ( (VT_ARRAY | VT_VARIANT) != varRecord.vt) { SafeArrayDestroy(psaConnectionProperties); break; } NETCON_PROPERTIES_EX *pPropsEx; hrDebug = HrNetConPropertiesExFromSafeArray(varRecord.parray, &pPropsEx); if (SUCCEEDED(hr)) { // don't insert incoming connection in transit state if (!((pPropsEx->dwCharacter & NCCF_INCOMING_ONLY) && (pPropsEx->ncMediaType != NCM_NONE) && !(fIsConnectedStatus(pPropsEx->ncStatus)) )) { // Get this for debugging only. PCONFOLDPIDL pcfpEmpty; hrDebug = HrInsertFromNetConPropertiesEx(*pPropsEx, pcfpEmpty); TraceError("Could not Insert from NetConProperties", hrDebug); } HrFreeNetConProperties2(pPropsEx); } else { TraceError("Could not obtain properties from Safe Array", hrDebug); } } } } } else { TraceHr(ttidError, FAL, hr, FALSE, "EnumConnectionProperties of the Connection Manager failed"); } // if S_OK == hr ReleaseWriteLock(); } // if SUCCEEDED(hrEnumConnections) } else { TraceHr(ttidError, FAL, hr, FALSE, "CoCreateInstance of the Connection Manager v2 failed. " "If you're in the process of shutting down, this is expected, as we can't do " "a CoCreate that would force a process to start (netman.exe). If you're not " "shutting down, then let us know the error code"); } #ifdef DBG if (SUCCEEDED(hr)) { AcquireLock(); TraceTag(ttidNotifySink, "CConnectionList::HrRefreshConManEntries:"); if (m_pcclc) { for (ConnListCore::const_iterator i = m_pcclc->begin(); i != m_pcclc->end(); i++) { const CONFOLDENTRY& cfe = i->second.ccfe; WCHAR szTrace[MAX_PATH*2]; OLECHAR szGuidString[MAX_GUID_STRING_LEN]; StringFromGUID2(cfe.GetGuidID(), szGuidString, MAX_GUID_STRING_LEN); TraceTag(ttidNotifySink, " ==>%S [%s:%s:%s:%s]", cfe.GetName(), DbgNcm(cfe.GetNetConMediaType()), DbgNcsm(cfe.GetNetConSubMediaType()), DbgNcs(cfe.GetNetConStatus()), DbgNccf(cfe.GetCharacteristics()) ); } } ReleaseLock(); } #endif TraceHr(ttidError, FAL, hr, FALSE, "CConnectionList::HrRetrieveConManEntries"); return hr; } //+--------------------------------------------------------------------------- // // Member: CConnectionList::HrGetBrandingInfo // // Purpose: Get the branding-specific information off of this particular // connection. It MUST be an NCCF_BRANDING-type connection, or // this information will not be present. // // Arguments: // cle [in, out] The entry for this connection. cle.ccfe must have been // set before this call. // // Returns: // // Author: jeffspr 25 Mar 1998 // // Notes: // HRESULT CConnectionList::HrGetBrandingInfo( IN OUT ConnListEntry& cle) { TraceFileFunc(ttidConnectionList); HRESULT hr = S_OK; INetConnectionBrandingInfo * pncbi = NULL; Assert(!cle.empty()); Assert(!cle.ccfe.empty()); if (cle.empty() || cle.ccfe.empty()) { hr = E_POINTER; } else { Assert(cle.ccfe.GetCharacteristics() & NCCF_BRANDED); hr = cle.ccfe.HrGetNetCon(IID_INetConnectionBrandingInfo, reinterpret_cast(&pncbi)); if (SUCCEEDED(hr)) { // Everything is kosher. Grab the paths. // hr = pncbi->GetBrandingIconPaths(&(cle.pcbi)); if (SUCCEEDED(hr)) { // Trace the icon paths for debugging // if (cle.pcbi->szwLargeIconPath) { TraceTag(ttidConnectionList, " Branded icon [large]: %S", cle.pcbi->szwLargeIconPath); } if (cle.pcbi->szwTrayIconPath) { TraceTag(ttidConnectionList, " Branded icon [tray]: %S", cle.pcbi->szwTrayIconPath); } } // Grab any menu items hr = pncbi->GetTrayMenuEntries(&(cle.pctmd)); if (SUCCEEDED(hr)) { // Trace the menu items for debugging CON_TRAY_MENU_DATA * pMenuData = cle.pctmd; if (pMenuData) { CON_TRAY_MENU_ENTRY * pMenuEntry = pMenuData->pctme; DWORD dwCount = pMenuData->dwCount; while (dwCount) { Assert(pMenuEntry); TraceTag(ttidConnectionList, "***CM menu:*** \nItem: %S \nCommand: %S \nParameters: %S", pMenuEntry->szwMenuText, pMenuEntry->szwMenuCmdLine, pMenuEntry->szwMenuParams); dwCount--; pMenuEntry++; } } } ReleaseObj(pncbi); // 180240 } else { // Not a problem -- just doesn't have branding information // hr = S_OK; } } TraceHr(ttidError, FAL, hr, FALSE, "CConnectionList::HrGetBrandingInfo"); return hr; } //+--------------------------------------------------------------------------- // // Member: CConnectionList::EnsureConPointNotifyAdded // // Purpose: Ensure that we create the con point notify // // Arguments: // (none) // // Returns: // // Author: jeffspr 5 Oct 1998 // // Notes: // VOID CConnectionList::EnsureConPointNotifyAdded() throw() { TraceFileFunc(ttidConnectionList); HRESULT hr = S_OK; // Not returned, but used for debugging IConnectionPoint * pConPoint = NULL; INetConnectionNotifySink * pSink = NULL; AssertSz(m_fAdviseOnThis, "Shouldn't even be calling EnsureConPointNotifyAdded if " "we don't want advises"); if (m_fAdviseOnThis) { if (!InSendMessage()) { // If we don't already have an advise sink // if (c_dwInvalidCookie == m_dwAdviseCookie) { AssertSz(g_dwAdvisesActive == 0, "An advise already exists. We should never " "be creating more than one Advise per Explorer instance"); // Make sure that we have a connection point. // hr = HrGetNotifyConPoint(&pConPoint); if (SUCCEEDED(hr)) { // Create the notify sink // hr = CConnectionNotifySink::CreateInstance( IID_INetConnectionNotifySink, (LPVOID*)&pSink); if (SUCCEEDED(hr)) { Assert(pSink); hr = pConPoint->Advise(pSink, &m_dwAdviseCookie); if (SUCCEEDED(hr)) { TraceTag(ttidNotifySink, "Added advise sink. Cookie = %d", m_dwAdviseCookie); g_dwAdvisesActive++; } TraceHr(ttidError, FAL, hr, FALSE, "pConPoint->Advise"); ReleaseObj(pSink); } ReleaseObj(pConPoint); } } } } TraceHr(ttidError, FAL, hr, FALSE, "EnsureConPointNotifyAdded"); } //+--------------------------------------------------------------------------- // // Member: CConnectionList::EnsureConPointNotifyRemoved // // Purpose: Ensure that the connection point notify has been unadvised. // // Arguments: // (none) // // Returns: // // Author: jeffspr 7 Oct 1998 // // Notes: // VOID CConnectionList::EnsureConPointNotifyRemoved() throw() { TraceFileFunc(ttidConnectionList); HRESULT hr = S_OK; IConnectionPoint * pConPoint = NULL; AssertSz(m_fAdviseOnThis, "EnsureConPointNotifyRemoved shouldn't be " "called when we're not a notify capable connection list"); // No more objects, so remove the advise if present // if (m_dwAdviseCookie != c_dwInvalidCookie) { hr = HrGetNotifyConPoint(&pConPoint); if (SUCCEEDED(hr)) { // Unadvise // hr = pConPoint->Unadvise(m_dwAdviseCookie); TraceTag(ttidNotifySink, "Removed advise sink. Cookie = d", m_dwAdviseCookie); TraceHr(ttidError, FAL, hr, FALSE, "pConPoint->Unadvise"); m_dwAdviseCookie = c_dwInvalidCookie; ReleaseObj(pConPoint); g_dwAdvisesActive--; } } TraceHr(ttidError, FAL, hr, FALSE, "EnsureConPointNotifyRemoved"); } //+--------------------------------------------------------------------------- // // Member: CConnectionList::HrInsert // // Purpose: Insert a connection into the list, based on a pre-built // ConFoldEntry // // Arguments: // pccfe [in] ConFoldEntry describing the connection // // Returns: // // Author: jeffspr 24 Sep 1998 // // Notes: // HRESULT CConnectionList::HrInsert(IN const CONFOLDENTRY& pccfe) { TraceFileFunc(ttidConnectionList); HRESULT hr = S_OK; HRESULT hrFind = S_OK; BOOL fLockHeld = FALSE; Assert(!pccfe.empty()); // Get the lock, so our find/add can't allow a dupe. // // Fill the struct data, and push it on. // ConnListEntry cle; cle.dwState = CLEF_NONE; cle.ccfe = pccfe; // Initialize the branding info cle.pcbi = NULL; cle.pctmd = NULL; if (cle.ccfe.GetCharacteristics() & NCCF_BRANDED) { HrGetBrandingInfo(cle); } Assert(!cle.empty()); AcquireLock(); TraceTag(ttidConnectionList, "Adding %S to the connection list", pccfe.GetName()); ConnListEntry cleFind; hrFind = HrFindConnectionByGuid(&(pccfe.GetGuidID()), cleFind); if (hrFind == S_FALSE) { // Allocate our list if we haven't already. // if (!m_pcclc) { m_pcclc = new ConnListCore; } // Allocate the structure to be pushed onto the STL list. // if (!m_pcclc) { hr = E_OUTOFMEMORY; ReleaseLock(); } else { Assert(!cle.empty()); (*m_pcclc)[cle.ccfe.GetGuidID()] = cle; ReleaseLock(); if (m_fTiedToTray && g_pCTrayUI && cle.ccfe.FShouldHaveTrayIconDisplayed()) { CONFOLDENTRY ccfeDup; hr = ccfeDup.HrDupFolderEntry(cle.ccfe); if (SUCCEEDED(hr)) { // Note: this must be a send message otherwise we can // get duplicate icons in the tray. ;-( We should set the // uiTrayIconId here (while we have the lock) and PostMessage // to actually add the tray icon, but that's a big change. // TraceTag(ttidSystray, "HrInsert: Adding tray icon for %S", cle.ccfe.GetName()); PostMessage(g_hwndTray, MYWM_ADDTRAYICON, (WPARAM) ccfeDup.TearOffItemIdList(), (LPARAM) 0); } } } } else { ReleaseLock(); if (S_OK == hrFind) { TraceTag(ttidConnectionList, "Avoiding adding duplicate connection to the connection list"); } else { // We had a failure finding the connection. We're hosed. TraceTag(ttidConnectionList, "Failure doing a findbyguid in the CConnectionList::HrInsert()"); } } TraceHr(ttidError, FAL, hr, FALSE, "CConnectionList::HrInsert"); return hr; } //+--------------------------------------------------------------------------- // // Member: CConnectionList::HrInsertFromNetCon // // Purpose: Given an INetConnection *, build the cle data and insert // the new connection into the list. Return a PCONFOLDPIDL if // requested. // // Arguments: // pNetCon [in] The active INetConnection interface // ppcfp [out] Return pointer for PCFP, if requested // // Returns: // // Author: jeffspr 24 Sep 1998 // // Notes: // HRESULT CConnectionList::HrInsertFromNetCon( IN INetConnection * pNetCon, OUT PCONFOLDPIDL & ppcfp) { TraceFileFunc(ttidConnectionList); HRESULT hr = S_OK; PCONFOLDPIDL pidlConnection; CONFOLDENTRY pccfe; Assert(pNetCon); NETCFG_TRY // From the net connection, create the pidl // hr = HrCreateConFoldPidl(WIZARD_NOT_WIZARD, pNetCon, pidlConnection); if (SUCCEEDED(hr)) { // Convert the pidl to a ConFoldEntry. // hr = pidlConnection.ConvertToConFoldEntry(pccfe); if (SUCCEEDED(hr)) { // Insert the item into the connection list. HrInsert should // take over this CONFOLDENTRY, so we can't delete it. // Note: We should kill this on fail, but we must make // sure that HrInsert doesn't keep the pointer anywhere on // failure. // hr = HrInsert(pccfe); } } if (SUCCEEDED(hr)) { // Fill in the out param if ( !(pidlConnection.empty()) ) { ppcfp = pidlConnection; } } NETCFG_CATCH(hr) TraceHr(ttidError, FAL, hr, FALSE, "CConnectionList::HrInsertFromNetCon"); return hr; } //+--------------------------------------------------------------------------- // // Member: CConnectionList::HrInsertFromNetConPropertiesEx // // Purpose: Given an NETCON_PROPERTIES_EX&, build the cle data and insert // the new connection into the list. Return a PCONFOLDPIDL // // Arguments: // pPropsEx [in] The active NETCON_PROPERTIES_EX // ppcfp [out] Return PCONFOLDPIDL // // Returns: // // Author: deonb 26 Mar 2001 // // Notes: // HRESULT CConnectionList::HrInsertFromNetConPropertiesEx( IN const NETCON_PROPERTIES_EX& pPropsEx, OUT PCONFOLDPIDL & ppcfp) { TraceFileFunc(ttidConnectionList); HRESULT hr = S_OK; PCONFOLDPIDL pidlConnection; CONFOLDENTRY pccfe; // hr = HrCreateConFoldPidl(pPropsEx, pidlConnection); if (SUCCEEDED(hr)) { // Convert the pidl to a ConFoldEntry. // hr = pidlConnection.ConvertToConFoldEntry(pccfe); if (SUCCEEDED(hr)) { // Insert the item into the connection list. HrInsert should // take over this CONFOLDENTRY, so we can't delete it. // Note: We should kill this on fail, but we must make // sure that HrInsert doesn't keep the pointer anywhere on // failure. // hr = HrInsert(pccfe); } } if (SUCCEEDED(hr)) { // Fill in the out param if ( !(pidlConnection.empty()) ) { ppcfp = pidlConnection; } } TraceHr(ttidError, FAL, hr, FALSE, "CConnectionList::HrInsertFromNetCon"); return hr; } // Old HrFindCallbackConnName bool operator==(IN const ConnListCore::value_type& val, IN PCWSTR pszName) throw() { bool bRet = false; Assert(pszName); const ConnListEntry &cle = val.second; Assert(!cle.empty()); Assert(!cle.ccfe.empty()); Assert(cle.ccfe.GetName()); if (lstrcmpiW(pszName, cle.ccfe.GetName()) == 0) { bRet = true; } return bRet; } // Old HrFindCallbackConFoldEntry bool operator==(IN const ConnListCore::value_type& val, IN const CONFOLDENTRY& cfe) throw() { bool bRet = false; Assert(!cfe.empty()) const ConnListEntry &cle = val.second; Assert(!cle.empty()); Assert(!cfe.empty()); Assert(!cle.ccfe.empty()); Assert(cle.ccfe.GetName()); if (cle.ccfe.GetWizard() && cfe.GetWizard()) { bRet = true; } else { if (InlineIsEqualGUID(cfe.GetGuidID(), cle.ccfe.GetGuidID())) { bRet = true; } } return bRet; } // Old HrFindCallbackTrayIconId bool operator==(IN const ConnListCore::value_type& val, IN const UINT& uiIcon) throw() { bool bRet = false; const ConnListEntry &cle = val.second; Assert(!cle.empty()); Assert(!cle.ccfe.empty()); if (cle.HasTrayIconData() && (cle.GetTrayIconData()->GetTrayIconId() == uiIcon)) { bRet = true; } return bRet; } // Old HrFindCallbackGuid bool operator < (IN const GUID& rguid1, IN const GUID& rguid2) throw() { return memcmp(&rguid1, &rguid2, sizeof(GUID)) < 0; } BOOL ConnListEntry::empty() const throw() { return (ccfe.empty()); } void ConnListEntry::clear() throw() { dwState = NULL; ccfe.clear(); pctmd = NULL; pcbi = NULL; DeleteTrayIconData(); } VOID CConnectionList::InternalAcquireLock() throw() { TraceFileFunc(ttidConnectionList); EnterCriticalSection(&m_csMain); #if DBG m_dwCritSecRef++; // TraceTag(ttidConnectionList, "CConnectionList::AcquireLock (%d)", m_dwCritSecRef); #endif } VOID CConnectionList::InternalReleaseLock() throw() { TraceFileFunc(ttidConnectionList); #if DBG m_dwCritSecRef--; // TraceTag(ttidConnectionList, "CConnectionList::ReleaseLock (%d)", m_dwCritSecRef); #endif LeaveCriticalSection(&m_csMain); } //+--------------------------------------------------------------------------- // // Member: CConnectionList::HrFindConnectionByName // // Purpose: Find a connection in the connection list, using // the connection name as the search key // // Arguments: // pszName [in] Name of the connection to find // cle [out] Return pointer for the connection entry // // Returns: // // Author: jeffspr 20 Mar 1998 // // Notes: // inline HRESULT CConnectionList::HrFindConnectionByName( IN PCWSTR pszName, OUT ConnListEntry& cle) { TraceFileFunc(ttidConnectionList); return HrFindConnectionByType( pszName, cle ); } inline HRESULT CConnectionList::HrFindConnectionByConFoldEntry( IN const CONFOLDENTRY& cfe, OUT ConnListEntry& cle) { TraceFileFunc(ttidConnectionList); return HrFindConnectionByType( cfe, cle ); } inline HRESULT CConnectionList::HrFindConnectionByTrayIconId( IN UINT uiIcon, OUT ConnListEntry& cle) { TraceFileFunc(ttidConnectionList); return HrFindConnectionByType( uiIcon, cle ); } //+--------------------------------------------------------------------------- // // Member: CConnectionList::HrFindRasServerConnection // // Purpose: Find the RAS Server connection // // Arguments: // cle [out] The connection list entry // // Returns: // // Author: deonb 26 Apr 2001 // // Notes: // HRESULT CConnectionList::HrFindRasServerConnection( OUT ConnListEntry& cle) { HRESULT hr = S_FALSE; if (m_pcclc) { AcquireLock(); ConnListCore::const_iterator clcIter; // Try to find the connection // for (clcIter = m_pcclc->begin(); clcIter != m_pcclc->end(); clcIter++) { cle = clcIter->second; if (!cle.ccfe.empty()) { if (cle.ccfe.GetCharacteristics() & NCCF_INCOMING_ONLY) { if (cle.ccfe.GetNetConMediaType() == NCM_NONE) { hr = S_OK; break; } } } } ReleaseLock(); } else { hr = E_UNEXPECTED; } return hr; } //+--------------------------------------------------------------------------- // // Member: CConnectionList::HrFindPidlByGuid // // Purpose: Using a GUID, find the connection in the connection list // and, using the conlist pccfe member, generate a pidl. This // will be used in most of the notify sink refresh operations. // // Arguments: // pguid [in] Connection GUID // ppidl [out] Out param for the generated pidl // // Returns: // // Author: jeffspr 28 Aug 1998 // // Notes: // HRESULT CConnectionList::HrFindPidlByGuid( IN const GUID * pguid, OUT PCONFOLDPIDL& pidl) { TraceFileFunc(ttidConnectionList); HRESULT hr = S_OK; ConnListEntry cle; hr = HrFindConnectionByGuid(pguid, cle); if (S_OK == hr) { // convert to pidl and call the deleteccl // hr = cle.ccfe.ConvertToPidl(pidl); } TraceHr(ttidError, FAL, hr, (S_FALSE == hr), "CConnectionList::HrFindPidlByGuid"); return hr; } //+--------------------------------------------------------------------------- // // Member: CConnectionList::HrFindConnectionByGuid // // Purpose: Find the connection list entry based on the unique GUID // of the connection. Return the list entry to the caller. // // Arguments: // pguid [in] Lookup key // cle [out] Return pointer for the list entry (see Notes:) // // Returns: S_OK, S_FALSE, or an error // // Author: jeffspr 24 Sep 1998 // // Notes: The list must be locked until the caller stops using // the returned entry // HRESULT CConnectionList::HrFindConnectionByGuid( IN const GUID UNALIGNED*pguid, OUT ConnListEntry & cle) { TraceFileFunc(ttidConnectionList); HRESULT hr = S_FALSE; GUID alignedGuid; Assert(pguid); alignedGuid = *pguid; // Pre-NULL this out in case of failure. // if (m_pcclc) { AcquireLock(); ConnListCore::const_iterator iter = m_pcclc->find(alignedGuid); if (iter != m_pcclc->end() ) { cle = iter->second; Assert(!cle.ccfe.empty() ); if (!cle.ccfe.empty()) { cle.UpdateCreationTime(); hr = S_OK; } else { hr = E_OUTOFMEMORY; } } else { hr = S_FALSE; } ReleaseLock(); } else { hr = S_FALSE; } return hr; } //+--------------------------------------------------------------------------- // // Member: CConnectionList::HrGetCurrentStatsForTrayIconId // // Purpose: Get the current statistics data from the connection // with the specified tray icon id. // // Arguments: // uiIcon [in] Tray icon id. // ppData [out] Address of where to return pointer to data. // pstrName [out] Address of a tstring where the name of the connection // is returned. // // Returns: S_OK, S_FALSE if not found, or an error. // // Author: shaunco 7 Nov 1998 // // Notes: Free the *ppData with CoTaskMemFree. // HRESULT CConnectionList::HrGetCurrentStatsForTrayIconId( IN UINT uiIcon, OUT STATMON_ENGINEDATA** ppData, OUT tstring* pstrName) { TraceFileFunc(ttidConnectionList); HRESULT hr; ConnListEntry cle; INetStatisticsEngine* pnse = NULL; // Initialize the output parameter. // if (ppData) { *ppData = NULL; } pstrName->erase(); // Lock the list only long enough to find the entry and // get an AddRef'd copy of its INetStatisticsEngine interface pointer. // It's very important not to use this pointer while our lock is // held because doing so will cause it to try to get it's own lock. // If, on some other thread, that statistics engine is trying to call // back into us (and it already has its lock held), we'd have a dead lock. // AddRefing it ensures that the interface is valid even after we // release our lock. // AcquireLock(); hr = HrFindConnectionByTrayIconId(uiIcon, cle); if (S_OK == hr) { Assert(cle.HasTrayIconData() ); pnse = cle.GetTrayIconData()->GetNetStatisticsEngine(); AddRefObj(pnse); // Make a copy of the name for the caller. // pstrName->assign(cle.ccfe.GetName()); } ReleaseLock(); // If we found the entry and obtained it's INetStatisticsEngine interface, // get the current statistics data from it and release it. // if (pnse && ppData) { hr = pnse->GetStatistics(ppData); } if (pnse) { ReleaseObj(pnse); } TraceHr(ttidError, FAL, hr, (S_FALSE == hr), "CConnectionList::HrGetCurrentStatsForTrayIconId"); return hr; } //+--------------------------------------------------------------------------- // // Member: CConnectionList::HrUpdateTrayIconIdByName // // Purpose: Update the connection list entry for a particular connection, // as the icon id has changed. // // Arguments: // pszName [in] Name of the connection to update // pccts [in] Tray stats interface // pcpStat [in] Interface used for Advise // pnseStats [in] More statistics object crap // uiIcon [in] Icon ID to be stored in that entry // // Returns: S_OK, S_FALSE if not found, or an error code. // // Author: jeffspr 20 Mar 1998 // // Notes: // HRESULT CConnectionList::HrUpdateTrayIconDataByGuid( IN const GUID * pguid, IN CConnectionTrayStats * pccts, IN IConnectionPoint * pcpStat, IN INetStatisticsEngine * pnseStats, IN UINT uiIcon) { TraceFileFunc(ttidConnectionList); HRESULT hr = S_OK; ConnListEntry cle; AcquireWriteLock(); hr = HrFindConnectionByGuid(pguid, cle); if (hr == S_OK) { Assert(!cle.empty()); CTrayIconData pTrayIconData(uiIcon, cle.ccfe.GetNetConStatus(), pcpStat, pnseStats, pccts); cle.SetTrayIconData(pTrayIconData); hr = HrUpdateConnectionByGuid(pguid, cle); } ReleaseWriteLock(); TraceHr(ttidError, FAL, hr, (S_FALSE == hr), "CConnectionList::HrUpdateTrayIconDataByGuid"); return hr; } //+--------------------------------------------------------------------------- // // Member: CConnectionList::HrUpdateTrayBalloonInfoByGuid // // Purpose: Update the balloon entry for a particular connection, // // Arguments: // pguid [in] Guid of the connection to update // dwLastBalloonMessage [in] BALLOONS enum // szCookie [in] Cookie // pfnBalloonFunction [in] Balloon callback function if BALLOONS == BALLOON_CALLBACK // // Returns: S_OK, S_FALSE if not found, or an error code. // // Author: deon 22 Mar 2001 // // Notes: // HRESULT CConnectionList::HrUpdateTrayBalloonInfoByGuid(IN const GUID * pguid, IN DWORD dwLastBalloonMessage, IN BSTR szCookie, IN FNBALLOONCLICK* pfnBalloonFunction) { TraceFileFunc(ttidConnectionList); HRESULT hr = S_OK; ConnListEntry cle; AcquireWriteLock(); hr = HrFindConnectionByGuid(pguid, cle); if (hr == S_OK) { Assert(!cle.empty()); CTrayIconData * pTrayIconData = cle.GetTrayIconData(); if (pTrayIconData != NULL) { hr = pTrayIconData->SetBalloonInfo(dwLastBalloonMessage, szCookie, pfnBalloonFunction); if (SUCCEEDED(hr)) { hr = HrUpdateConnectionByGuid(pguid, cle); } } } ReleaseWriteLock(); TraceHr(ttidError, FAL, hr, (S_FALSE == hr), "CConnectionList::HrUpdateTrayBalloonInfoByGuid"); return hr; } HRESULT CConnectionList::HrUpdateConnectionByGuid(IN const GUID * pguid, IN const ConnListEntry& cle ) { TraceFileFunc(ttidConnectionList); HRESULT hr = S_OK; GUID alignedGuid; Assert(pguid); alignedGuid = *pguid; if (m_pcclc) { ConnListEntry cleCopy(cle); AcquireLock(); ConnListCore::iterator iter = m_pcclc->find(alignedGuid); if (iter != m_pcclc->end() ) { // If what we have in the list is already more recent, just discard the change if ( iter->second.GetCreationTime() <= cleCopy.GetCreationTime() ) { iter->second = cleCopy; hr = S_OK; } else { TraceError("HrUpdateConnectionByGuid discarded older ConnectionListEntry", E_FAIL); hr = S_FALSE; } Assert(!cleCopy.empty()); } else { hr = E_FAIL; } ReleaseLock(); } else { hr = E_FAIL; } return hr; } //+--------------------------------------------------------------------------- // // Member: CConnectionList::HrUpdateNameByGuid // // Purpose: Update the list with the new connection name. Search for the // connection using the guid. Depending on the value of fForce, // either fail a duplicate connection name or force the issue // (since this might be as a result of a shell call, which we // have no control over) // // Arguments: // pguid [in] Lookup key // pszNewName [in] New name for the connection // ppidlOut [out] Output pidl, if requested // fForce [in] Force the name change, or fail on duplicate? // // Returns: // // Author: jeffspr 24 Sep 1998 // // Notes: // HRESULT CConnectionList::HrUpdateNameByGuid( IN const GUID * pguid, IN PCWSTR pszNewName, OUT PCONFOLDPIDL & pidlOut, IN BOOL fForce) { TraceFileFunc(ttidConnectionList); HRESULT hr = S_OK; ConnListEntry cle; Assert(pguid); Assert(pszNewName); AcquireWriteLock(); hr = HrFindConnectionByGuid(pguid, cle); if (S_OK == hr) { // Check to see if we already have an entry with this name // ConnListEntry cleDupe; hr = HrFindConnectionByName(pszNewName, cleDupe); if (S_OK == hr && !fForce) { Assert(!cleDupe.empty()); hr = NETCFG_E_NAME_IN_USE; } else { // This is what we want.. Either there's not already a connection // with this name or we are allowing ourselves to rename it to // a duplicate string (this can occur when RAS is notifying us of // a change -- you know, separate phonebooks and all). // if ((S_FALSE == hr) || (hr == S_OK && fForce)) { PWSTR pszNewNameCopy = NULL; if (!(cle.ccfe.GetWizard())) { hr = HrDupeShellString(pszNewName, &pszNewNameCopy); if (SUCCEEDED(hr)) { Assert(pszNewNameCopy); // If it's not the static wizard string, and it's non-NULL then // free it // cle.ccfe.SetPName(pszNewNameCopy); // If we're to return a new PIDL for this entry // // Convert the class back to the pidl format // hr = cle.ccfe.ConvertToPidl(pidlOut); } } } else { AssertSz(FALSE, "Error occurred while attempting to find a dupe in HrUpdateNameByGuid"); } } if (SUCCEEDED(hr)) { hr = HrUpdateConnectionByGuid(pguid, cle); } } ReleaseWriteLock(); TraceHr(ttidError, FAL, hr, FALSE, "CConnectionList::HrUpdateNameByGuid"); return hr; } //+--------------------------------------------------------------------------- // // Member: CConnectionList::HrUpdateTrayIconByGuid // // Purpose: Update the icon image based on the connection changes. // Do the lookup by GUID. // // Arguments: // pguid [in] GUID of the changed connection // // Returns: // // Author: jeffspr 24 Sep 1998 // // Notes: // HRESULT CConnectionList::HrUpdateTrayIconByGuid( IN const GUID * pguid, OUT BOOL fBrieflyShowBalloon) { TraceFileFunc(ttidConnectionList); HRESULT hr = S_OK; ConnListEntry cle; Assert(m_fTiedToTray); TraceTag(ttidConnectionList, "HrUpdateTrayIconByGuid"); if (!g_pCTrayUI || !m_fTiedToTray) { TraceTag(ttidConnectionList, "!g_pCTrayUI || !m_fTiedToTray, so no updates"); return S_OK; } Assert(pguid); AcquireWriteLock(); hr = HrFindConnectionByGuid(pguid, cle); if (S_OK == hr) { GUID * pguidCopy = NULL; BOOL fShouldHaveIcon = cle.ccfe.FShouldHaveTrayIconDisplayed(); BOOL fShouldRemoveOld = FALSE; TraceTag(ttidConnectionList, "HrUpdateTrayIconByGuid: Found. fShouldHave: %d", fShouldHaveIcon); // If there's an existing icon, see if it needs to go away if (cle.HasTrayIconData()) { // If we need to remove a media-disconnected icon, do so. // if (cle.ccfe.GetNetConStatus() != cle.GetTrayIconData()->GetConnected()) // If the status has changed. { NETCON_STATUS ncsOldStatus = cle.GetTrayIconData()->GetConnected(); NETCON_STATUS ncsNewStatus = cle.ccfe.GetNetConStatus(); if ( (NCS_INVALID_ADDRESS == ncsNewStatus) || // Definitely changes the icon (NCS_MEDIA_DISCONNECTED == ncsNewStatus) || // Definitely changes the icon (NCS_INVALID_ADDRESS == ncsOldStatus) || // Definitely changes the icon (NCS_MEDIA_DISCONNECTED == ncsOldStatus) || // Definitely changes the icon ( (fIsConnectedStatus(ncsOldStatus) != fIsConnectedStatus(ncsNewStatus)) && // From connect to disconnect or disconnect to connect !((NCS_DISCONNECTING == ncsOldStatus) && (NCS_CONNECTED == ncsNewStatus)) && // BUT NOT going from Disconnecting to Connect (BAP dialup failure) !((NCS_CONNECTED == ncsOldStatus) && (NCS_CONNECTING == ncsNewStatus)) // Or from Connect to Connecting (BAP dialup failure) ) ) { // if we are changing to one of these states, we need to remove whatever was there previously TraceTag(ttidConnectionList, "HrUpdateTrayByGuid: Need to remove icon"); fShouldRemoveOld = TRUE; } } // Else if we just don't need one anymore... // else if (!fShouldHaveIcon) { TraceTag(ttidConnectionList, "HrUpdateTrayIconByGuid: Shouldn't have a tray icon. Need to remove"); fShouldRemoveOld = TRUE; } } else { TraceTag(ttidConnectionList, "HrUpdateTrayIconByGuid. No existing icon (for removal)"); pguidCopy = new GUID; // Copy the guid if (pguidCopy) { CopyMemory(pguidCopy, pguid, sizeof(GUID)); } } TraceTag(ttidConnectionList, "HrUpdateTrayIconByGuid: Found. fShouldHave: %d, fShouldRemove: %d", fShouldHaveIcon, fShouldRemoveOld); if (fShouldRemoveOld || pguidCopy) { TraceTag(ttidConnectionList, "HrUpdateTrayIconByGuid: Posting icon removal"); if (cle.HasTrayIconData()) { CTrayIconData* pTrayIconData = new CTrayIconData(*cle.GetTrayIconData()); cle.DeleteTrayIconData(); TraceTag(ttidSystray, "HrUpdateTrayIconByGuid: Removing tray icon for %S", cle.ccfe.GetName()); PostMessage(g_hwndTray, MYWM_REMOVETRAYICON, (WPARAM) pTrayIconData, (LPARAM) 0); } else { TraceTag(ttidSystray, "HrUpdateTrayIconByGuid: Removing tray icon [FROM GUID] for %S", cle.ccfe.GetName()); PostMessage(g_hwndTray, MYWM_REMOVETRAYICON, (WPARAM) 0, (LPARAM) pguidCopy); } TraceTag(ttidConnectionList, "HrUpdateTrayIconByGuid: Back from icon removal"); } TraceTag(ttidConnectionList, "HrUpdateTrayIconByGuid: cle.pTrayIconData: 0x%08x, fShouldHave: %d", cle.GetTrayIconData(), fShouldHaveIcon); // If there's no tray icon, but the characteristics say that there should be, // add one. // if ((!cle.HasTrayIconData()) && fShouldHaveIcon) { TraceTag(ttidConnectionList, "HrUpdateTrayIconByGuid: Adding tray icon"); CONFOLDENTRY ccfeDup; hr = ccfeDup.HrDupFolderEntry(cle.ccfe); if (SUCCEEDED(hr)) { TraceTag(ttidSystray, "HrUpdateTrayIconByGuid: Adding tray icon for %S", cle.ccfe.GetName()); PostMessage(g_hwndTray, MYWM_ADDTRAYICON, (WPARAM) ccfeDup.TearOffItemIdList(), (LPARAM) fBrieflyShowBalloon); } } else { TraceTag(ttidConnectionList, "HrUpdateTrayIconByGuid: Not adding an icon"); } if (SUCCEEDED(hr)) { hr = HrUpdateConnectionByGuid(pguid, cle); } } ReleaseWriteLock(); TraceHr(ttidError, FAL, hr, FALSE, "CConnectionList::HrUpdateTrayIconByGuid"); return hr; } //+--------------------------------------------------------------------------- // // Member: CConnectionList::HrSuggestNameForDuplicate // // Purpose: Given an existing connection name, suggest a new name // based on name conflict resolution rules // // Arguments: // pszOriginal [in] Name being copied // ppszNew [out] Suggested duplicate // // Returns: // // Author: jeffspr 24 Sep 1998 // // Notes: // HRESULT CConnectionList::HrSuggestNameForDuplicate( IN PCWSTR pszOriginal, OUT PWSTR * ppszNew) { TraceFileFunc(ttidConnectionList); HRESULT hr = S_OK; PWSTR pszReturn = NULL; DWORD dwLength = lstrlenW(pszOriginal); BOOL fUnique = FALSE; ConnListEntry cle; // Maximum # of digits for resolving duplicates = 999999 static const DWORD c_cmaxDigits = 6; static const DWORD c_cmaxSuggest = 999999; if (dwLength == 0) { hr = E_INVALIDARG; } else { dwLength += lstrlenW(SzLoadIds(IDS_CONFOLD_DUPLICATE_PREFIX2)) + c_cmaxDigits; pszReturn = new WCHAR[dwLength + 1]; if (!pszReturn) { hr = E_FAIL; } else { INT cSuggest = 0; while (!fUnique && SUCCEEDED(hr) && (cSuggest <= c_cmaxSuggest)) { if (!cSuggest) { // Try "Copy of " first DwFormatString(SzLoadIds(IDS_CONFOLD_DUPLICATE_PREFIX1), pszReturn, dwLength, pszOriginal); } else { WCHAR szDigits[c_cmaxDigits + 1]; wsprintfW(szDigits, L"%lu", cSuggest + 1); // Try "Copy (x) of " now. DwFormatString(SzLoadIds(IDS_CONFOLD_DUPLICATE_PREFIX2), pszReturn, dwLength, szDigits, pszOriginal); } if (lstrlenW(pszReturn) > 255) { pszReturn[255] = '\0'; // Truncate if too long } // See if it already exists // hr = HrFindConnectionByName(pszReturn, cle); if (SUCCEEDED(hr)) { if (hr == S_FALSE) { // Normalize the hr -- don't want to return S_FALSE; // hr = S_OK; fUnique = TRUE; } } cSuggest++; } // If we're still not unique, then we're out of range, and fail out. // if (!fUnique) { hr = E_FAIL; } } } if (SUCCEEDED(hr)) { *ppszNew = pszReturn; } else { if (pszReturn) { delete [] pszReturn; } } TraceHr(ttidError, FAL, hr, FALSE, "CConnectionList::HrSuggestNameForDuplicate"); return hr; } //+--------------------------------------------------------------------------- // // Member: CConnectionList::HrGetCachedPidlCopyFromPidl // // Purpose: Given an existing (likely outdated) pidl, retrieve the // cached info from the list and build an up-to-date pidl // // Arguments: // pidl [in] Not-necessarily-new pidl // ppcfp [out] New pidl using cached data // // Returns: // // Author: jeffspr 24 Sep 1998 // // Notes: // HRESULT CConnectionList::HrGetCachedPidlCopyFromPidl( IN const PCONFOLDPIDL& pidl, OUT PCONFOLDPIDL & pcfp) { TraceFileFunc(ttidConnectionList); HRESULT hr = S_OK; ConnListEntry cle; Assert(!pidl.empty()); NETCFG_TRY pcfp.Clear(); // Verify that this is a confoldpidl // if (pidl->IsPidlOfThisType()) { hr = HrFindConnectionByGuid(&(pidl->guidId), cle); if (S_OK == hr) { Assert(!cle.empty()); Assert(!cle.ccfe.empty()); const CONFOLDENTRY &pccfe = cle.ccfe; hr = pccfe.ConvertToPidl(pcfp); } else { pcfp = pidl; } } else { pcfp = pidl; hr = S_OK; } NETCFG_CATCH(hr) TraceHr(ttidError, FAL, hr, (S_FALSE == hr), "CConnectionList::HrGetCachedPidlCopyFromPidl"); return hr; } //+--------------------------------------------------------------------------- // // Function: HrMapCMHiddenConnectionToOwner // // Purpose: Maps a child connection to its parent connection. // // Connection Manager has two stages: Dialup and VPN. // For the Dialup it creates a hidden connectoid that the // folder (netshell) does not see. However netman caches // the name, guid and status of this connectedoid. Both // the parent and child connectoid have the same name. When // the status of the hidden connectiod is updated the folder // recives the guid of the hidden connectoid and maps the // connectiod to it parent (Connection Manager) by searching // netmans cache for the name of the hidden connectoid. Then it // searches the connections in the folder for that name and thus // gets the guid of the parent connectoid. // // When the folder gets a notify message from netman for the hidden // connection it uses this function to find the parent and update the // parent's status. The hidden connection is not displayed. // // Arguments: // guidHidden [in] GUID of the hidden connectiod // pguidOwner [out] GUID of the parent connectiod // // Returns: S_OK -- mapped the hidden connection to its parent // // Author: omiller 1 Jun 2000 // // Notes: // HRESULT CConnectionList::HrMapCMHiddenConnectionToOwner(IN REFGUID guidHidden, OUT GUID * pguidOwner) { TraceFileFunc(ttidConnectionList); INetConnectionCMUtil * pCMUtil; HRESULT hr = S_OK; hr = HrCreateInstance( CLSID_ConnectionManager, CLSCTX_LOCAL_SERVER | CLSCTX_NO_CODE_DOWNLOAD, &pCMUtil); if( SUCCEEDED(hr) ) { // Map the hidden connection to its parent. // hr = pCMUtil->MapCMHiddenConnectionToOwner(guidHidden, pguidOwner); ReleaseObj(pCMUtil); } return hr; } //+--------------------------------------------------------------------------- // // Function: HrUnsetCurrentDefault // // Purpose: Searches for the current default connection and clear // the default flag. // // Arguments: // guidHidden [in] GUID of the hidden connectiod // pguidOwner [out] GUID of the parent connectiod // // Returns: S_OK -- mapped the hidden connection to its parent // // Author: deonb 4 Apr 2001 // // Notes: // HRESULT CConnectionList::HrUnsetCurrentDefault(OUT PCONFOLDPIDL& cfpPreviousDefault) { HRESULT hr = S_FALSE; AcquireLock(); ConnListCore::iterator clcIter; // Iterate through the list and search for the old default connection. // for (clcIter = m_pcclc->begin(); clcIter != m_pcclc->end(); clcIter++) { ConnListEntry &cle = clcIter->second; if (!cle.ccfe.empty()) { if (cle.ccfe.GetCharacteristics() & NCCF_DEFAULT) { cle.ccfe.SetCharacteristics(cle.ccfe.GetCharacteristics() & ~NCCF_DEFAULT); hr = cle.ccfe.ConvertToPidl(cfpPreviousDefault); break; } } else { hr = E_OUTOFMEMORY; } } ReleaseLock(); return hr; } //+--------------------------------------------------------------------------- // // Function: HrHasActiveIncomingConnections // // Purpose: See if there are active incoming connections active (apart from // the RAS server). // // Arguments: pdwCount [out] Number of incoming connections // // Returns: S_OK -- Has active incoming connections // S_FALSE -- Does not have active incoming connections // FAILED(HRESULT) if failed // // Author: deonb 24 Apr 2001 // // Notes: // HRESULT CConnectionList::HasActiveIncomingConnections(OUT LPDWORD pdwCount) { HRESULT hr = S_FALSE; Assert(pdwCount); *pdwCount = 0; AcquireLock(); ConnListCore::const_iterator clcIter; BOOL bRasServer = FALSE; // Iterate through the list and search for the old default connection. // for (clcIter = m_pcclc->begin(); clcIter != m_pcclc->end(); clcIter++) { const ConnListEntry &cle = clcIter->second; if (!cle.ccfe.empty()) { if (cle.ccfe.GetCharacteristics() & NCCF_INCOMING_ONLY) { if (cle.ccfe.GetNetConMediaType() == NCM_NONE) { AssertSz(!bRasServer, "How did you get more than one RAS Server?"); bRasServer = TRUE; } else { (*pdwCount)++; } } } else { hr = E_OUTOFMEMORY; } } ReleaseLock(); if (SUCCEEDED(hr)) { if (*pdwCount) { AssertSz(bRasServer, "How did you get Incoming Connections without a RAS Server?") hr = S_OK; } else { hr = S_FALSE; } } return hr; } //+--------------------------------------------------------------------------- // // Function: HrCheckForActivation // // Purpose: Check to see if this connection is in the process of // activating (so we can disallow delete/rename/etc.). // // Arguments: // pccfe [in] ConFoldEntry to check // pfActivating [out] Return pointer for activating yes/no // // Returns: S_OK on success, S_FALSE if connection not found, or // any upstream error code. // // Author: jeffspr 4 Jun 1998 // // Notes: // HRESULT HrCheckForActivation( IN const PCONFOLDPIDL& pcfp, IN const CONFOLDENTRY& pccfe, OUT BOOL * pfActivating) { HRESULT hr = S_OK; ConnListEntry cle; BOOL fActivating = FALSE; Assert(pfActivating); Assert(! (pccfe.empty() && pcfp.empty()) ); // Must specify one of the two if (!pccfe.empty()) { hr = g_ccl.HrFindConnectionByConFoldEntry(pccfe, cle); } else { hr = g_ccl.HrFindConnectionByGuid(&(pcfp->guidId), cle); } if (S_OK == hr) { fActivating = (cle.dwState & CLEF_ACTIVATING); } if (SUCCEEDED(hr)) { *pfActivating = fActivating; } TraceHr(ttidError, FAL, hr, (S_FALSE == hr), "HrCheckForActivation"); return hr; } //+--------------------------------------------------------------------------- // // Function: HrSetActivationFlag // // Purpose: Set the activation flag for a particular connection // // Arguments: // pcfp [in] Either this pidl or the pconfoldentry below // pccfe [in] must be valid. // fActivating [out] Current activation status // // Returns: // // Author: jeffspr 5 Jun 1998 // // Notes: // HRESULT HrSetActivationFlag( IN const PCONFOLDPIDL& pcfp, IN const CONFOLDENTRY& pccfe, IN BOOL fActivating) { HRESULT hr = S_OK; ConnListEntry cle; // If the pccfe is valid, use that. Otherwise, use the guid from the pidl // #ifdef DBG if (FIsDebugFlagSet(dfidTraceFileFunc)) { TraceTag(ttidConnectionList, "Acquiring LOCK: %s, %s, %d", __FUNCTION__, __FILE__, __LINE__); } #endif g_ccl.AcquireWriteLock(); if (!pccfe.empty()) { hr = g_ccl.HrFindConnectionByConFoldEntry(pccfe, cle); } else { Assert(!pcfp.empty()); hr = g_ccl.HrFindConnectionByGuid(&(pcfp->guidId), cle); } if (S_OK == hr) { // Assert that the state isn't already set this way. // // Assert((!!(cle.dwState & CLEF_ACTIVATING)) != fActivating); if (fActivating) { cle.dwState |= CLEF_ACTIVATING; } else { cle.dwState &= ~CLEF_ACTIVATING; } g_ccl.HrUpdateConnectionByGuid(&(cle.ccfe.GetGuidID()), cle); } #ifdef DBG if (FIsDebugFlagSet(dfidTraceFileFunc)) { TraceTag(ttidConnectionList, "Releasing LOCK: %s, %s, %d", __FUNCTION__, __FILE__, __LINE__); } #endif g_ccl.ReleaseWriteLock(); TraceHr(ttidError, FAL, hr, (S_FALSE == hr), "HrSetActivationFlag"); return hr; } //+--------------------------------------------------------------------------- // // Function: HrGetTrayIconLock // // Purpose: Get a lock for the tray icon -- keeps us from getting // duplicate icons in the tray if two enumerations are occurring // simultaneously // // Arguments: // pguid [in] Item for which to set the lock // // Returns: S_OK if the lock could be set. S_FALSE otherwise. // // Author: jeffspr 23 Oct 1998 // // Notes: // HRESULT HrGetTrayIconLock( IN const GUID * pguid, OUT UINT * puiIcon, OUT LPDWORD pdwLockingThreadId) { HRESULT hr = S_OK; ConnListEntry cle; Assert(pguid); // Otherwise, use the guid from the pidl // TraceTag(ttidSystray, "Acquiring Tray icon lock"); g_ccl.AcquireWriteLock(); hr = g_ccl.HrFindConnectionByGuid(pguid, cle); if (S_OK == hr) { if (cle.dwState & CLEF_TRAY_ICON_LOCKED) { hr = S_FALSE; #ifdef DBG // if (pdwLockingThreadId) { Assert(cle.dwLockingThreadId); *pdwLockingThreadId = cle.dwLockingThreadId; } #endif } else { cle.dwState |= CLEF_TRAY_ICON_LOCKED; #ifdef DBG cle.dwLockingThreadId = GetCurrentThreadId(); #endif if (puiIcon) { if (cle.HasTrayIconData()) { *puiIcon = cle.GetTrayIconData()->GetTrayIconId(); } else { *puiIcon = BOGUS_TRAY_ICON_ID; } } g_ccl.HrUpdateConnectionByGuid(pguid, cle); Assert(cle.dwLockingThreadId); } } else { hr = E_FILE_NOT_FOUND; } g_ccl.ReleaseWriteLock(); TraceHr(ttidError, FAL, hr, (S_FALSE == hr), "HrGetTrayIconLock"); return hr; } //+--------------------------------------------------------------------------- // // Function: ReleaseTrayIconLock // // Purpose: Release a lock (if held) on a particular tray icon // // Arguments: // pguid [in] Item for which to release the lock // // Returns: // // Author: jeffspr 23 Oct 1998 // // Notes: // VOID ReleaseTrayIconLock( IN const GUID * pguid) throw() { HRESULT hr = S_OK; ConnListEntry cle; g_ccl.AcquireWriteLock(); Assert(pguid); hr = g_ccl.HrFindConnectionByGuid(pguid, cle); if (S_OK == hr) { // Ignore whether or not this flag has already been removed. // cle.dwState &= ~CLEF_TRAY_ICON_LOCKED; #ifdef DBG cle.dwLockingThreadId = 0; #endif g_ccl.HrUpdateConnectionByGuid(pguid, cle); } g_ccl.ReleaseWriteLock(); TraceTag(ttidSystray, "Releasing Tray icon lock"); TraceHr(ttidError, FAL, hr, (S_FALSE == hr), "ReleaseTrayIconLock"); } ConnListEntry::ConnListEntry() throw() : dwState(0), m_pTrayIconData(NULL), pctmd(NULL), pcbi(NULL) { TraceFileFunc(ttidConnectionList); m_CreationTime = GetTickCount(); #ifdef DBG dwLockingThreadId = 0; #endif } ConnListEntry::ConnListEntry(const ConnListEntry& ConnectionListEntry) throw() { TraceFileFunc(ttidConnectionList); #ifdef DBG dwLockingThreadId = ConnectionListEntry.dwLockingThreadId; #endif m_CreationTime = ConnectionListEntry.m_CreationTime; dwState = ConnectionListEntry.dwState; ccfe = ConnectionListEntry.ccfe; if (ConnectionListEntry.HasTrayIconData()) { m_pTrayIconData = new CTrayIconData(*ConnectionListEntry.GetTrayIconData()); } else { m_pTrayIconData = NULL; } pctmd = ConnectionListEntry.pctmd; pcbi = ConnectionListEntry.pcbi; } ConnListEntry& ConnListEntry::operator =(const ConnListEntry& ConnectionListEntry) { TraceFileFunc(ttidConnectionList); m_CreationTime = ConnectionListEntry.m_CreationTime; #ifdef DBG dwLockingThreadId = ConnectionListEntry.dwLockingThreadId; #endif dwState = ConnectionListEntry.dwState; ccfe = ConnectionListEntry.ccfe; if (ConnectionListEntry.HasTrayIconData()) { if (m_pTrayIconData) { delete m_pTrayIconData; m_pTrayIconData = NULL; } m_pTrayIconData = new CTrayIconData(*ConnectionListEntry.GetTrayIconData()); } else { if (m_pTrayIconData) { delete m_pTrayIconData; m_pTrayIconData = NULL; } else { m_pTrayIconData = NULL; } } pctmd = ConnectionListEntry.pctmd; pcbi = ConnectionListEntry.pcbi; return *this; } ConnListEntry::~ConnListEntry() { TraceFileFunc(ttidConnectionList); delete m_pTrayIconData; m_pTrayIconData = NULL; } void CConnectionList::AcquireWriteLock() throw() { EnterCriticalSection(&m_csWriteLock); #ifdef DBG m_dwWriteLockRef++; TraceTag(ttidConnectionList, "CConnectionList::AcquireWriteLock (%d)", m_dwWriteLockRef); #endif } void CConnectionList::ReleaseWriteLock() throw() { #ifdef DBG m_dwWriteLockRef--; TraceTag(ttidConnectionList, "CConnectionList::ReleaseWriteLock (%d)", m_dwWriteLockRef); #endif LeaveCriticalSection(&m_csWriteLock); }