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.
787 lines
24 KiB
787 lines
24 KiB
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1997.
|
|
//
|
|
// File: N O T I F Y . C P P
|
|
//
|
|
// Contents: Implementation of INetConnectionNotifySink
|
|
//
|
|
// Notes:
|
|
//
|
|
// Author: shaunco 21 Aug 1998
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include "pch.h"
|
|
#pragma hdrstop
|
|
#include "foldinc.h"
|
|
#include "nccom.h"
|
|
#include "notify.h"
|
|
#include "shutil.h"
|
|
#include "smcent.h"
|
|
#include "ctrayui.h"
|
|
#include "traymsgs.h"
|
|
#include "wzcdlg.h"
|
|
|
|
extern HWND g_hwndTray;
|
|
|
|
enum EVENT_LEVELS
|
|
{
|
|
EVT_LVL_DISABLE_ALL = 0,
|
|
EVT_LVL_ENABLE_PRIVATE = 1,
|
|
EVT_LVL_ENABLE_ALL = 2
|
|
};
|
|
|
|
DWORD g_dwCurrentEventLevel = EVT_LVL_ENABLE_ALL;
|
|
|
|
//static
|
|
HRESULT
|
|
CConnectionNotifySink::CreateInstance (
|
|
IN REFIID riid,
|
|
OUT VOID** ppv)
|
|
{
|
|
TraceFileFunc(ttidNotifySink);
|
|
|
|
HRESULT hr = E_OUTOFMEMORY;
|
|
|
|
// Initialize the output parameter.
|
|
//
|
|
*ppv = NULL;
|
|
|
|
CConnectionNotifySink* pObj;
|
|
pObj = new CComObject <CConnectionNotifySink>;
|
|
if (pObj)
|
|
{
|
|
// Do the standard CComCreator::CreateInstance stuff.
|
|
//
|
|
pObj->SetVoid (NULL);
|
|
pObj->InternalFinalConstructAddRef ();
|
|
hr = pObj->FinalConstruct ();
|
|
pObj->InternalFinalConstructRelease ();
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// Call the PidlInitialize function to allow the enumeration
|
|
// object to copy the list.
|
|
//
|
|
hr = HrGetConnectionsFolderPidl(pObj->m_pidlFolder);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pObj->QueryInterface (riid, ppv);
|
|
}
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
delete pObj;
|
|
}
|
|
}
|
|
|
|
TraceHr(ttidError, FAL, hr, (S_FALSE == hr), "CConnectionNotifySink::CreateInstance");
|
|
return hr;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CConnectionNotifySink::~CConnectionNotifySink
|
|
//
|
|
// Purpose: Clean up the sink object, deleting the folder pidl and any
|
|
// alloc'd junk we might add in the future.
|
|
//
|
|
// Arguments:
|
|
// (none)
|
|
//
|
|
// Returns:
|
|
//
|
|
// Author: jeffspr 26 Aug 1998
|
|
//
|
|
// Notes:
|
|
//
|
|
CConnectionNotifySink::~CConnectionNotifySink() throw()
|
|
{
|
|
TraceFileFunc(ttidNotifySink);
|
|
|
|
if (FIsDebugFlagSet (dfidBreakOnNotifySinkRelease))
|
|
{
|
|
AssertSz(FALSE, "THIS IS NOT A BUG! The debug flag "
|
|
"\"BreakOnNotifySinkRelease\" has been set. Set your breakpoints now.");
|
|
}
|
|
|
|
TraceTag(ttidNotifySink, "Connection notify sink destroyed");
|
|
}
|
|
|
|
HRESULT CConnectionNotifySink::HrUpdateIncomingConnection()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
ConnListEntry cle;
|
|
hr = g_ccl.HrFindRasServerConnection(cle);
|
|
if (S_OK == hr)
|
|
{
|
|
hr = HrOnNotifyUpdateConnection(
|
|
m_pidlFolder,
|
|
&(cle.ccfe.GetGuidID()),
|
|
cle.ccfe.GetNetConMediaType(),
|
|
cle.ccfe.GetNetConSubMediaType(),
|
|
cle.ccfe.GetNetConStatus(),
|
|
cle.ccfe.GetCharacteristics(),
|
|
cle.ccfe.GetName(),
|
|
cle.ccfe.GetDeviceName(),
|
|
cle.ccfe.GetPhoneOrHostAddress()
|
|
);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
PCONFOLDPIDL pidlShellNotify;
|
|
hr = cle.ccfe.ConvertToPidl(pidlShellNotify);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
GenerateEvent(SHCNE_UPDATEITEM, m_pidlFolder, pidlShellNotify, NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT
|
|
CConnectionNotifySink::ConnectionAdded (
|
|
IN const NETCON_PROPERTIES_EX* pPropsEx)
|
|
{
|
|
TraceFileFunc(ttidNotifySink);
|
|
|
|
#ifdef DBG
|
|
OLECHAR szGuidString[MAX_GUID_STRING_LEN];
|
|
StringFromGUID2(pPropsEx->guidId, szGuidString, MAX_GUID_STRING_LEN);
|
|
TraceTag(ttidNotifySink, "INetConnectionNotifySink::ConnectionAdded - %S %S [%s:%s:%s:%s]",
|
|
szGuidString, pPropsEx->bstrName, DbgNcm(pPropsEx->ncMediaType), DbgNcsm(pPropsEx->ncSubMediaType), DbgNcs(pPropsEx->ncStatus), DbgNccf(pPropsEx->dwCharacter) );
|
|
#endif
|
|
if (g_dwCurrentEventLevel <= EVT_LVL_DISABLE_ALL)
|
|
{
|
|
TraceTag(ttidNotifySink, "Last event ignored due to g_dwCurrentEventLevel == %d", g_dwCurrentEventLevel);
|
|
return S_FALSE;
|
|
}
|
|
|
|
HRESULT hr = S_OK; // Only used for code paths. We don't return this.
|
|
HRESULT hrFind = S_OK; // Only for finding the connection.
|
|
PCONFOLDPIDL pidlNew;
|
|
|
|
ConnListEntry cleDontCare;
|
|
hrFind = g_ccl.HrFindConnectionByGuid(&(pPropsEx->guidId), cleDontCare);
|
|
if (S_OK == hrFind)
|
|
{
|
|
// We already know about this connection. Don't bother added it.
|
|
TraceTag(ttidShellFolder, "Ignoring known connection on ConnectionAdded notify");
|
|
}
|
|
else
|
|
{
|
|
// Create the entry in the connection list and get the returned pidl
|
|
//
|
|
hr = HrCreateConFoldPidl(
|
|
*pPropsEx,
|
|
pidlNew);
|
|
if (SUCCEEDED(hr) && (!pidlNew.empty()))
|
|
{
|
|
CONFOLDENTRY cfe;
|
|
|
|
Assert(!m_pidlFolder.empty());
|
|
|
|
// Convert to the confoldentry
|
|
//
|
|
hr = pidlNew.ConvertToConFoldEntry(cfe);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// Insert the connection in the connection list
|
|
//
|
|
hr = g_ccl.HrInsert(cfe);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// Notify the shell that we have a new object
|
|
//
|
|
PCONFOLDPIDL pidlShellNotify;
|
|
hr = cfe.ConvertToPidl(pidlShellNotify);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
GenerateEvent(SHCNE_CREATE, m_pidlFolder, pidlShellNotify, NULL);
|
|
}
|
|
}
|
|
|
|
// Don't delete the cfe here because the connection list now owns it.
|
|
}
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hr) &&
|
|
(NCM_NONE != pPropsEx->ncMediaType) &&
|
|
(pPropsEx->dwCharacter & NCCF_INCOMING_ONLY) )
|
|
{
|
|
hr = HrUpdateIncomingConnection();
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT
|
|
CConnectionNotifySink::ConnectionBandWidthChange (
|
|
IN const GUID* pguidId)
|
|
{
|
|
TraceFileFunc(ttidNotifySink);
|
|
#ifdef DBG
|
|
OLECHAR szGuidString[MAX_GUID_STRING_LEN];
|
|
StringFromGUID2(*pguidId, szGuidString, MAX_GUID_STRING_LEN);
|
|
TraceTag(ttidNotifySink, "INetConnectionNotifySink::ConnectionBandWidthChange - %S", szGuidString);
|
|
#endif
|
|
if (g_dwCurrentEventLevel <= EVT_LVL_DISABLE_ALL)
|
|
{
|
|
TraceTag(ttidNotifySink, "Last event ignored due to g_dwCurrentEventLevel == %d", g_dwCurrentEventLevel);
|
|
return S_FALSE;
|
|
}
|
|
|
|
HRESULT hr = S_OK;
|
|
CNetStatisticsCentral * pnsc = NULL;
|
|
|
|
hr = CNetStatisticsCentral::HrGetNetStatisticsCentral(&pnsc, FALSE);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
pnsc->UpdateRasLinkList(pguidId);
|
|
ReleaseObj(pnsc);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CConnectionNotifySink::ConnectionDeleted (
|
|
IN const GUID* pguidId)
|
|
{
|
|
TraceFileFunc(ttidNotifySink);
|
|
|
|
HRESULT hr = S_OK;
|
|
HRESULT hrFind = S_OK;
|
|
ConnListEntry cle;
|
|
PCONFOLDPIDL pidlFind;
|
|
BOOL fFlushPosts = FALSE;
|
|
|
|
Assert(pguidId);
|
|
Assert(!m_pidlFolder.empty());
|
|
|
|
if (g_dwCurrentEventLevel <= EVT_LVL_DISABLE_ALL)
|
|
{
|
|
TraceTag(ttidNotifySink, "CConnectionNotifySink::ConnectionDeleted event ignored due to g_dwCurrentEventLevel == %d", g_dwCurrentEventLevel);
|
|
return S_FALSE;
|
|
}
|
|
|
|
// Find the connection using the GUID.
|
|
//
|
|
hrFind = g_ccl.HrFindConnectionByGuid(pguidId, cle);
|
|
if (S_OK == hrFind)
|
|
{
|
|
#ifdef DBG
|
|
OLECHAR szGuidString[MAX_GUID_STRING_LEN];
|
|
StringFromGUID2(cle.ccfe.GetGuidID(), szGuidString, MAX_GUID_STRING_LEN);
|
|
TraceTag(ttidNotifySink, "INetConnectionNotifySink::ConnectionDeleted - %S %S [%s:%s:%s:%s]", szGuidString, cle.ccfe.GetName(),
|
|
DbgNcm(cle.ccfe.GetNetConMediaType()), DbgNcsm(cle.ccfe.GetNetConSubMediaType()), DbgNcs(cle.ccfe.GetNetConStatus()), DbgNccf(cle.ccfe.GetCharacteristics()));
|
|
#endif
|
|
// Very important to release the lock before doing any thing which
|
|
// calls back into the shell. (e.g. GenerateEvent)
|
|
|
|
const CONFOLDENTRY &ccfe = cle.ccfe;
|
|
|
|
// Get the pidl for the connection so we can use it to notify
|
|
// the shell further below.
|
|
//
|
|
ccfe.ConvertToPidl(pidlFind);
|
|
|
|
// Remove this connection from the global list while we
|
|
// have the lock held.
|
|
//
|
|
hr = g_ccl.HrRemove(cle.ccfe, &fFlushPosts);
|
|
}
|
|
else
|
|
{
|
|
TraceTag(ttidShellFolder, "Notify: Delete <item not found in cache>. hr = 0x%08x", hr);
|
|
}
|
|
|
|
|
|
// If we need to flush the posts after making tray icon changes, do so
|
|
//
|
|
if (g_hwndTray && fFlushPosts)
|
|
{
|
|
FlushTrayPosts(g_hwndTray);
|
|
}
|
|
|
|
if (SUCCEEDED(hr) && (!pidlFind.empty()))
|
|
{
|
|
GenerateEvent(SHCNE_DELETE, m_pidlFolder, pidlFind, NULL);
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = HrUpdateIncomingConnection();
|
|
}
|
|
|
|
// Only return S_OK from here.
|
|
//
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT
|
|
CConnectionNotifySink::ConnectionModified (
|
|
IN const NETCON_PROPERTIES_EX* pPropsEx)
|
|
{
|
|
TraceFileFunc(ttidNotifySink);
|
|
|
|
Assert(pPropsEx);
|
|
Assert(!m_pidlFolder.empty());
|
|
|
|
#ifdef DBG
|
|
OLECHAR szGuidString[MAX_GUID_STRING_LEN];
|
|
StringFromGUID2(pPropsEx->guidId, szGuidString, MAX_GUID_STRING_LEN);
|
|
TraceTag(ttidNotifySink, "INetConnectionNotifySink::ConnectionModified - %S %S [%s:%s:%s:%s]", szGuidString, pPropsEx->bstrName,
|
|
DbgNcm(pPropsEx->ncMediaType), DbgNcsm(pPropsEx->ncSubMediaType), DbgNcs(pPropsEx->ncStatus), DbgNccf(pPropsEx->dwCharacter));
|
|
#endif
|
|
|
|
if (g_dwCurrentEventLevel <= EVT_LVL_ENABLE_PRIVATE)
|
|
{
|
|
TraceTag(ttidNotifySink, "Last event ignored due to g_dwCurrentEventLevel == %d", g_dwCurrentEventLevel);
|
|
return S_FALSE;
|
|
}
|
|
|
|
// Get the result for debugging only. We never want to fail this function
|
|
//
|
|
HRESULT hrTmp = HrOnNotifyUpdateConnection(
|
|
m_pidlFolder,
|
|
(GUID *)&(pPropsEx->guidId),
|
|
pPropsEx->ncMediaType,
|
|
pPropsEx->ncSubMediaType,
|
|
pPropsEx->ncStatus,
|
|
pPropsEx->dwCharacter,
|
|
pPropsEx->bstrName,
|
|
pPropsEx->bstrDeviceName,
|
|
pPropsEx->bstrPhoneOrHostAddress);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CConnectionNotifySink::ConnectionRenamed (
|
|
IN const GUID* pguidId,
|
|
IN PCWSTR pszwNewName)
|
|
{
|
|
TraceFileFunc(ttidNotifySink);
|
|
|
|
HRESULT hr = S_OK;
|
|
PCONFOLDPIDL pidlNew;
|
|
|
|
Assert(pguidId);
|
|
Assert(pszwNewName);
|
|
|
|
if (g_dwCurrentEventLevel <= EVT_LVL_DISABLE_ALL)
|
|
{
|
|
TraceTag(ttidNotifySink, "CConnectionNotifySink::ConnectionRenamed event ignored due to g_dwCurrentEventLevel == %d", g_dwCurrentEventLevel);
|
|
return S_FALSE;
|
|
}
|
|
|
|
// Update the name in the cache
|
|
//
|
|
|
|
// Note: There exists a race condition with shutil.cpp:
|
|
// HrRenameConnectionInternal\HrUpdateNameByGuid can also update the cache.
|
|
ConnListEntry cle;
|
|
hr = g_ccl.HrFindConnectionByGuid(pguidId, cle);
|
|
if (FAILED(hr))
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
#ifdef DBG
|
|
OLECHAR szGuidString[MAX_GUID_STRING_LEN];
|
|
StringFromGUID2(cle.ccfe.GetGuidID(), szGuidString, MAX_GUID_STRING_LEN);
|
|
TraceTag(ttidNotifySink, "INetConnectionNotifySink::ConnectionRenamed - %S %S (to %S) [%s:%s:%s:%s]", szGuidString, cle.ccfe.GetName(), pszwNewName,
|
|
DbgNcm(cle.ccfe.GetNetConMediaType()), DbgNcsm(cle.ccfe.GetNetConSubMediaType()), DbgNcs(cle.ccfe.GetNetConStatus()), DbgNccf(cle.ccfe.GetCharacteristics()));
|
|
#endif
|
|
|
|
hr = g_ccl.HrUpdateNameByGuid(
|
|
(GUID *) pguidId,
|
|
(PWSTR) pszwNewName,
|
|
pidlNew,
|
|
TRUE); // Force the update -- this is a notification, not a request
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
PCONFOLDPIDL pidl;
|
|
cle.ccfe.ConvertToPidl(pidl);
|
|
|
|
GenerateEvent(
|
|
SHCNE_RENAMEITEM,
|
|
m_pidlFolder,
|
|
pidl,
|
|
pidlNew.GetItemIdList());
|
|
|
|
// Update status monitor title (RAS case)
|
|
CNetStatisticsCentral * pnsc = NULL;
|
|
|
|
hr = CNetStatisticsCentral::HrGetNetStatisticsCentral(&pnsc, FALSE);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
pnsc->UpdateTitle(pguidId, pszwNewName);
|
|
ReleaseObj(pnsc);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// If the connection wasn't found in the cache, then it's likely that
|
|
// the notification engine is giving us a notification for a connection
|
|
// that hasn't yet been given to us.
|
|
//
|
|
if (S_FALSE == hr)
|
|
{
|
|
TraceHr(ttidShellFolder, FAL, hr, FALSE, "Rename notification received on a connection we don't know about");
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT
|
|
CConnectionNotifySink::ConnectionStatusChange (
|
|
IN const GUID* pguidId,
|
|
IN NETCON_STATUS Status)
|
|
{
|
|
TraceFileFunc(ttidNotifySink);
|
|
|
|
HRESULT hr = S_OK;
|
|
HRESULT hrFind = S_OK;
|
|
PCONFOLDPIDL pidlFind;
|
|
|
|
if (g_dwCurrentEventLevel <= EVT_LVL_ENABLE_PRIVATE)
|
|
{
|
|
TraceTag(ttidNotifySink, "CConnectionNotifySink::ConnectionStatusChange event ignored due to g_dwCurrentEventLevel == %d", g_dwCurrentEventLevel);
|
|
return S_FALSE;
|
|
}
|
|
|
|
// Find the connection using the GUID. Cast the const away from the GUID
|
|
//
|
|
hrFind = g_ccl.HrFindPidlByGuid((GUID *) pguidId, pidlFind);
|
|
|
|
if( S_OK != hrFind )
|
|
{
|
|
GUID guidOwner;
|
|
|
|
// We did not find the guid in connection folder. Try finding the connection in the
|
|
// hidden connectiod list on netmans side.
|
|
//
|
|
hr = g_ccl.HrMapCMHiddenConnectionToOwner(*pguidId, &guidOwner);
|
|
if (S_OK == hr)
|
|
{
|
|
// The conection has a parent!!!! Use the childs status instead of the parents status.
|
|
//
|
|
if (Status == NCS_CONNECTED)
|
|
{
|
|
// This means that the child has connected and the parent still has to connect
|
|
// the overall status should stay as connected. This was done to overrule the Multi-link
|
|
// hack in HrOnNotifyUpdateStatus. If we did not do this it would say :
|
|
// Child( Connecting, Connected) and then Parent(Connecting, Connected)
|
|
//
|
|
Status = NCS_CONNECTING;
|
|
}
|
|
|
|
// Get the pidl of the parent.
|
|
//
|
|
hrFind = g_ccl.HrFindPidlByGuid(&guidOwner, pidlFind);
|
|
}
|
|
}
|
|
|
|
if (S_OK == hrFind)
|
|
{
|
|
#ifdef DBG
|
|
OLECHAR szGuidString[MAX_GUID_STRING_LEN];
|
|
StringFromGUID2(pidlFind->guidId, szGuidString, MAX_GUID_STRING_LEN);
|
|
TraceTag(ttidNotifySink, "INetConnectionNotifySink::ConnectionStatusChange - %S %S [%s:%s:%s:%s]", szGuidString, pidlFind->PszGetNamePointer(),
|
|
DbgNcm(pidlFind->ncm), DbgNcsm(pidlFind->ncsm), DbgNcs(Status), DbgNccf(pidlFind->dwCharacteristics));
|
|
#endif
|
|
hr = HrOnNotifyUpdateStatus(m_pidlFolder, pidlFind, Status);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT
|
|
CConnectionNotifySink::RefreshAll ()
|
|
{
|
|
TraceFileFunc(ttidNotifySink);
|
|
|
|
#ifdef DBG
|
|
TraceTag(ttidNotifySink, "INetConnectionNotifySink::RefreshAll");
|
|
#endif
|
|
|
|
if (g_dwCurrentEventLevel <= EVT_LVL_DISABLE_ALL)
|
|
{
|
|
TraceTag(ttidNotifySink, "Last event ignored due to g_dwCurrentEventLevel == %d", g_dwCurrentEventLevel);
|
|
return S_FALSE;
|
|
}
|
|
|
|
// Refresh the connections folder, without having to hook the shell view.
|
|
// In this case, we do a non-flush refresh where we compare the new set
|
|
// of items to the cached set and do the merge (with the correct set
|
|
// of individual notifications).
|
|
//
|
|
(VOID) HrForceRefreshNoFlush(m_pidlFolder);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CConnectionNotifySink::ConnectionAddressChange (
|
|
IN const GUID* pguidId )
|
|
{
|
|
// Find the connection using the GUID.
|
|
//
|
|
PCONFOLDPIDL pidlFind;
|
|
HRESULT hr = g_ccl.HrFindPidlByGuid(pguidId, pidlFind);
|
|
if (S_OK != hr)
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
#ifdef DBG
|
|
OLECHAR szGuidString[MAX_GUID_STRING_LEN];
|
|
StringFromGUID2(pidlFind->guidId, szGuidString, MAX_GUID_STRING_LEN);
|
|
TraceTag(ttidNotifySink, "INetConnectionNotifySink::ConnectionAddressChange - %S %S [%s:%s:%s:%s]", szGuidString, pidlFind->PszGetNamePointer(),
|
|
DbgNcm(pidlFind->ncm), DbgNcsm(pidlFind->ncsm), DbgNcs(pidlFind->ncs), DbgNccf(pidlFind->dwCharacteristics));
|
|
|
|
#endif
|
|
if (g_dwCurrentEventLevel <= EVT_LVL_DISABLE_ALL)
|
|
{
|
|
TraceTag(ttidNotifySink, "Last event ignored due to g_dwCurrentEventLevel == %d", g_dwCurrentEventLevel);
|
|
return S_FALSE;
|
|
}
|
|
|
|
PCONFOLDPIDLFOLDER pidlFolder;
|
|
hr = HrGetConnectionsFolderPidl(pidlFolder);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
GenerateEvent(SHCNE_UPDATEITEM, pidlFolder, pidlFind, NULL);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
DWORD WINAPI OnTaskBarIconBalloonClickThread(IN LPVOID lpParam);
|
|
|
|
STDMETHODIMP CConnectionNotifySink::ShowBalloon(
|
|
IN const GUID* pguidId,
|
|
IN const BSTR szCookie,
|
|
IN const BSTR szBalloonText)
|
|
{
|
|
HRESULT hr;
|
|
|
|
#ifdef DBG
|
|
OLECHAR szGuidString[MAX_GUID_STRING_LEN];
|
|
StringFromGUID2(*pguidId, szGuidString, MAX_GUID_STRING_LEN);
|
|
TraceTag(ttidNotifySink, "INetConnectionNotifySink::ShowBalloon - %S (%S)", szGuidString, szBalloonText);
|
|
#endif
|
|
|
|
if (g_dwCurrentEventLevel <= EVT_LVL_DISABLE_ALL)
|
|
{
|
|
TraceTag(ttidNotifySink, "Last event ignored due to g_dwCurrentEventLevel == %d", g_dwCurrentEventLevel);
|
|
return S_FALSE;
|
|
}
|
|
|
|
CComBSTR szBalloonTextTmp = szBalloonText;
|
|
BSTR szCookieTmp = NULL;
|
|
|
|
if (szCookie)
|
|
{
|
|
szCookieTmp = SysAllocStringByteLen(reinterpret_cast<LPCSTR>(szCookie), SysStringByteLen(szCookie));
|
|
|
|
if (szCookieTmp)
|
|
{
|
|
ConnListEntry cleFind;
|
|
hr = g_ccl.HrFindConnectionByGuid(pguidId, cleFind);
|
|
if (S_OK == hr)
|
|
{
|
|
hr = WZCCanShowBalloon(pguidId, cleFind.ccfe.GetName(), &szBalloonTextTmp, &szCookieTmp);
|
|
if ( (S_OK == hr) || (S_OBJECT_NO_LONGER_VALID == hr) )
|
|
{
|
|
CTrayBalloon *pTrayBalloon = new CTrayBalloon();
|
|
if (!pTrayBalloon)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
else
|
|
{
|
|
pTrayBalloon->m_gdGuid = *pguidId;
|
|
pTrayBalloon->m_dwTimeOut = 30 * 1000;
|
|
pTrayBalloon->m_szMessage = szBalloonTextTmp;
|
|
pTrayBalloon->m_pfnFuncCallback = WZCOnBalloonClick;
|
|
pTrayBalloon->m_szCookie = szCookieTmp;
|
|
pTrayBalloon->m_szAdapterName = cleFind.ccfe.GetName();
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
PostMessage(g_hwndTray, MYWM_SHOWBALLOON,
|
|
NULL,
|
|
(LPARAM) pTrayBalloon);
|
|
}
|
|
else // S_OBJECT_NO_LONGER_VALID == hr
|
|
{
|
|
CreateThread(NULL, STACK_SIZE_SMALL, OnTaskBarIconBalloonClickThread, pTrayBalloon, 0, NULL);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (S_OK != hr && S_OBJECT_NO_LONGER_VALID != hr)
|
|
{
|
|
SysFreeString(szCookieTmp);
|
|
}
|
|
}
|
|
}
|
|
|
|
TraceHr(ttidError, FAL, hr, FALSE,
|
|
"CConnectionNotifySink::ShowBalloon");
|
|
|
|
return hr;
|
|
}
|
|
|
|
UINT_PTR uipTimer = NULL;
|
|
|
|
VOID CALLBACK EventTimerProc(
|
|
IN HWND hwnd, // handle to window
|
|
IN UINT uMsg, // WM_TIMER message
|
|
IN UINT_PTR idEvent, // timer identifier
|
|
IN DWORD dwTime // current system time
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
TraceTag(ttidNotifySink, "Refreshing the folder due to DisableEvents timeout reached");
|
|
|
|
g_dwCurrentEventLevel = EVT_LVL_ENABLE_ALL;
|
|
if (uipTimer)
|
|
{
|
|
KillTimer(NULL, uipTimer);
|
|
uipTimer = NULL;
|
|
}
|
|
|
|
PCONFOLDPIDLFOLDER pcfpFolder;
|
|
hr = HrGetConnectionsFolderPidl(pcfpFolder);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
HrForceRefreshNoFlush(pcfpFolder);
|
|
}
|
|
}
|
|
|
|
STDMETHODIMP CConnectionNotifySink::DisableEvents (
|
|
IN const BOOL fDisable,
|
|
IN const ULONG ulDisableTimeout)
|
|
{
|
|
#ifdef DBG
|
|
TraceTag(ttidNotifySink, "INetConnectionNotifySink::DisableEvents - %s 0x%08x", fDisable ? "DISABLE" : "ENABLE", ulDisableTimeout);
|
|
#endif
|
|
HRESULT hr = S_OK;
|
|
|
|
if (fDisable)
|
|
{
|
|
if (HIWORD(ulDisableTimeout) & 0x8000)
|
|
{
|
|
// Called from private interface - disable all the events
|
|
g_dwCurrentEventLevel = EVT_LVL_DISABLE_ALL;
|
|
}
|
|
else
|
|
{
|
|
// Called from public interface - only disable connection modified & status change events
|
|
g_dwCurrentEventLevel = EVT_LVL_ENABLE_PRIVATE;
|
|
}
|
|
|
|
UINT uiEventTimeOut = LOWORD(ulDisableTimeout);
|
|
if (uipTimer)
|
|
{
|
|
KillTimer(NULL, uipTimer);
|
|
uipTimer = NULL;
|
|
}
|
|
|
|
uipTimer = SetTimer(NULL, NULL, uiEventTimeOut, EventTimerProc);
|
|
}
|
|
else
|
|
{
|
|
g_dwCurrentEventLevel = EVT_LVL_ENABLE_ALL;
|
|
|
|
if (uipTimer)
|
|
{
|
|
KillTimer(NULL, uipTimer);
|
|
uipTimer = NULL;
|
|
}
|
|
else
|
|
{
|
|
hr = S_FALSE; // Timer no more.
|
|
}
|
|
|
|
HrForceRefreshNoFlush(m_pidlFolder);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: HrGetNotifyConPoint
|
|
//
|
|
// Purpose: Common code for getting the connection point for use in
|
|
// NotifyAdd and NotifyRemove
|
|
//
|
|
// Arguments:
|
|
// ppConPoint [out] Return ptr for IConnectionPoint
|
|
//
|
|
// Returns:
|
|
//
|
|
// Author: jeffspr 24 Aug 1998
|
|
//
|
|
// Notes:
|
|
//
|
|
HRESULT HrGetNotifyConPoint(
|
|
IConnectionPoint ** ppConPoint)
|
|
{
|
|
TraceFileFunc(ttidNotifySink);
|
|
|
|
HRESULT hr = S_OK;
|
|
IConnectionPointContainer * pContainer = NULL;
|
|
|
|
Assert(ppConPoint);
|
|
|
|
// Get the debug interface from the connection manager
|
|
//
|
|
hr = HrCreateInstance(
|
|
CLSID_ConnectionManager,
|
|
CLSCTX_LOCAL_SERVER | CLSCTX_NO_CODE_DOWNLOAD,
|
|
&pContainer);
|
|
|
|
TraceHr(ttidError, FAL, hr, FALSE,
|
|
"HrCreateInstance(CLSID_ConnectionManager) for IConnectionPointContainer");
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
IConnectionPoint * pConPoint = NULL;
|
|
|
|
// Get the connection point itself and fill in the return param
|
|
// on success
|
|
//
|
|
hr = pContainer->FindConnectionPoint(
|
|
IID_INetConnectionNotifySink,
|
|
&pConPoint);
|
|
|
|
TraceHr(ttidError, FAL, hr, FALSE, "pContainer->FindConnectionPoint");
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
NcSetProxyBlanket (pConPoint);
|
|
*ppConPoint = pConPoint;
|
|
}
|
|
|
|
ReleaseObj(pContainer);
|
|
}
|
|
|
|
TraceHr(ttidError, FAL, hr, FALSE, "HrGetNotifyConPoint");
|
|
return hr;
|
|
}
|