You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3040 lines
87 KiB
3040 lines
87 KiB
//+---------------------------------------------------------------------------
|
|
//
|
|
// 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);
|
|
}
|