|
|
//+---------------------------------------------------------------------------
//
// 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<LPCSTR>(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<LPCSTR>(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<CConnectionList *>(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<WPARAM>(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<INetConnectionManager2> 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<LPVOID>(&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<VOID**>(&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 <foo>" 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 <foo>" 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); }
|