windows-nt/Source/XPSP1/NT/shell/shdocvw/inetnot.cpp
2020-09-26 16:20:57 +08:00

275 lines
8.2 KiB
C++

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