Source code of Windows XP (NT5)
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.

274 lines
8.2 KiB

  1. #include "priv.h"
  2. #include "inetnot.h"
  3. //+-------------------------------------------------------------------------
  4. // Static initialization
  5. //--------------------------------------------------------------------------
  6. HWND CWinInetNotify::s_hwnd = NULL;
  7. ULONG CWinInetNotify::s_ulEnabled = 0;
  8. CWinInetNotify* CWinInetNotify::s_pWinInetNotify = NULL;
  9. //+-------------------------------------------------------------------------
  10. // Constructor - Creates invisible top-level window.
  11. //--------------------------------------------------------------------------
  12. CWinInetNotify::CWinInetNotify()
  13. : _hMutex(NULL),
  14. _fEnabled(FALSE)
  15. {
  16. }
  17. //+-------------------------------------------------------------------------
  18. // Enables/disables wininet notifications
  19. //--------------------------------------------------------------------------
  20. void CWinInetNotify::Enable(BOOL fEnable)
  21. {
  22. if (fEnable && !_fEnabled)
  23. {
  24. //
  25. // Enable the notifications
  26. //
  27. ENTERCRITICAL;
  28. ++s_ulEnabled;
  29. if (NULL == s_hwnd)
  30. {
  31. // create an invisible top-level window to receive notifications
  32. WNDCLASS wc;
  33. ZeroMemory(&wc, SIZEOF(wc));
  34. wc.lpfnWndProc = _WndProc;
  35. wc.hInstance = HINST_THISDLL;
  36. wc.lpszClassName = CWinInetNotify_szWindowClass;
  37. SHRegisterClass(&wc);
  38. s_hwnd = CreateWindow(CWinInetNotify_szWindowClass, NULL, WS_POPUP,
  39. 0, 0, 1, 1, NULL, NULL, HINST_THISDLL, this);
  40. }
  41. if (s_hwnd)
  42. {
  43. _fEnabled = TRUE;
  44. }
  45. LEAVECRITICAL;
  46. }
  47. else if (!fEnable && _fEnabled)
  48. {
  49. //
  50. // Disable the notifications
  51. //
  52. ENTERCRITICAL;
  53. if (--s_ulEnabled == 0)
  54. {
  55. //
  56. // We use a mutex here because we can have multiple instances of
  57. // iexplore. We want to avoid setting up a window to accept wininet
  58. // notifications if it is in the process of being destroyed.
  59. //
  60. _EnterMutex();
  61. // Look for another window to receive wininet notifications
  62. if (EnumWindows(EnumWindowsProc, NULL))
  63. {
  64. // No one left so turn off notifications
  65. RegisterUrlCacheNotification(0, 0, 0, 0, 0);
  66. }
  67. //
  68. // Handle any queued notifications.
  69. //
  70. // Note that we have a small window in which a notification
  71. // can be lost! Something could be posted to us after we are
  72. // destroyed!
  73. //
  74. MSG msg;
  75. if (PeekMessage(&msg, s_hwnd, CWM_WININETNOTIFY, CWM_WININETNOTIFY, PM_REMOVE))
  76. {
  77. _OnNotify(msg.wParam);
  78. }
  79. DestroyWindow(s_hwnd);
  80. s_hwnd = NULL;
  81. // Now that our window is gone, we can allow other processes to
  82. // look for windows to receive notifications.
  83. _LeaveMutex();
  84. }
  85. LEAVECRITICAL;
  86. _fEnabled = FALSE;
  87. }
  88. }
  89. //+-------------------------------------------------------------------------
  90. // Destructor - Destroys top-level window when last instance is destroyed
  91. //--------------------------------------------------------------------------
  92. CWinInetNotify::~CWinInetNotify()
  93. {
  94. Enable(FALSE);
  95. }
  96. //+-------------------------------------------------------------------------
  97. // Called for each top level window to find another one to accept wininet
  98. // notifications.
  99. //--------------------------------------------------------------------------
  100. BOOL CALLBACK CWinInetNotify::EnumWindowsProc
  101. (
  102. HWND hwnd, // handle to top-level window
  103. LPARAM lParam // application-defined value
  104. )
  105. {
  106. // Ignore our own window
  107. if (hwnd == s_hwnd)
  108. return TRUE;
  109. // See if it's one of our windows
  110. TCHAR szWindowClass[30];
  111. if (GetClassName(hwnd, szWindowClass, ARRAYSIZE(szWindowClass)) &&
  112. StrCmp(CWinInetNotify_szWindowClass, szWindowClass) == 0)
  113. {
  114. _HookInetNotifications(hwnd);
  115. return FALSE;
  116. }
  117. return TRUE;
  118. }
  119. //+-------------------------------------------------------------------------
  120. // Hooks up wininet notifications.
  121. //--------------------------------------------------------------------------
  122. void CWinInetNotify::_HookInetNotifications(HWND hwnd)
  123. {
  124. // We always want to know when cache items become sticky or unstickey
  125. // or transition between online and offline
  126. DWORD dwFlags = CACHE_NOTIFY_URL_SET_STICKY |
  127. CACHE_NOTIFY_URL_UNSET_STICKY |
  128. CACHE_NOTIFY_SET_ONLINE |
  129. CACHE_NOTIFY_SET_OFFLINE ;
  130. //
  131. // We only care about things being added to or removed from the
  132. // cache when we are offline. The name-space-control greys unavailable
  133. // items when we are offline.
  134. //
  135. if (SHIsGlobalOffline())
  136. {
  137. dwFlags |= CACHE_NOTIFY_ADD_URL | CACHE_NOTIFY_DELETE_URL | CACHE_NOTIFY_DELETE_ALL;
  138. }
  139. RegisterUrlCacheNotification(hwnd, CWM_WININETNOTIFY, 0, dwFlags, 0);
  140. }
  141. //+-------------------------------------------------------------------------
  142. // Re-broadcasts the notification using SHChangeNotify
  143. //--------------------------------------------------------------------------
  144. void CWinInetNotify::_OnNotify(DWORD_PTR dwFlags)
  145. {
  146. // Remove any other queued notifications
  147. MSG msg;
  148. while (PeekMessage(&msg, s_hwnd, CWM_WININETNOTIFY, CWM_WININETNOTIFY, PM_REMOVE))
  149. {
  150. // Combine the notification bits
  151. dwFlags |= msg.wParam;
  152. }
  153. SHChangeDWORDAsIDList dwidl;
  154. // Align for UNIX
  155. dwidl.cb = (unsigned short) PtrDiff(& dwidl.cbZero, &dwidl);
  156. dwidl.dwItem1 = SHCNEE_WININETCHANGED;
  157. dwidl.dwItem2 = (DWORD)dwFlags;
  158. dwidl.cbZero = 0;
  159. SHChangeNotify(SHCNE_EXTENDED_EVENT, SHCNF_FLUSH | SHCNF_FLUSHNOWAIT, (LPCITEMIDLIST)&dwidl, NULL);
  160. // If we are switching between online and offline, we need to update the
  161. // events that we are interested in.
  162. if (dwFlags & (CACHE_NOTIFY_SET_ONLINE | CACHE_NOTIFY_SET_OFFLINE))
  163. {
  164. _HookInetNotifications(s_hwnd);
  165. }
  166. }
  167. //+-------------------------------------------------------------------------
  168. // Window procedure for our invisible top-level window. Receives
  169. // notifications from wininet.
  170. //--------------------------------------------------------------------------
  171. LRESULT CALLBACK CWinInetNotify::_WndProc(HWND hwnd, UINT uMessage, WPARAM wParam, LPARAM lParam)
  172. {
  173. switch (uMessage)
  174. {
  175. case WM_CREATE:
  176. {
  177. // Hook us up to get the notifications
  178. _HookInetNotifications(hwnd);
  179. break;
  180. }
  181. case CWM_WININETNOTIFY:
  182. {
  183. _OnNotify(wParam);
  184. return 0;
  185. }
  186. }
  187. return DefWindowProcWrap(hwnd, uMessage, wParam, lParam);
  188. }
  189. //+-------------------------------------------------------------------------
  190. // Protect simultaneous access by multiple processes
  191. //--------------------------------------------------------------------------
  192. void CWinInetNotify::_EnterMutex()
  193. {
  194. ASSERT(_hMutex == NULL);
  195. // This gets an existing mutex if one exists
  196. _hMutex = CreateMutex(NULL, FALSE, CWinInetNotify_szWindowClass);
  197. // Wait for up to 20 seconds
  198. if (!_hMutex || WaitForSingleObject(_hMutex, 20000) == WAIT_TIMEOUT)
  199. {
  200. ASSERT(FALSE);
  201. }
  202. }
  203. void CWinInetNotify::_LeaveMutex()
  204. {
  205. if (_hMutex)
  206. {
  207. ReleaseMutex(_hMutex);
  208. CloseHandle(_hMutex);
  209. _hMutex = NULL;
  210. }
  211. }
  212. //+-------------------------------------------------------------------------
  213. // Manages a global CWinInetNotify object
  214. //--------------------------------------------------------------------------
  215. void CWinInetNotify::GlobalEnable()
  216. {
  217. if (s_pWinInetNotify == NULL)
  218. {
  219. ENTERCRITICAL;
  220. if (s_pWinInetNotify == NULL)
  221. {
  222. s_pWinInetNotify = new CWinInetNotify();
  223. if (s_pWinInetNotify)
  224. {
  225. s_pWinInetNotify->Enable();
  226. }
  227. }
  228. LEAVECRITICAL;
  229. }
  230. }
  231. void CWinInetNotify::GlobalDisable()
  232. {
  233. ENTERCRITICAL;
  234. if (s_pWinInetNotify)
  235. {
  236. delete s_pWinInetNotify;
  237. s_pWinInetNotify = NULL;
  238. }
  239. LEAVECRITICAL;
  240. }