1400 lines
39 KiB
C++
1400 lines
39 KiB
C++
//----------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1997
|
|
//
|
|
// File: trayagnt.cpp
|
|
//
|
|
// Contents: tray notification agent
|
|
//
|
|
// Classes:
|
|
//
|
|
// Functions:
|
|
//
|
|
// History: 01-14-1997 rayen (Raymond Endres) Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
#include "private.h"
|
|
#include "updateui.h"
|
|
#include "chanmgr.h"
|
|
#include "chanmgrp.h"
|
|
#include "shguidp.h"
|
|
#include "offline.h"
|
|
#include "offl_cpp.h"
|
|
|
|
//xnotfmgr - can probably nuke most of this file
|
|
|
|
#undef TF_THISMODULE
|
|
#define TF_THISMODULE TF_TRAYAGENT
|
|
|
|
extern const TCHAR c_szTrayUI[] = TEXT("BogusClassName");
|
|
const TCHAR c_szTrayMenu[] = TEXT("TrayMenu");
|
|
|
|
#if WANT_REGISTRY_LOG
|
|
const TCHAR c_szLog[] = TEXT("\\Log");
|
|
const TCHAR c_szLogMaxIndex[] = TEXT("MaxIndex");
|
|
#endif
|
|
|
|
typedef struct _tagCHANNELIMAGEDATA
|
|
{
|
|
CHAR szPath[MAX_PATH];
|
|
CHAR szHash[MAX_PATH];
|
|
int iIndex;
|
|
UINT uFlags;
|
|
int iImageIndex;
|
|
} CHANNELIMAGEDATA, *PCHANNELIMAGEDATA;
|
|
|
|
|
|
CTrayUI *g_pTrayUI; // TrayUI object (not COM), separate from TrayAgent for now
|
|
|
|
DWORD WINAPI UpdateRequest(UINT idCmd, INotification *);
|
|
HRESULT UpdateNotifyReboot(void);
|
|
extern BOOL OnConnectedNotification(void);
|
|
extern BOOL OnDisconnectedNotification(void);
|
|
extern HRESULT LoadWithCookie(LPCTSTR, OOEBuf *, DWORD *, SUBSCRIPTIONCOOKIE *);
|
|
void DoReboot(void);
|
|
void IdleBegin(HWND hwnd);
|
|
void IdleEnd(void);
|
|
|
|
// Private message sent by Channel Screen Saver to
|
|
// periodically initiate relaunch of the screen saver.
|
|
#define WM_LOADSCREENSAVER (WM_USER+550)
|
|
extern BOOL ReloadChannelScreenSaver(); // from SSSEPROX.CPP
|
|
|
|
#ifdef DEBUG
|
|
extern INotificationSink * g_pOfflineTraySink;
|
|
HRESULT RunTest()
|
|
{
|
|
//xnotfmgr
|
|
|
|
INotificationMgr * pMgr = NULL;
|
|
INotification * pNotf = NULL;
|
|
HRESULT hr;
|
|
|
|
hr = GetNotificationMgr(&pMgr);
|
|
if (FAILED(hr) || !pMgr)
|
|
return E_FAIL;
|
|
|
|
hr = pMgr->CreateNotification(
|
|
NOTIFICATIONTYPE_AGENT_START,
|
|
0, NULL, &pNotf, 0);
|
|
|
|
if (SUCCEEDED(hr) && !pNotf)
|
|
hr = E_FAIL;
|
|
|
|
if (SUCCEEDED(hr))
|
|
hr = pMgr->DeliverNotification(pNotf, CLSID_WebCrawlerAgent,
|
|
DM_DELIVER_DEFAULT_PROCESS |
|
|
DM_THROTTLE_MODE |
|
|
DM_NEED_COMPLETIONREPORT
|
|
,g_pOfflineTraySink,0,0);
|
|
|
|
SAFERELEASE(pNotf);
|
|
SAFERELEASE(pMgr);
|
|
return hr;
|
|
}
|
|
#endif
|
|
|
|
HRESULT CancelAllDownloads()
|
|
{
|
|
//xnotfmgr
|
|
HRESULT hr = S_OK;
|
|
INotificationMgr * pMgr = NULL;
|
|
IEnumNotification * pRunEnum = NULL;
|
|
IEnumNotification * pThrEnum = NULL;
|
|
|
|
hr = GetNotificationMgr(&pMgr);
|
|
if (FAILED(hr)) {
|
|
return hr;
|
|
}
|
|
|
|
hr = pMgr->GetEnumNotification(EF_NOTIFICATION_INPROGRESS, &pRunEnum);
|
|
if (SUCCEEDED(hr)) {
|
|
hr = pMgr->GetEnumNotification(EF_NOTIFICATION_THROTTLED, &pThrEnum);
|
|
}
|
|
|
|
if (FAILED(hr)) {
|
|
SAFERELEASE(pRunEnum);
|
|
SAFERELEASE(pThrEnum);
|
|
SAFERELEASE(pMgr);
|
|
return hr;
|
|
}
|
|
|
|
INotification *pNotCancel = NULL;
|
|
hr = pMgr->CreateNotification(NOTIFICATIONTYPE_TASKS_ABORT,
|
|
(NOTIFICATIONFLAGS)0,
|
|
NULL,
|
|
&pNotCancel,
|
|
0);
|
|
|
|
if (FAILED(hr) || !pNotCancel){
|
|
SAFERELEASE(pMgr);
|
|
SAFERELEASE(pRunEnum);
|
|
SAFERELEASE(pThrEnum);
|
|
return E_FAIL;
|
|
}
|
|
|
|
NOTIFICATIONITEM item = {0};
|
|
ULONG cItems = 0;
|
|
item.cbSize = sizeof(NOTIFICATIONITEM);
|
|
|
|
hr = pThrEnum->Next(1, &item, &cItems);
|
|
while ( SUCCEEDED(hr) && cItems )
|
|
{
|
|
CLSID cookie;
|
|
BOOL bAbort = FALSE;
|
|
if (item.NotificationType == NOTIFICATIONTYPE_AGENT_START
|
|
// REVIEW big hack.
|
|
&& item.clsidDest != CLSID_ConnectionAgent)
|
|
{
|
|
bAbort = TRUE;
|
|
cookie = item.NotificationCookie;
|
|
}
|
|
SAFERELEASE(item.pNotification);
|
|
item.cbSize = sizeof(NOTIFICATIONITEM);
|
|
cItems = 0;
|
|
hr = pThrEnum->Next(1, &item, &cItems);
|
|
|
|
// REVIEW. If we put the following statement before
|
|
// the Next statement, we can delete the package and then break the
|
|
// enumerator.
|
|
if (bAbort) {
|
|
HRESULT hr1 = pMgr->DeliverReport(pNotCancel, &cookie, 0);
|
|
ASSERT(SUCCEEDED(hr1));
|
|
}
|
|
}
|
|
|
|
cItems = 0;
|
|
item.cbSize = sizeof(NOTIFICATIONITEM);
|
|
|
|
hr = pRunEnum->Next(1, &item, &cItems);
|
|
while ( SUCCEEDED(hr) && cItems )
|
|
{
|
|
CLSID cookie;
|
|
BOOL bAbort = FALSE;
|
|
if (item.NotificationType == NOTIFICATIONTYPE_AGENT_START
|
|
// REVIEW big hack.
|
|
&& item.clsidDest != CLSID_ConnectionAgent)
|
|
{
|
|
bAbort = TRUE;
|
|
cookie = item.NotificationCookie;
|
|
}
|
|
SAFERELEASE(item.pNotification);
|
|
item.cbSize = sizeof(NOTIFICATIONITEM);
|
|
cItems = 0;
|
|
hr = pRunEnum->Next(1, &item, &cItems);
|
|
|
|
// REVIEW. We don't seem to have the same problem. Just try to be
|
|
// cautious.
|
|
if (bAbort) {
|
|
HRESULT hr1 = pMgr->DeliverReport(pNotCancel, &cookie, 0);
|
|
ASSERT(SUCCEEDED(hr1));
|
|
}
|
|
}
|
|
|
|
SAFERELEASE(pMgr);
|
|
SAFERELEASE(pNotCancel);
|
|
SAFERELEASE(pRunEnum);
|
|
SAFERELEASE(pThrEnum);
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Get the path of channel containing the given URL.
|
|
//
|
|
|
|
HRESULT GetChannelPath(LPCSTR pszURL, LPTSTR pszPath, int cch,
|
|
IChannelMgrPriv** ppIChannelMgrPriv)
|
|
{
|
|
ASSERT(pszURL);
|
|
ASSERT(pszPath || 0 == cch);
|
|
ASSERT(ppIChannelMgrPriv);
|
|
|
|
HRESULT hr;
|
|
BOOL bCoinit = FALSE;
|
|
|
|
hr = CoCreateInstance(CLSID_ChannelMgr, NULL, CLSCTX_INPROC_SERVER,
|
|
IID_IChannelMgrPriv, (void**)ppIChannelMgrPriv);
|
|
|
|
if ((hr == CO_E_NOTINITIALIZED || hr == REGDB_E_IIDNOTREG) &&
|
|
SUCCEEDED(CoInitialize(NULL)))
|
|
{
|
|
bCoinit = TRUE;
|
|
hr = CoCreateInstance(CLSID_ChannelMgr, NULL, CLSCTX_INPROC_SERVER,
|
|
IID_IChannelMgrPriv, (void**)ppIChannelMgrPriv);
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
ASSERT(*ppIChannelMgrPriv);
|
|
|
|
IChannelMgr* pIChannelMgr;
|
|
|
|
hr = (*ppIChannelMgrPriv)->QueryInterface(IID_IChannelMgr,
|
|
(void**)&pIChannelMgr);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
ASSERT(pIChannelMgr);
|
|
|
|
WCHAR wszURL[INTERNET_MAX_URL_LENGTH];
|
|
MyStrToOleStrN(wszURL, ARRAYSIZE(wszURL), pszURL);
|
|
|
|
IEnumChannels* pIEnumChannels;
|
|
|
|
hr = pIChannelMgr->EnumChannels(CHANENUM_ALLFOLDERS | CHANENUM_PATH,
|
|
wszURL, &pIEnumChannels);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
ASSERT(pIEnumChannels);
|
|
|
|
CHANNELENUMINFO ci;
|
|
|
|
if (S_OK == pIEnumChannels->Next(1, &ci, NULL))
|
|
{
|
|
MyOleStrToStrN(pszPath, cch, ci.pszPath);
|
|
|
|
CoTaskMemFree(ci.pszPath);
|
|
}
|
|
else
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
pIEnumChannels->Release();
|
|
}
|
|
|
|
pIChannelMgr->Release();
|
|
}
|
|
|
|
}
|
|
|
|
if (bCoinit)
|
|
CoUninitialize();
|
|
|
|
ASSERT((SUCCEEDED(hr) && *ppIChannelMgrPriv) || FAILED(hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Update channel
|
|
//
|
|
|
|
HRESULT UpdateChannel(IChannelMgrPriv* pIChannelMgrPriv, LPCSTR pszURL)
|
|
{
|
|
ASSERT(pIChannelMgrPriv);
|
|
ASSERT(pszURL);
|
|
|
|
HRESULT hr;
|
|
|
|
IChannelMgr* pIChannelMgr;
|
|
|
|
hr = pIChannelMgrPriv->QueryInterface(IID_IChannelMgr,
|
|
(void**)&pIChannelMgr);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
ASSERT(pIChannelMgr);
|
|
|
|
WCHAR wszURL[INTERNET_MAX_URL_LENGTH];
|
|
MyStrToOleStrN(wszURL, ARRAYSIZE(wszURL), pszURL);
|
|
|
|
IEnumChannels* pIEnumChannels;
|
|
|
|
hr = pIChannelMgr->EnumChannels(CHANENUM_ALLFOLDERS | CHANENUM_PATH,
|
|
wszURL, &pIEnumChannels);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
ASSERT(pIEnumChannels);
|
|
|
|
CHANNELENUMINFO ci;
|
|
|
|
//
|
|
// Update all instances of this channel.
|
|
//
|
|
|
|
while (S_OK == pIEnumChannels->Next(1, &ci, NULL))
|
|
{
|
|
char szPath[MAX_PATH];
|
|
MyOleStrToStrN(szPath, ARRAYSIZE(szPath), ci.pszPath);
|
|
|
|
// Removed to give UPDATEIMAGE (gleams) a better chance.
|
|
//SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_PATH, (void*)szPath,
|
|
// NULL);
|
|
|
|
CoTaskMemFree(ci.pszPath);
|
|
}
|
|
|
|
pIEnumChannels->Release();
|
|
}
|
|
|
|
pIChannelMgr->Release();
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Gather data that will be used to update a channel image.
|
|
//
|
|
|
|
HRESULT PreUpdateChannelImage(IChannelMgrPriv* pIChannelMgrPriv,
|
|
CHANNELIMAGEDATA* pcid)
|
|
{
|
|
ASSERT(pcid);
|
|
ASSERT(pIChannelMgrPriv);
|
|
|
|
return (pIChannelMgrPriv)->PreUpdateChannelImage(pcid->szPath,
|
|
pcid->szHash,
|
|
&pcid->iIndex,
|
|
&pcid->uFlags,
|
|
&pcid->iImageIndex);
|
|
}
|
|
|
|
//
|
|
// Update a channel image.
|
|
//
|
|
|
|
HRESULT UpdateChannelImage(IChannelMgrPriv* pIChannelMgrPriv,
|
|
CHANNELIMAGEDATA* pcid)
|
|
{
|
|
ASSERT(pcid);
|
|
ASSERT(pIChannelMgrPriv);
|
|
|
|
WCHAR wszHash[MAX_PATH];
|
|
MyStrToOleStrN(wszHash, ARRAYSIZE(wszHash), pcid->szHash);
|
|
|
|
return pIChannelMgrPriv->UpdateChannelImage(wszHash, pcid->iIndex,
|
|
pcid->uFlags,
|
|
pcid->iImageIndex);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Tray Agent object
|
|
//----------------------------------------------------------------------------
|
|
|
|
CTrayAgent::CTrayAgent()
|
|
{
|
|
DBG("Creating CTrayAgent object");
|
|
|
|
//
|
|
// Maintain global count of objects in webcheck.dll
|
|
//
|
|
DllAddRef();
|
|
|
|
//
|
|
// Initialize object member variables
|
|
//
|
|
m_cRef = 1;
|
|
#ifdef DEBUG
|
|
m_AptThreadId = GetCurrentThreadId();
|
|
#endif
|
|
}
|
|
|
|
CTrayAgent::~CTrayAgent()
|
|
{
|
|
//
|
|
// Maintain global count of objects
|
|
//
|
|
DllRelease();
|
|
|
|
//
|
|
// Release/delete any resources
|
|
//
|
|
DBG("Destroyed CTrayAgent object");
|
|
}
|
|
|
|
//
|
|
// IUnknown members
|
|
//
|
|
|
|
STDMETHODIMP_(ULONG) CTrayAgent::AddRef(void)
|
|
{
|
|
return ++m_cRef;
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CTrayAgent::Release(void)
|
|
{
|
|
if( 0L != --m_cRef )
|
|
return m_cRef;
|
|
|
|
delete this;
|
|
return 0L;
|
|
}
|
|
|
|
STDMETHODIMP CTrayAgent::QueryInterface(REFIID riid, void ** ppv)
|
|
{
|
|
*ppv = NULL;
|
|
//xnotfmgr
|
|
|
|
//
|
|
// Currently just support INotificationSink
|
|
//
|
|
if ((IID_IUnknown == riid) ||
|
|
(IID_INotificationSink == riid))
|
|
{
|
|
*ppv = (INotificationSink *)this;
|
|
}
|
|
|
|
//
|
|
// Addref through the interface
|
|
//
|
|
if( NULL != *ppv )
|
|
{
|
|
((LPUNKNOWN)*ppv)->AddRef();
|
|
return NOERROR;
|
|
}
|
|
|
|
return ResultFromScode(E_NOINTERFACE);
|
|
}
|
|
|
|
|
|
//
|
|
// INotificationSink member(s)
|
|
//
|
|
STDMETHODIMP CTrayAgent::OnNotification(
|
|
LPNOTIFICATION pNotification,
|
|
LPNOTIFICATIONREPORT pNotificationReport,
|
|
DWORD dwReserved)
|
|
{
|
|
//xnotfmgr
|
|
DBG("CTrayAgent::OnNotification called");
|
|
ASSERT(pNotification);
|
|
ASSERT(GetCurrentThreadId() == m_AptThreadId);
|
|
|
|
//
|
|
// Extract Notification Type.
|
|
//
|
|
HRESULT hr;
|
|
NOTIFICATIONTYPE notfType;
|
|
hr = pNotification->GetNotificationInfo(¬fType, NULL, NULL, NULL, 0);
|
|
ASSERT(SUCCEEDED(hr));
|
|
|
|
if (notfType == NOTIFICATIONTYPE_CONFIG_CHANGED)
|
|
{
|
|
DBG("CTrayAgent::OnNotification - config changed");
|
|
//
|
|
// The global properties have changed and we must respond.
|
|
//
|
|
ASSERT(g_pTrayUI); // Fault here means NotificationMgr calling me in wrong process
|
|
if (g_pTrayUI)
|
|
g_pTrayUI->ConfigChanged();
|
|
return S_OK;
|
|
}
|
|
else if (notfType == NOTIFICATIONTYPE_BEGIN_REPORT) {
|
|
DBG("CTrayAgent::OnNotification - begin report");
|
|
ASSERT(g_pTrayUI);
|
|
if (g_pTrayUI)
|
|
g_pTrayUI->OnBeginReport(pNotification);
|
|
return S_OK;
|
|
}
|
|
else if (notfType == NOTIFICATIONTYPE_AGENT_START)
|
|
{
|
|
DBG("CTrayAgent::OnNotification - agent start (update now)");
|
|
//
|
|
// The user chose Update Subscriptions Now.
|
|
// Is this the best notification to use for this?
|
|
// Are there any properties we care about? Like a guid to trigger
|
|
// a specific one?
|
|
//
|
|
ASSERT(g_pTrayUI); // Fault here means NotificationMgr calling me in wrong process
|
|
if (g_pTrayUI)
|
|
g_pTrayUI->UpdateNow(pNotification);
|
|
return S_OK;
|
|
}
|
|
else if (notfType == NOTIFICATIONTYPE_END_REPORT)
|
|
{
|
|
DBG("CTrayAgent::OnNotification - end report");
|
|
ASSERT(g_pTrayUI);
|
|
if (g_pTrayUI)
|
|
g_pTrayUI->OnEndReport(pNotification);
|
|
|
|
#if WANT_REGISTRY_LOG
|
|
//
|
|
// Log all the End Reports
|
|
//
|
|
BSTR bstrStatus = NULL;
|
|
CLSID cookie;
|
|
|
|
if (g_pTrayUI &&
|
|
SUCCEEDED(ReadBSTR(pNotification,NULL, c_szPropStatusString, &bstrStatus))
|
|
&& SUCCEEDED(ReadGUID(pNotification, NULL, c_szStartCookie, &cookie)))
|
|
{
|
|
g_pTrayUI->AddToLog(bstrStatus, CLSID_NULL, cookie);
|
|
} else {
|
|
DBG_WARN("CTrayAgent::OnNotification/End Report - Not status str");
|
|
}
|
|
SAFEFREEBSTR(bstrStatus);
|
|
#endif
|
|
|
|
//
|
|
// Read the status code from the end report.
|
|
//
|
|
SCODE scEndStatus;
|
|
hr = ReadSCODE(pNotification, NULL, c_szPropStatusCode, &scEndStatus);
|
|
if (SUCCEEDED(hr) && SUCCEEDED(scEndStatus))
|
|
{
|
|
//
|
|
// Special feature for desktop HTML:
|
|
// If we receive an end report with "DesktopComponent=1" in it,
|
|
// let the desktop know that it needs to refresh itself. We always
|
|
// do this instead of only on "changes detected" because desktop
|
|
// component authors don't want to change their CDFs.
|
|
//
|
|
DWORD dwRet;
|
|
HRESULT hr2 = ReadDWORD(pNotification, NULL, c_szPropDesktopComponent, &dwRet);
|
|
if (SUCCEEDED(hr2) && (dwRet == 1))
|
|
{
|
|
IActiveDesktop *pAD = NULL;
|
|
hr2 = CoCreateInstance(CLSID_ActiveDesktop, NULL, CLSCTX_INPROC_SERVER, IID_IActiveDesktop, (void**)&pAD);
|
|
DBGASSERT(SUCCEEDED(hr2), "Unable to create ActiveDesktop in order to refresh desktop component");
|
|
if (SUCCEEDED(hr2))
|
|
{
|
|
ASSERT(pAD);
|
|
pAD->ApplyChanges(AD_APPLY_FORCE | AD_APPLY_REFRESH | AD_APPLY_BUFFERED_REFRESH);
|
|
pAD->Release();
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// If the delivery agent succeeded and changes were detected
|
|
// notify the appropriate code.
|
|
//
|
|
if (SUCCEEDED(hr) && SUCCEEDED(scEndStatus) && (S_FALSE != scEndStatus))
|
|
{
|
|
//
|
|
// Gleam the Internet Shortcut for the URL if requested. (EnableShortcutGleam=1)
|
|
// NOTE: End Reports without changes (S_FALSE) were filtered above.
|
|
//
|
|
DWORD dwRet;
|
|
hr = ReadDWORD(pNotification, NULL, c_szPropEnableShortcutGleam, &dwRet);
|
|
if (SUCCEEDED(hr) && dwRet)
|
|
{
|
|
LPSTR strURL = NULL;
|
|
hr = ReadAnsiSTR(pNotification, NULL, c_szPropURL, &strURL);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
PROPVARIANT propvar;
|
|
PropVariantInit(&propvar);
|
|
hr = IntSiteHelper(strURL, &c_rgPropRead[PROP_FLAGS], &propvar, 1, FALSE);
|
|
if (SUCCEEDED(hr) && (VT_UI4 == propvar.vt))
|
|
{
|
|
// Set our flag without disturbing the others.
|
|
propvar.ulVal |= PIDISF_RECENTLYCHANGED;
|
|
}
|
|
else
|
|
{
|
|
// Be sure to clear the variant if it wasn't a DWORD.
|
|
PropVariantClear(&propvar);
|
|
propvar.vt = VT_UI4;
|
|
propvar.ulVal = PIDISF_RECENTLYCHANGED;
|
|
}
|
|
|
|
//
|
|
// Update channels.
|
|
//
|
|
|
|
hr = ReadDWORD(pNotification, NULL, c_szPropChannel, &dwRet);
|
|
BOOL bChannel = SUCCEEDED(hr) && dwRet;
|
|
|
|
CHANNELIMAGEDATA cid = {0};
|
|
IChannelMgrPriv* pIChannelMgrPriv = NULL;
|
|
HRESULT hr2 = E_FAIL;
|
|
|
|
if (bChannel)
|
|
{
|
|
hr2 = GetChannelPath(strURL, cid.szPath,
|
|
ARRAYSIZE(cid.szPath),
|
|
&pIChannelMgrPriv);
|
|
if (SUCCEEDED(hr2))
|
|
hr2 = PreUpdateChannelImage(pIChannelMgrPriv, &cid);
|
|
}
|
|
|
|
hr = IntSiteHelper(strURL, &c_rgPropRead[PROP_FLAGS], &propvar, 1, TRUE);
|
|
DBGASSERT(SUCCEEDED(hr), "CTrayAgent::OnNotification - failed to set gleam.");
|
|
|
|
if (bChannel && SUCCEEDED(hr2))
|
|
{
|
|
ASSERT(pIChannelMgrPriv);
|
|
|
|
pIChannelMgrPriv->InvalidateCdfCache();
|
|
UpdateChannelImage(pIChannelMgrPriv, &cid);
|
|
UpdateChannel(pIChannelMgrPriv, strURL);
|
|
|
|
pIChannelMgrPriv->Release();
|
|
}
|
|
}
|
|
MemFree(strURL); // Free the string allocated by ReadAnsiSTR().
|
|
}
|
|
|
|
//
|
|
// Send Email to notify the user if requested (EmailNotification=1)
|
|
// NOTE: End Reports without changes (S_FALSE) were filtered above.
|
|
//
|
|
hr = ReadDWORD(pNotification, NULL, c_szPropEmailNotf, &dwRet);
|
|
if (SUCCEEDED(hr) && dwRet)
|
|
{
|
|
hr = SendEmailFromNotification(pNotification);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DBG_WARN("CTrayAgent::OnNotification - unchanged or failed end report");
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
else if (notfType == NOTIFICATIONTYPE_DISCONNECT_FROM_INTERNET)
|
|
{
|
|
OnDisconnectedNotification();
|
|
return S_OK;
|
|
}
|
|
else if (notfType == NOTIFICATIONTYPE_CONNECT_TO_INTERNET )
|
|
{
|
|
OnConnectedNotification();
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// TrayAgent doesn't handle this notification
|
|
//
|
|
DBG("CTrayAgent::OnNotification - unknown notification");
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// TrayUI object (not COM)
|
|
//----------------------------------------------------------------------------
|
|
|
|
LRESULT CALLBACK TrayUI_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
//xnotfmgr
|
|
//
|
|
// We need this annoying global to make single and double left click work nicely.
|
|
// (USER should have a WM_LBUTTONSINGLECLK message.)
|
|
//
|
|
static int iLeftClick = 0;
|
|
static POINT pt;
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_USER: // Subscription icon was clicked
|
|
ASSERT(g_pTrayUI);
|
|
switch (lParam)
|
|
{
|
|
#ifdef DEBUG
|
|
case WM_RBUTTONUP:
|
|
if (iLeftClick) {
|
|
ASSERT(1 == iLeftClick);
|
|
KillTimer(hwnd, TIMER_ID_DBL_CLICK);
|
|
iLeftClick = 0;
|
|
}
|
|
GetCursorPos(&pt);
|
|
g_pTrayUI->OpenContextMenu(&pt);
|
|
break;
|
|
case WM_LBUTTONUP:
|
|
if (0 == iLeftClick) // first left click up
|
|
{
|
|
UINT uRet;
|
|
GetCursorPos(&pt);
|
|
uRet = SetTimer(hwnd, TIMER_ID_DBL_CLICK, GetDoubleClickTime(), NULL);
|
|
ASSERT(uRet);
|
|
iLeftClick = 1;
|
|
}
|
|
else // second left click up
|
|
{
|
|
ASSERT(1 == iLeftClick);
|
|
KillTimer(hwnd, TIMER_ID_DBL_CLICK);
|
|
iLeftClick = 0;
|
|
g_pTrayUI->OpenSubscriptionFolder();
|
|
}
|
|
break;
|
|
#endif
|
|
case UM_NEEDREBOOT:
|
|
// forward reboot required flag to update agent
|
|
if (FAILED(UpdateNotifyReboot()))
|
|
DoReboot();
|
|
break;
|
|
}
|
|
return 0;
|
|
|
|
case WM_TIMER:
|
|
switch(wParam) {
|
|
case TIMER_ID_DBL_CLICK:
|
|
// Timer went off so it was a single click
|
|
KillTimer(hwnd, TIMER_ID_DBL_CLICK);
|
|
if (1 == iLeftClick) {
|
|
iLeftClick = 0;
|
|
g_pTrayUI->OpenContextMenu(&pt);
|
|
}
|
|
break;
|
|
} /* switch */
|
|
break;
|
|
|
|
// Process the Infodelivery Admin Policies on WM_WININICHANGE lParam="Policy"
|
|
case WM_WININICHANGE:
|
|
if (lParam && !lstrcmpi((LPCTSTR)lParam, TEXT("policy")))
|
|
{
|
|
ProcessInfodeliveryPolicies();
|
|
}
|
|
// FEATURE: This should be done on Policy and another filter, not for
|
|
// all changes. (The other filter hasn't been defined yet.)
|
|
|
|
// TODO: handle this in the new architecture!
|
|
//SetNotificationMgrRestrictions(NULL);
|
|
break;
|
|
|
|
case WM_LOADSCREENSAVER:
|
|
{
|
|
EVAL(ReloadChannelScreenSaver());
|
|
break;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
return DefWindowProc(hwnd, uMsg, wParam, lParam);
|
|
}
|
|
|
|
CTrayUI::CTrayUI(void)
|
|
{
|
|
// There should only be one of these objects
|
|
ASSERT(!g_pTrayUI);
|
|
// Assert that we're zero initialized.
|
|
ASSERT(!m_hwnd);
|
|
#if WANT_REGISTRY_LOG
|
|
ASSERT(!m_cLogs);
|
|
#endif
|
|
ASSERT(!m_cUpdates);
|
|
ASSERT(!m_fUpdatingTrayIcon);
|
|
#ifdef DEBUG
|
|
m_AptThreadId = GetCurrentThreadId();
|
|
#endif
|
|
}
|
|
|
|
CTrayUI::~CTrayUI(void)
|
|
{
|
|
//
|
|
// Clean up any BSTRs we have around
|
|
//
|
|
|
|
// ZDC Detect ongoing updates?
|
|
ASSERT(m_cUpdates >= 0);
|
|
|
|
#if WANT_REGISTRY_LOG
|
|
ASSERT(m_cLogs >= 0);
|
|
ASSERT(m_cLogs < TRAYUI_CLOGS);
|
|
for (int i = 0; i < m_cLogs; i++)
|
|
{
|
|
SAFEFREEBSTR(m_aLogEntry[i].bstrStatus);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#if WANT_REGISTRY_LOG
|
|
#define TRAYLOGVERSION 716
|
|
|
|
STDMETHODIMP WriteSingleEntry(PLogEntry pLog, LPCTSTR szSubKey, int index)
|
|
{
|
|
|
|
ASSERT(pLog && szSubKey);
|
|
ASSERT(index >= 0);
|
|
ASSERT(index < TRAYUI_CLOGS);
|
|
|
|
// Check to see if it's a valid log entry.
|
|
if (!(pLog->bstrStatus)) {
|
|
ASSERT(0);
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
TCHAR szLogName[16];
|
|
wsprintf(szLogName, TEXT("%d"), index);
|
|
|
|
CRegStream * prLog = new CRegStream(HKEY_CURRENT_USER, szSubKey, szLogName);
|
|
if (prLog) {
|
|
CLSID clsidAgent = pLog->clsidAgent;
|
|
CLSID cookie = pLog->startCookie;
|
|
FILETIME ftLog = pLog->ftLog;
|
|
int versionNumber = TRAYLOGVERSION;
|
|
BSTR bstrStatus = pLog->bstrStatus;
|
|
DWORD cbWritten;
|
|
int len;
|
|
|
|
prLog->Write(&versionNumber, sizeof(int), &cbWritten);
|
|
ASSERT(sizeof(int) == cbWritten);
|
|
|
|
prLog->Write(&clsidAgent, sizeof(CLSID), &cbWritten);
|
|
ASSERT(sizeof(CLSID) == cbWritten);
|
|
|
|
prLog->Write(&cookie, sizeof(CLSID), &cbWritten);
|
|
ASSERT(sizeof(CLSID) == cbWritten);
|
|
|
|
prLog->Write(&ftLog, sizeof(FILETIME), &cbWritten);
|
|
ASSERT(sizeof(FILETIME) == cbWritten);
|
|
|
|
len = lstrlenW(bstrStatus);
|
|
prLog->Write(&len, sizeof(int), &cbWritten);
|
|
ASSERT(sizeof(int) == cbWritten);
|
|
len *= sizeof(WCHAR);
|
|
prLog->Write(bstrStatus, len, &cbWritten);
|
|
ASSERT(len == (int)cbWritten);
|
|
|
|
delete prLog;
|
|
return S_OK;
|
|
} else {
|
|
return E_FAIL;
|
|
}
|
|
}
|
|
|
|
STDMETHODIMP ReadSingleEntry(PLogEntry pLog, LPCTSTR szSubKey, int index)
|
|
{
|
|
ASSERT(pLog && szSubKey);
|
|
ASSERT(index >= 0);
|
|
ASSERT(index < TRAYUI_CLOGS);
|
|
|
|
// Check to see if it's a valid log entry.
|
|
if (pLog->bstrStatus) {
|
|
ASSERT(0);
|
|
SAFEFREEBSTR(pLog->bstrStatus);
|
|
}
|
|
|
|
TCHAR szLogName[16];
|
|
HRESULT hrLog = E_INVALIDARG;
|
|
wsprintf(szLogName, TEXT("%d"), index);
|
|
|
|
CRegStream * prLog = new CRegStream(HKEY_CURRENT_USER, szSubKey, szLogName);
|
|
if (prLog && (FALSE == prLog->m_fNewStream)) {
|
|
CLSID clsidAgent;
|
|
CLSID cookie;
|
|
FILETIME ftLog;
|
|
int versionNumber;
|
|
BSTR bstrStatus = NULL;
|
|
DWORD cbWritten;
|
|
int len;
|
|
|
|
if (SUCCEEDED(prLog->Read(&versionNumber, sizeof(int), &cbWritten))
|
|
&& (sizeof(int) == cbWritten)
|
|
&& (TRAYLOGVERSION == versionNumber))
|
|
{
|
|
hrLog = ERROR_SUCCESS;
|
|
}
|
|
|
|
if (ERROR_SUCCESS == hrLog) {
|
|
hrLog = E_INVALIDARG;
|
|
if (SUCCEEDED(prLog->Read(&clsidAgent, sizeof(CLSID), &cbWritten))
|
|
&& (sizeof(CLSID) == cbWritten))
|
|
{
|
|
hrLog = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
|
|
if (ERROR_SUCCESS == hrLog) {
|
|
hrLog = E_INVALIDARG;
|
|
if (SUCCEEDED(prLog->Read(&cookie, sizeof(CLSID), &cbWritten))
|
|
&& (sizeof(CLSID) == cbWritten))
|
|
{
|
|
hrLog = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
|
|
if (ERROR_SUCCESS == hrLog) {
|
|
hrLog = E_INVALIDARG;
|
|
if (SUCCEEDED(prLog->Read(&ftLog, sizeof(FILETIME), &cbWritten))
|
|
&& (sizeof(FILETIME) == cbWritten))
|
|
{
|
|
hrLog = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
|
|
if (ERROR_SUCCESS == hrLog) {
|
|
hrLog = E_INVALIDARG;
|
|
if (SUCCEEDED(prLog->Read(&len, sizeof(int), &cbWritten))
|
|
&& (sizeof(int) == cbWritten)
|
|
&& (len < INTERNET_MAX_URL_LENGTH)
|
|
&& (bstrStatus = SysAllocStringLen(NULL, len))
|
|
&& SUCCEEDED(prLog->Read(bstrStatus, len * sizeof(WCHAR), &cbWritten))
|
|
&& (len * sizeof(WCHAR) == (int)cbWritten))
|
|
{
|
|
hrLog = ERROR_SUCCESS;
|
|
bstrStatus[len] = 0;
|
|
}
|
|
}
|
|
|
|
if (ERROR_SUCCESS == hrLog) {
|
|
pLog->clsidAgent = clsidAgent;
|
|
pLog->startCookie = cookie;
|
|
pLog->ftLog = ftLog;
|
|
pLog->bstrStatus = bstrStatus;
|
|
|
|
#ifdef DEBUG
|
|
WCHAR wszCookie[GUIDSTR_MAX];
|
|
TCHAR tmpTSTR[INTERNET_MAX_URL_LENGTH];
|
|
|
|
StringFromGUID2(cookie, wszCookie, ARRAYSIZE(wszCookie));
|
|
MyOleStrToStrN(tmpTSTR, ARRAYSIZE(wszCookie), wszCookie);
|
|
TraceMsg(TF_THISMODULE, TEXT("TrayUI:LoadLog - %s(cookie)"), tmpTSTR);
|
|
MyOleStrToStrN(tmpTSTR, ARRAYSIZE(tmpTSTR), bstrStatus);
|
|
TraceMsg(TF_THISMODULE, TEXT("TrayUI:LoadLog - %s(status)"), tmpTSTR);
|
|
|
|
SYSTEMTIME stLog;
|
|
FileTimeToSystemTime(&ftLog, &stLog);
|
|
GetTimeFormat(LOCALE_SYSTEM_DEFAULT, LOCALE_NOUSEROVERRIDE,
|
|
&stLog, NULL, tmpTSTR, ARRAYSIZE(tmpTSTR));
|
|
TraceMsg(TF_THISMODULE, TEXT("TrayUI:LoadLog - %s(time)"), tmpTSTR);
|
|
#endif
|
|
} else {
|
|
SAFEFREEBSTR(bstrStatus);
|
|
}
|
|
}
|
|
|
|
if (prLog)
|
|
delete prLog;
|
|
|
|
return hrLog;
|
|
}
|
|
|
|
STDMETHODIMP CTrayUI::SyncLogWithReg(int index, BOOL fWriteMax)
|
|
{
|
|
if ((index < 0) || (index >= m_cLogs))
|
|
return S_FALSE;
|
|
|
|
TCHAR szSubKey[1024];
|
|
|
|
ASSERT((lstrlen(c_szRegKey) + lstrlen(c_szLog) + 2) < 1024);
|
|
|
|
#error Potential Buffer overflow:
|
|
lstrcpy(szSubKey, c_szRegKey);
|
|
lstrcat(szSubKey, c_szLog);
|
|
|
|
HRESULT hr = E_FAIL;
|
|
|
|
hr = WriteSingleEntry(&(m_aLogEntry[index]), szSubKey, index);
|
|
if ((ERROR_SUCCESS == hr) && fWriteMax) {
|
|
CRegStream * prs =
|
|
new CRegStream(HKEY_CURRENT_USER, szSubKey, c_szLogMaxIndex);
|
|
DWORD cbWritten;
|
|
|
|
if (prs) {
|
|
prs->Write(&m_cLogs, sizeof(int), &cbWritten);
|
|
ASSERT(sizeof(int) == cbWritten);
|
|
delete prs;
|
|
} else {
|
|
hr = E_FAIL;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CTrayUI::SaveLogToReg(void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
TCHAR szSubKey[1024];
|
|
|
|
ASSERT((lstrlen(c_szRegKey) + lstrlen(c_szLog) + 2) < 1024);
|
|
|
|
#error Potential Buffer overflow:
|
|
lstrcpy(szSubKey, c_szRegKey);
|
|
lstrcat(szSubKey, c_szLog);
|
|
|
|
int index = 0;
|
|
int cIndex = 0;
|
|
ULONG cbWritten;
|
|
int maxIndex = m_cLogs;
|
|
|
|
for (; index < maxIndex; index ++) {
|
|
if (SUCCEEDED(
|
|
WriteSingleEntry(&(m_aLogEntry[index]), szSubKey, cIndex)
|
|
)
|
|
)
|
|
{
|
|
cIndex ++;
|
|
}
|
|
}
|
|
|
|
CRegStream * prs =
|
|
new CRegStream(HKEY_CURRENT_USER, szSubKey, c_szLogMaxIndex);
|
|
if (prs) {
|
|
prs->Write(&cIndex, sizeof(int), &cbWritten);
|
|
ASSERT(sizeof(int) == cbWritten);
|
|
delete prs;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CTrayUI::LoadLogFromReg(void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
TCHAR szSubKey[1024];
|
|
|
|
ASSERT((lstrlen(c_szRegKey) + lstrlen(c_szLog) + 2) < 1024);
|
|
|
|
#error Potential Buffer overflow:
|
|
lstrcpy(szSubKey, c_szRegKey);
|
|
lstrcat(szSubKey, c_szLog);
|
|
|
|
m_cLogs = 0;
|
|
|
|
int index = 0;
|
|
ULONG cbWritten;
|
|
int len = 0;
|
|
int maxIndex = 0;
|
|
|
|
CRegStream * prs = new CRegStream(HKEY_CURRENT_USER, szSubKey, c_szLogMaxIndex);
|
|
|
|
if (!prs) {
|
|
hr = E_FAIL;
|
|
} else if (TRUE == prs->m_fNewStream) {
|
|
hr = E_FAIL;
|
|
} else {
|
|
if (SUCCEEDED(prs->Read(&maxIndex, sizeof(int), &cbWritten))
|
|
&& (sizeof(int) == cbWritten) && (maxIndex >= 0))
|
|
{
|
|
FILETIME ftFirst;
|
|
SYSTEMTIME stNow;
|
|
|
|
if (TRAYUI_CLOGS < maxIndex) {
|
|
maxIndex = TRAYUI_CLOGS;
|
|
}
|
|
|
|
m_cLogPtr = -1;
|
|
GetSystemTime(&stNow);
|
|
SystemTimeToFileTime(&stNow, &ftFirst);
|
|
|
|
for (; index < maxIndex; index ++)
|
|
{
|
|
PLogEntry pLog = &(m_aLogEntry[m_cLogs]);
|
|
if (SUCCEEDED(ReadSingleEntry(pLog, szSubKey, index))) {
|
|
if (-1 == CompareFileTime(&(pLog->ftLog), &ftFirst)) {
|
|
ftFirst= pLog->ftLog;
|
|
m_cLogPtr = m_cLogs;
|
|
}
|
|
m_cLogs ++;
|
|
}
|
|
}
|
|
|
|
// m_cLogPtr points to the oldest log. If we haven't used up
|
|
// all log space m_cLogPtr should point to 0. We then adjust
|
|
// it to the next available log slot.
|
|
if (m_cLogs < TRAYUI_CLOGS) {
|
|
ASSERT(m_cLogPtr == 0);
|
|
m_cLogPtr = m_cLogs;
|
|
}
|
|
}
|
|
}
|
|
if (prs)
|
|
delete prs;
|
|
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CTrayUI::AddToLog(BSTR bstrStatus, CLSID clsidAgent, CLSID startCookie)
|
|
{
|
|
ASSERT(bstrStatus);
|
|
BSTR bstrTmp = NULL;
|
|
bstrTmp = SysAllocString(bstrStatus);
|
|
|
|
if (bstrTmp == NULL)
|
|
return E_OUTOFMEMORY;
|
|
|
|
PLogEntry pLog = &(m_aLogEntry[m_cLogPtr]);
|
|
|
|
pLog->bstrStatus = bstrTmp;
|
|
pLog->clsidAgent = clsidAgent;
|
|
pLog->startCookie = startCookie;
|
|
|
|
SYSTEMTIME stNow;
|
|
GetSystemTime(&stNow);
|
|
SystemTimeToFileTime(&stNow, &(pLog->ftLog));
|
|
|
|
if (m_cLogPtr == m_cLogs) {
|
|
m_cLogs ++;
|
|
SyncLogWithReg(m_cLogPtr, TRUE);
|
|
} else {
|
|
SyncLogWithReg(m_cLogPtr, FALSE);
|
|
}
|
|
|
|
m_cLogPtr ++;
|
|
m_cLogPtr %= TRAYUI_CLOGS;
|
|
return S_OK;
|
|
}
|
|
#endif // WANT_REGISTRY_LOG
|
|
|
|
STDMETHODIMP CTrayUI::InitTrayUI(void)
|
|
{
|
|
// shouldn't already be initialized
|
|
ASSERT(NULL == m_hwnd);
|
|
|
|
// create a hidden window
|
|
WNDCLASS wndclass;
|
|
|
|
wndclass.style = 0;
|
|
wndclass.lpfnWndProc = TrayUI_WndProc;
|
|
wndclass.cbClsExtra = 0;
|
|
wndclass.cbWndExtra = 0;
|
|
wndclass.hInstance = g_hInst;
|
|
wndclass.hIcon = NULL;
|
|
wndclass.hCursor = NULL;
|
|
wndclass.hbrBackground = NULL;
|
|
wndclass.lpszMenuName = NULL;
|
|
wndclass.lpszClassName = c_szTrayUI;
|
|
|
|
RegisterClass (&wndclass) ;
|
|
|
|
m_hwnd = CreateWindow(c_szTrayUI,
|
|
c_szTrayUI,
|
|
WS_OVERLAPPEDWINDOW,
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
NULL,
|
|
NULL,
|
|
g_hInst,
|
|
NULL);
|
|
|
|
DBGASSERT(m_hwnd, "failed to create TrayUI window");
|
|
if (NULL == m_hwnd)
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
ShowWindow(m_hwnd, SW_HIDE);
|
|
|
|
//
|
|
// Add an icon to tray after seeing if it's enabled in the registry.
|
|
//
|
|
ASSERT(FALSE == m_fUpdatingTrayIcon);
|
|
|
|
// turn on idle monitoring
|
|
IdleBegin(m_hwnd);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CTrayUI::DestroyTrayUI(void)
|
|
{
|
|
// stop idle monitoring
|
|
IdleEnd();
|
|
|
|
if (m_hwnd)
|
|
{
|
|
BOOL bRet;
|
|
bRet = DestroyWindow(m_hwnd);
|
|
ASSERT(bRet);
|
|
m_hwnd = NULL;
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
STDMETHODIMP CTrayUI::OpenSubscriptionFolder(void)
|
|
{
|
|
#ifdef DEBUG
|
|
// WARNING: This is copied from shdocvw and it might change post beta 1.
|
|
TCHAR szSubPath[MAX_PATH];
|
|
DWORD dwSize = SIZEOF(szSubPath);
|
|
|
|
if (ReadRegValue(HKEY_LOCAL_MACHINE, REGSTR_PATH_SUBSCRIPTION,
|
|
REGSTR_VAL_DIRECTORY, (LPBYTE)szSubPath, dwSize) == FALSE)
|
|
{
|
|
TCHAR szWindows[MAX_PATH];
|
|
|
|
GetWindowsDirectory(szWindows, ARRAYSIZE(szWindows));
|
|
PathCombine(szSubPath, szWindows, TEXT("Subscriptions"));
|
|
}
|
|
|
|
SHELLEXECUTEINFO shei;
|
|
ZeroMemory(&shei, sizeof(shei));
|
|
shei.cbSize = sizeof(shei);
|
|
shei.lpFile = szSubPath;
|
|
shei.nShow = SW_SHOWNORMAL;
|
|
ShellExecuteEx(&shei);
|
|
|
|
#endif
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CTrayUI::OpenContextMenu(POINT * pPoint)
|
|
{
|
|
#ifdef DEBUG
|
|
int iCmd;
|
|
HMENU hMenu;
|
|
TCHAR menuString[MAX_PATH];
|
|
|
|
ASSERT(pPoint);
|
|
// SetForegroundWindow(hwnd);
|
|
hMenu = CreatePopupMenu();
|
|
if (!hMenu)
|
|
return E_FAIL;
|
|
|
|
|
|
// MLLoadString(IDS_SHOWPROG, menuString, MAX_PATH);
|
|
// AppendMenu(hMenu, MF_STRING, IDS_SHOWPROG, menuString);
|
|
|
|
MLLoadString(IDS_CANCELDL, menuString, MAX_PATH);
|
|
AppendMenu(hMenu, MF_STRING, IDS_CANCELDL, menuString);
|
|
|
|
MLLoadString(IDS_VIEW_SUBS, menuString, MAX_PATH);
|
|
AppendMenu(hMenu, MF_STRING, IDS_VIEW_SUBS, menuString);
|
|
|
|
SetMenuDefaultItem(hMenu, IDS_CANCELDL, FALSE);
|
|
|
|
if (hMenu)
|
|
{
|
|
//
|
|
// Set the owner window to be foreground as a hack so the
|
|
// popup menu disappears when the user clicks elsewhere.
|
|
//
|
|
BOOL bRet;
|
|
ASSERT(m_hwnd);
|
|
bRet = SetForegroundWindow(m_hwnd);
|
|
ASSERT(bRet);
|
|
iCmd = TrackPopupMenu(hMenu, TPM_RETURNCMD | TPM_NONOTIFY | TPM_RIGHTBUTTON,
|
|
pPoint->x, pPoint->y, 0, m_hwnd, NULL);
|
|
DestroyMenu(hMenu);
|
|
|
|
MSG msgTmp;
|
|
while (PeekMessage(&msgTmp, m_hwnd, WM_LBUTTONDOWN, WM_LBUTTONUP, PM_REMOVE)) {
|
|
DispatchMessage(&msgTmp);
|
|
}
|
|
}
|
|
|
|
switch (iCmd)
|
|
{
|
|
case IDS_SHOWPROG:
|
|
RunTest();
|
|
break;
|
|
case IDS_CANCELDL:
|
|
CancelAllDownloads();
|
|
break;
|
|
case IDS_VIEW_SUBS:
|
|
OpenSubscriptionFolder();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
#endif
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CTrayUI::UpdateNow(INotification * pNotification)
|
|
{
|
|
//
|
|
// Update Subscriptions Now
|
|
// We really don't want to do this on the caller's thread. We should
|
|
// always get here through a notification on the appartment thread.
|
|
// (No direct calls from other threads are allowed to avoid race
|
|
// conditions at startup.)
|
|
ASSERT(GetCurrentThreadId() == m_AptThreadId);
|
|
|
|
// Essentially we do a PostThreadMessage here to the updating thread.
|
|
return UpdateRequest(UM_ONREQUEST, pNotification);
|
|
}
|
|
|
|
|
|
STDMETHODIMP CTrayUI::SetTrayIcon(DWORD fUpdating)
|
|
{
|
|
#ifdef DEBUG
|
|
if (fUpdating == m_fUpdatingTrayIcon) {
|
|
return S_OK;
|
|
}
|
|
|
|
if (fUpdating)
|
|
{
|
|
BOOL bRet;
|
|
NOTIFYICONDATA NotifyIconData;
|
|
NotifyIconData.cbSize = sizeof(NOTIFYICONDATA);
|
|
NotifyIconData.hWnd = m_hwnd;
|
|
NotifyIconData.uID = 0;
|
|
NotifyIconData.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
|
|
NotifyIconData.uCallbackMessage = WM_USER;
|
|
NotifyIconData.hIcon = LoadIcon(g_hInst, MAKEINTRESOURCE(IDI_TRAYICON));
|
|
ASSERT(NotifyIconData.hIcon);
|
|
bRet = MLLoadString(IDS_TRAY_TOOLTIP, NotifyIconData.szTip, ARRAYSIZE(NotifyIconData.szTip));
|
|
ASSERT(bRet);
|
|
bRet = Shell_NotifyIcon(NIM_ADD, &NotifyIconData);
|
|
ASSERT(bRet);
|
|
}
|
|
else
|
|
{
|
|
// Remove the tray icon
|
|
BOOL bRet;
|
|
NOTIFYICONDATA NotifyIconData;
|
|
NotifyIconData.cbSize = sizeof(NOTIFYICONDATA);
|
|
NotifyIconData.hWnd = m_hwnd;
|
|
NotifyIconData.uID = 0;
|
|
NotifyIconData.uFlags = 0;
|
|
bRet = Shell_NotifyIcon(NIM_DELETE, &NotifyIconData);
|
|
ASSERT(bRet);
|
|
}
|
|
|
|
m_fUpdatingTrayIcon = fUpdating;
|
|
#endif
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CTrayUI::ConfigChanged(void)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CTrayUI::OnEndReport(INotification * pNot)
|
|
{
|
|
//xnotfmgr
|
|
ASSERT(pNot);
|
|
CLSID cookie;
|
|
|
|
if (SUCCEEDED(ReadGUID(pNot, NULL, c_szStartCookie, &cookie)))
|
|
{
|
|
DBGIID("TrayAgent::OnEndReport - ", cookie);
|
|
UpdateRequest(UM_ENDREPORT, pNot);
|
|
LONG lTmp = InterlockedDecrement(&m_cUpdates);
|
|
|
|
if (!lTmp)
|
|
SetTrayIcon(FALSE);
|
|
|
|
OOEBuf ooeBuf;
|
|
LPMYPIDL newPidl = NULL;
|
|
DWORD dwSize = 0;
|
|
|
|
ZeroMemory((void *)&ooeBuf, sizeof(OOEBuf));
|
|
HRESULT hr = LoadWithCookie(NULL, &ooeBuf, &dwSize, &cookie);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
newPidl = COfflineFolderEnum::NewPidl(dwSize);
|
|
if (newPidl) {
|
|
CopyToMyPooe(&ooeBuf, &(newPidl->ooe));
|
|
_GenerateEvent(SHCNE_UPDATEITEM, (LPITEMIDLIST)newPidl, NULL);
|
|
COfflineFolderEnum::FreePidl(newPidl);
|
|
}
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CTrayUI::OnBeginReport(INotification * pNot)
|
|
{
|
|
//xnotfmgr
|
|
ASSERT(pNot);
|
|
CLSID cookie;
|
|
|
|
if (SUCCEEDED(ReadGUID(pNot, NULL, c_szStartCookie, &cookie)))
|
|
{
|
|
DBGIID("TrayAgent::OnBeginReport - ", cookie);
|
|
UpdateRequest(UM_BEGINREPORT, pNot);
|
|
InterlockedIncrement(&m_cUpdates);
|
|
SetTrayIcon(TRUE);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|