|
|
#include "priv.h"
#include "inetnot.h"
//+-------------------------------------------------------------------------
// Static initialization
//--------------------------------------------------------------------------
HWND CWinInetNotify::s_hwnd = NULL; ULONG CWinInetNotify::s_ulEnabled = 0; CWinInetNotify* CWinInetNotify::s_pWinInetNotify = NULL;
//+-------------------------------------------------------------------------
// Constructor - Creates invisible top-level window.
//--------------------------------------------------------------------------
CWinInetNotify::CWinInetNotify() : _hMutex(NULL), _fEnabled(FALSE) { }
//+-------------------------------------------------------------------------
// Enables/disables wininet notifications
//--------------------------------------------------------------------------
void CWinInetNotify::Enable(BOOL fEnable) { if (fEnable && !_fEnabled) { //
// Enable the notifications
//
ENTERCRITICAL; ++s_ulEnabled; if (NULL == s_hwnd) { // create an invisible top-level window to receive notifications
WNDCLASS wc; ZeroMemory(&wc, SIZEOF(wc));
wc.lpfnWndProc = _WndProc; wc.hInstance = HINST_THISDLL; wc.lpszClassName = CWinInetNotify_szWindowClass;
SHRegisterClass(&wc);
s_hwnd = CreateWindow(CWinInetNotify_szWindowClass, NULL, WS_POPUP, 0, 0, 1, 1, NULL, NULL, HINST_THISDLL, this); }
if (s_hwnd) { _fEnabled = TRUE; }
LEAVECRITICAL; } else if (!fEnable && _fEnabled) { //
// Disable the notifications
//
ENTERCRITICAL; if (--s_ulEnabled == 0) { //
// We use a mutex here because we can have multiple instances of
// iexplore. We want to avoid setting up a window to accept wininet
// notifications if it is in the process of being destroyed.
//
_EnterMutex();
// Look for another window to receive wininet notifications
if (EnumWindows(EnumWindowsProc, NULL)) { // No one left so turn off notifications
RegisterUrlCacheNotification(0, 0, 0, 0, 0); }
//
// Handle any queued notifications.
//
// Note that we have a small window in which a notification
// can be lost! Something could be posted to us after we are
// destroyed!
//
MSG msg; if (PeekMessage(&msg, s_hwnd, CWM_WININETNOTIFY, CWM_WININETNOTIFY, PM_REMOVE)) { _OnNotify(msg.wParam); }
DestroyWindow(s_hwnd); s_hwnd = NULL;
// Now that our window is gone, we can allow other processes to
// look for windows to receive notifications.
_LeaveMutex(); } LEAVECRITICAL;
_fEnabled = FALSE; } }
//+-------------------------------------------------------------------------
// Destructor - Destroys top-level window when last instance is destroyed
//--------------------------------------------------------------------------
CWinInetNotify::~CWinInetNotify() { Enable(FALSE); }
//+-------------------------------------------------------------------------
// Called for each top level window to find another one to accept wininet
// notifications.
//--------------------------------------------------------------------------
BOOL CALLBACK CWinInetNotify::EnumWindowsProc ( HWND hwnd, // handle to top-level window
LPARAM lParam // application-defined value
) { // Ignore our own window
if (hwnd == s_hwnd) return TRUE;
// See if it's one of our windows
TCHAR szWindowClass[30]; if (GetClassName(hwnd, szWindowClass, ARRAYSIZE(szWindowClass)) && StrCmp(CWinInetNotify_szWindowClass, szWindowClass) == 0) { _HookInetNotifications(hwnd); return FALSE; } return TRUE; } //+-------------------------------------------------------------------------
// Hooks up wininet notifications.
//--------------------------------------------------------------------------
void CWinInetNotify::_HookInetNotifications(HWND hwnd) { // We always want to know when cache items become sticky or unstickey
// or transition between online and offline
DWORD dwFlags = CACHE_NOTIFY_URL_SET_STICKY | CACHE_NOTIFY_URL_UNSET_STICKY | CACHE_NOTIFY_SET_ONLINE | CACHE_NOTIFY_SET_OFFLINE ;
//
// We only care about things being added to or removed from the
// cache when we are offline. The name-space-control greys unavailable
// items when we are offline.
//
if (SHIsGlobalOffline()) { dwFlags |= CACHE_NOTIFY_ADD_URL | CACHE_NOTIFY_DELETE_URL | CACHE_NOTIFY_DELETE_ALL; }
RegisterUrlCacheNotification(hwnd, CWM_WININETNOTIFY, 0, dwFlags, 0); }
//+-------------------------------------------------------------------------
// Re-broadcasts the notification using SHChangeNotify
//--------------------------------------------------------------------------
void CWinInetNotify::_OnNotify(DWORD_PTR dwFlags) { // Remove any other queued notifications
MSG msg; while (PeekMessage(&msg, s_hwnd, CWM_WININETNOTIFY, CWM_WININETNOTIFY, PM_REMOVE)) { // Combine the notification bits
dwFlags |= msg.wParam; }
SHChangeDWORDAsIDList dwidl; // Align for UNIX
dwidl.cb = (unsigned short) PtrDiff(& dwidl.cbZero, &dwidl); dwidl.dwItem1 = SHCNEE_WININETCHANGED; dwidl.dwItem2 = (DWORD)dwFlags; dwidl.cbZero = 0;
SHChangeNotify(SHCNE_EXTENDED_EVENT, SHCNF_FLUSH | SHCNF_FLUSHNOWAIT, (LPCITEMIDLIST)&dwidl, NULL);
// If we are switching between online and offline, we need to update the
// events that we are interested in.
if (dwFlags & (CACHE_NOTIFY_SET_ONLINE | CACHE_NOTIFY_SET_OFFLINE)) { _HookInetNotifications(s_hwnd); } }
//+-------------------------------------------------------------------------
// Window procedure for our invisible top-level window. Receives
// notifications from wininet.
//--------------------------------------------------------------------------
LRESULT CALLBACK CWinInetNotify::_WndProc(HWND hwnd, UINT uMessage, WPARAM wParam, LPARAM lParam) { switch (uMessage) { case WM_CREATE: { // Hook us up to get the notifications
_HookInetNotifications(hwnd); break; }
case CWM_WININETNOTIFY: { _OnNotify(wParam); return 0; } }
return DefWindowProcWrap(hwnd, uMessage, wParam, lParam); }
//+-------------------------------------------------------------------------
// Protect simultaneous access by multiple processes
//--------------------------------------------------------------------------
void CWinInetNotify::_EnterMutex() { ASSERT(_hMutex == NULL);
// This gets an existing mutex if one exists
_hMutex = CreateMutex(NULL, FALSE, CWinInetNotify_szWindowClass);
// Wait for up to 20 seconds
if (!_hMutex || WaitForSingleObject(_hMutex, 20000) == WAIT_TIMEOUT) { ASSERT(FALSE); } }
void CWinInetNotify::_LeaveMutex() { if (_hMutex) { ReleaseMutex(_hMutex); CloseHandle(_hMutex); _hMutex = NULL; } }
//+-------------------------------------------------------------------------
// Manages a global CWinInetNotify object
//--------------------------------------------------------------------------
void CWinInetNotify::GlobalEnable() { if (s_pWinInetNotify == NULL) { ENTERCRITICAL; if (s_pWinInetNotify == NULL) { s_pWinInetNotify = new CWinInetNotify(); if (s_pWinInetNotify) { s_pWinInetNotify->Enable(); } } LEAVECRITICAL; } }
void CWinInetNotify::GlobalDisable() { ENTERCRITICAL; if (s_pWinInetNotify) { delete s_pWinInetNotify; s_pWinInetNotify = NULL; } LEAVECRITICAL; }
|