|
|
//----------------------------------------------------------------------------
//
// 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; }
|