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.

539 lines
14 KiB

  1. #include "private.h"
  2. #include <shlguid.h>
  3. #define TF_THISMODULE TF_WEBCHECKCORE
  4. DWORD g_idSchedThread = 0;
  5. // global containing pointer to instance of CWebcheck. Needed to control
  6. // externals loading on demand.
  7. CWebCheck *g_pwc = NULL;
  8. //////////////////////////////////////////////////////////////////////////
  9. //
  10. // CWebCheck implementation
  11. //
  12. //////////////////////////////////////////////////////////////////////////
  13. CWebCheck::CWebCheck()
  14. {
  15. // Maintain global object count
  16. DllAddRef();
  17. // Initialize object
  18. m_cRef = 1;
  19. // save our instance
  20. g_pwc = this;
  21. }
  22. CWebCheck::~CWebCheck()
  23. {
  24. // Maintain global object count
  25. DllRelease();
  26. // no longer available
  27. g_pwc = NULL;
  28. }
  29. //
  30. // IUnknown members
  31. //
  32. STDMETHODIMP_(ULONG) CWebCheck::AddRef(void)
  33. {
  34. // TraceMsg(TF_THISMODULE, "CWebCheck::AddRef m_cRef=%d", m_cRef+1);
  35. return ++m_cRef;
  36. }
  37. STDMETHODIMP_(ULONG) CWebCheck::Release(void)
  38. {
  39. // TraceMsg(TF_THISMODULE, "CWebCheck::Release m_cRef=%d", m_cRef-1);
  40. if( 0L != --m_cRef )
  41. return m_cRef;
  42. delete this;
  43. return 0L;
  44. }
  45. STDMETHODIMP CWebCheck::QueryInterface(REFIID riid, void ** ppv)
  46. {
  47. *ppv=NULL;
  48. // Validate requested interface
  49. if (IsEqualIID(riid, IID_IUnknown))
  50. *ppv = (IUnknown *)this;
  51. else if (IsEqualIID(riid, IID_IOleCommandTarget))
  52. *ppv = (IOleCommandTarget *)this;
  53. else
  54. return E_NOINTERFACE;
  55. // Addref through the interface
  56. ((LPUNKNOWN)*ppv)->AddRef();
  57. return S_OK;
  58. }
  59. //
  60. // IOleCommandTarget members
  61. // The shell will send notifications to us through this interface.
  62. //
  63. STDMETHODIMP CWebCheck::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds,
  64. OLECMD prgCmds[], OLECMDTEXT *pCmdText)
  65. {
  66. if (IsEqualGUID(*pguidCmdGroup, CGID_ShellServiceObject))
  67. {
  68. // We like Shell Service Object notifications...
  69. return S_OK;
  70. }
  71. return(OLECMDERR_E_UNKNOWNGROUP);
  72. }
  73. STDMETHODIMP CWebCheck::Exec(const GUID *pguidCmdGroup, DWORD nCmdID,
  74. DWORD nCmdexecopt, VARIANTARG *pvaIn,
  75. VARIANTARG *pvaOut)
  76. {
  77. if (pguidCmdGroup && IsEqualGUID(*pguidCmdGroup, CGID_ShellServiceObject))
  78. {
  79. // Handle Shell Service Object notifications here.
  80. switch (nCmdID)
  81. {
  82. case SSOCMDID_OPEN:
  83. StartService(FALSE);
  84. break;
  85. case SSOCMDID_CLOSE:
  86. StopService();
  87. break;
  88. }
  89. return S_OK;
  90. }
  91. return(E_NOTIMPL);
  92. }
  93. //
  94. // IWebCheck members
  95. //
  96. // Starts the webcheck service in a process
  97. STDMETHODIMP CWebCheck::StartService(BOOL fForceExternals)
  98. {
  99. DBG("CWebCheck::StartService entered");
  100. // reset offline mode for all platforms except NT5
  101. if(FALSE == g_fIsWinNT5)
  102. {
  103. HMODULE hWininet = GetModuleHandle(TEXT("WININET.DLL"));
  104. if(hWininet)
  105. {
  106. // wininet is loaded - tell it to go online
  107. INTERNET_CONNECTED_INFO ci;
  108. memset(&ci, 0, sizeof(ci));
  109. ci.dwConnectedState = INTERNET_STATE_CONNECTED;
  110. InternetSetOption(NULL, INTERNET_OPTION_CONNECTED_STATE, &ci, sizeof(ci));
  111. }
  112. else
  113. {
  114. // wininet not loaded - blow away offline reg key so we'll
  115. // be online when it does load
  116. DWORD dwOffline = 0; // FALSE => not offline
  117. WriteRegValue(HKEY_CURRENT_USER, c_szRegPathInternetSettings,
  118. TEXT("GlobalUserOffline"), &dwOffline, sizeof(DWORD), REG_DWORD);
  119. }
  120. }
  121. // create dialmon window
  122. DialmonInit();
  123. // Fire up LCE and sens if necessary
  124. if(fForceExternals || ShouldLoadExternals())
  125. LoadExternals();
  126. //
  127. // Process the Infodelivery Admin Policies on user login. (User login coincides
  128. // with webcheck's StartService() call.)
  129. //
  130. ProcessInfodeliveryPolicies();
  131. DBG("CWebCheck::StartService exiting");
  132. return S_OK;
  133. }
  134. // Stops Webcheck if running.
  135. STDMETHODIMP CWebCheck::StopService(void)
  136. {
  137. DBG("CWebCheck::StopService entered");
  138. // kill dialmon window
  139. DialmonShutdown();
  140. // shut down the external bits
  141. if(FALSE == g_fIsWinNT)
  142. UnloadExternals();
  143. DBG("CWebCheck::StopService exiting");
  144. return S_OK;
  145. }
  146. //
  147. // load behavior: (win9x)
  148. //
  149. // "auto" Load if on a laptop
  150. // "yes" Load always
  151. // "no" Load never
  152. //
  153. static const WCHAR s_szAuto[] = TEXT("auto");
  154. static const WCHAR s_szYes[] = TEXT("yes");
  155. static const WCHAR s_szNo[] = TEXT("no");
  156. BOOL CWebCheck::ShouldLoadExternals(void)
  157. {
  158. WCHAR szSens[16], szLce[16];
  159. DWORD cbData;
  160. //
  161. // don't load on NT
  162. //
  163. if(g_fIsWinNT)
  164. {
  165. DBG("CWebCheck::ShouldLoadExternals -> NO (NT)");
  166. return FALSE;
  167. }
  168. //
  169. // read sens/lce user settings - no setting means auto
  170. //
  171. cbData = sizeof(szLce);
  172. if(ERROR_SUCCESS != SHGetValueW(HKEY_LOCAL_MACHINE, c_szRegKey, L"LoadLCE", NULL, szLce, &cbData))
  173. {
  174. StrCpyW(szLce, s_szAuto);
  175. }
  176. cbData = sizeof(szSens);
  177. if(ERROR_SUCCESS != SHGetValueW(HKEY_LOCAL_MACHINE, c_szRegKey, L"LoadSens", NULL, szSens, &cbData))
  178. {
  179. StrCpyW(szSens, s_szAuto);
  180. }
  181. //
  182. // if either is yes, load
  183. //
  184. if(0 == StrCmpIW(szLce, s_szYes) || 0 == StrCmpIW(szSens, s_szYes))
  185. {
  186. DBG("CWebCheck::ShouldLoadExternals -> YES (reg = yes)");
  187. return TRUE;
  188. }
  189. //
  190. // if either is auto, check for laptop
  191. //
  192. if(0 == StrCmpIW(szLce, s_szAuto) || 0 == StrCmpIW(szSens, s_szAuto))
  193. {
  194. if(SHGetMachineInfo(GMI_LAPTOP))
  195. {
  196. // Is a laptop - load
  197. DBG("CWebCheck::ShouldLoadExternals -> YES (reg = auto, laptop)");
  198. return TRUE;
  199. }
  200. }
  201. // don't load
  202. DBG("CWebCheck::ShouldLoadExternals -> NO");
  203. return FALSE;
  204. }
  205. BOOL CWebCheck::AreExternalsLoaded(void)
  206. {
  207. return (_hThread != NULL);
  208. }
  209. void CWebCheck::LoadExternals(void)
  210. {
  211. DWORD dwThreadId;
  212. DBG("CWebCheck::LoadExternals");
  213. if(_hThread)
  214. {
  215. DBG("CWebCheck::LoadExternals - already loaded");
  216. return;
  217. }
  218. // fire up a thread to do the work
  219. _hThread = CreateThread(NULL, 4096, ExternalsThread, this, 0, &dwThreadId);
  220. if(NULL == _hThread) {
  221. DBG("LoadExternals failed to create externals thread!");
  222. return;
  223. }
  224. // create initializion and termination events
  225. //
  226. // [darrenmi 2/7/00] Wininet now tries to find this named mutex instead of querying
  227. // dialmon. It's the A version because wininet isn't unicode and OpenEventA can't
  228. // find events created with CreateEventW.
  229. //
  230. // See GetSensLanState in inet\wininet\dll\autodial.cxx.
  231. //
  232. _hTerminateEvent = CreateEventA(NULL, TRUE, FALSE, "MS_WebcheckExternalsTerminateEvent");
  233. if(NULL == _hTerminateEvent) {
  234. DBG("LoadExternals failed to create termination event");
  235. return;
  236. }
  237. DBG("CWebCheck::LoadExternals exiting");
  238. return;
  239. }
  240. void CWebCheck::UnloadExternals(void)
  241. {
  242. if(NULL == _hThread)
  243. {
  244. DBG("CWebCheck::UnloadExternals - nothing to unload");
  245. return;
  246. }
  247. // tell externals thread to go away by setting termination event
  248. SetEvent(_hTerminateEvent);
  249. // Give thread a 10 second grace period to shut down
  250. // don't really care if it goes away or not... our process is going away!
  251. WaitForSingleObject(_hThread, 10000);
  252. // clean up
  253. CloseHandle(_hThread);
  254. CloseHandle(_hTerminateEvent);
  255. _hThread = NULL;
  256. _hTerminateEvent = NULL;
  257. return;
  258. }
  259. DWORD WINAPI ExternalsThread(LPVOID lpData)
  260. {
  261. CWebCheck * pWebCheck = (CWebCheck *)lpData;
  262. HINSTANCE hLCE, hSENS = NULL;
  263. BOOL fLCEStarted = FALSE, fSENSStarted = FALSE;
  264. DWORD dwRet;
  265. MSG msg;
  266. // sleep for 10 seconds before firing off externals
  267. Sleep(10 * 1000);
  268. // fire up com
  269. HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
  270. if(FAILED(hr)) {
  271. DBG("LoadExternals: Failed to initialize COM");
  272. return 0;
  273. }
  274. // load and start LCE
  275. hLCE = LoadLibrary(TEXT("estier2.dll"));
  276. DBGASSERT(hLCE, "LoadExternals: Failed to load estier2.dll");
  277. if(hLCE) {
  278. LCESTART startfunc;
  279. startfunc = (LCESTART)GetProcAddress(hLCE, "LCEStartServer");
  280. DBGASSERT(startfunc, "LoadExternals: Failed to find LCEStartServer");
  281. if(startfunc) {
  282. hr = startfunc();
  283. if(SUCCEEDED(hr))
  284. fLCEStarted = TRUE;
  285. DBGASSERT(fLCEStarted, "LoadExternals: Failed to start LCE");
  286. }
  287. }
  288. // if LCE started sucessfully, load and start SENS
  289. if(fLCEStarted) {
  290. hSENS = LoadLibrary(TEXT("sens.dll"));
  291. DBGASSERT(hSENS, "LoadExternals: Failed to load sens.dll");
  292. if(hSENS) {
  293. SENSSTART startfunc;
  294. startfunc = (SENSSTART)GetProcAddress(hSENS, "SensInitialize");
  295. DBGASSERT(startfunc, "LoadExternals: Failed to find SensInitialize");
  296. if(startfunc) {
  297. if(startfunc())
  298. fSENSStarted = TRUE;
  299. DBGASSERT(fSENSStarted, "LoadExternals: Failed to start SENS");
  300. }
  301. }
  302. }
  303. // Wait for our shutdown event but pump messages in the mean time
  304. do {
  305. dwRet = MsgWaitForMultipleObjects(1, &(pWebCheck->_hTerminateEvent),
  306. FALSE, INFINITE, QS_ALLINPUT);
  307. if(WAIT_OBJECT_0 == dwRet) {
  308. // got our event, drop out of do loop
  309. break;
  310. }
  311. // empty the message queue...
  312. while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
  313. TranslateMessage(&msg);
  314. DispatchMessage(&msg);
  315. }
  316. } while(TRUE);
  317. // shut down SENS
  318. if(fSENSStarted) {
  319. ASSERT(hSENS);
  320. SENSSTOP stopfunc;
  321. stopfunc = (SENSSTOP)GetProcAddress(hSENS, "SensUninitialize");
  322. if(stopfunc) {
  323. stopfunc();
  324. }
  325. }
  326. //
  327. // [darrenmi] beta-1 hack: Sens may have a thread sitting in its code
  328. // at this point so it's not safe to unload sens. Since we're in the
  329. // process of shutting down anyway, just leave it alone and let the
  330. // system unload it.
  331. //
  332. //if(hSENS) {
  333. // FreeLibrary(hSENS);
  334. //}
  335. // shut down LCE
  336. if(fLCEStarted) {
  337. ASSERT(hLCE)
  338. LCESTOP stopfunc;
  339. stopfunc = (LCESTOP)GetProcAddress(hLCE, "LCEStopServer");
  340. if(stopfunc) {
  341. stopfunc();
  342. }
  343. }
  344. if(hLCE) {
  345. FreeLibrary(hLCE);
  346. }
  347. // clean up com goo
  348. CoUninitialize();
  349. return 0;
  350. }
  351. #if 0
  352. // TODO: need similar functionality in the new world
  353. void SetNotificationMgrRestrictions(INotificationProcessMgr0 *pNotfMgrProcess)
  354. {
  355. HRESULT hr;
  356. INotificationProcessMgr0 *pNotProcess = pNotfMgrProcess;
  357. // get NotificationMgr if it wasn't passed in
  358. if (!pNotfMgrProcess)
  359. {
  360. hr = CoCreateInstance(CLSID_StdNotificationMgr,
  361. NULL,
  362. CLSCTX_INPROC_SERVER,
  363. IID_INotificationProcessMgr0,
  364. (void**)&pNotProcess);
  365. DBGASSERT(SUCCEEDED(hr), "SetNotificationMgrRestrictions - failed to create notification mgr");
  366. }
  367. // set the restrictions
  368. if (pNotProcess)
  369. {
  370. const TCHAR c_szNoScheduledUpdates[] = TEXT("NoScheduledUpdates");
  371. THROTTLEITEM ti = {0};
  372. ti.NotificationType = NOTIFICATIONTYPE_AGENT_START;
  373. ti.nParallel = 3;
  374. // Has the user has disabled scheduled subscription updates?
  375. DWORD dwData;
  376. DWORD cbData = sizeof(dwData);
  377. if ((ERROR_SUCCESS == SHGetValue(HKEY_CURRENT_USER, c_szRegKey, c_szNoScheduledUpdates, NULL, &dwData, &cbData))
  378. && dwData)
  379. {
  380. ti.dwFlags |= TF_DONT_DELIVER_SCHEDULED_ITEMS;
  381. }
  382. // Has the administrator has disabled scheduled subscription updates?
  383. if (SHRestricted2W(REST_NoScheduledUpdates, NULL, 0))
  384. {
  385. ti.dwFlags |= TF_DONT_DELIVER_SCHEDULED_ITEMS;
  386. }
  387. // Has the administrator has excluded scheduled subscription updates
  388. // from this time range?
  389. DWORD dwBegin = SHRestricted2W(REST_UpdateExcludeBegin, NULL, 0);
  390. DWORD dwEnd = SHRestricted2W(REST_UpdateExcludeEnd, NULL, 0);
  391. if (dwBegin && dwEnd)
  392. {
  393. ti.dwFlags |= TF_APPLY_EXCLUDE_RANGE;
  394. ti.stBegin.wHour = (WORD)(dwBegin / 60);
  395. ti.stBegin.wMinute = (WORD)(dwBegin % 60);
  396. ti.stEnd.wHour = (WORD)(dwEnd / 60);
  397. ti.stEnd.wMinute = (WORD)(dwEnd %60);
  398. }
  399. // Has the admin set a minimum interval for scheduled subscription updates?
  400. dwData = SHRestricted2W(REST_MinUpdateInterval, NULL, 0);
  401. if (dwData)
  402. {
  403. ti.dwFlags |= TF_APPLY_UPDATEINTERVAL;
  404. ti.dwMinItemUpdateInterval = dwData;
  405. }
  406. hr = pNotProcess->RegisterThrottleNotificationType(1, &ti, 0, NULL, 0, 0);
  407. DBGASSERT(SUCCEEDED(hr), "SetNotificationMgrRestrictions - failed to register throttle type & restrictions");
  408. }
  409. // release NotificationMgr if it wasn't passed in
  410. if (!pNotfMgrProcess)
  411. {
  412. SAFERELEASE(pNotProcess);
  413. }
  414. }
  415. #endif
  416. //
  417. // OLE bypass code
  418. //
  419. // Expose a couple of APIs to call start and stop service so loadwc doesn't
  420. // need to load up OLE at start time.
  421. //
  422. HRESULT
  423. ExtStartService(
  424. BOOL fForceExternals
  425. )
  426. {
  427. HRESULT hr = E_FAIL;
  428. // make a webcheck object
  429. ASSERT(NULL == g_pwc);
  430. if(NULL == g_pwc)
  431. {
  432. g_pwc = new CWebCheck;
  433. if(g_pwc)
  434. {
  435. hr = g_pwc->StartService(fForceExternals);
  436. }
  437. }
  438. return hr;
  439. }
  440. HRESULT
  441. ExtStopService(
  442. void
  443. )
  444. {
  445. HRESULT hr = E_FAIL;
  446. if(g_pwc)
  447. {
  448. hr = g_pwc->StopService();
  449. SAFERELEASE(g_pwc);
  450. }
  451. return hr;
  452. }