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.

2181 lines
64 KiB

  1. //----------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1997
  5. //
  6. // File: update.cpp
  7. //
  8. // Contents: update subscriptions agent
  9. //
  10. // Classes:
  11. //
  12. // Functions:
  13. //
  14. // History: 01-14-1997 rayen (Raymond Endres) Created
  15. //
  16. //----------------------------------------------------------------------------
  17. //xnotfmgr - darremi owns this
  18. #include "private.h"
  19. #include "offline.h"
  20. #include "offl_cpp.h"
  21. #undef TF_THISMODULE
  22. #define TF_THISMODULE TF_UPDATEAGENT
  23. const IDMSG_NOTHING = 100 + IDCANCEL;
  24. const IDMSG_INITFAILED = 101 + IDCANCEL;
  25. const IDMSG_SESSIONEND = 102 + IDCANCEL;
  26. const IDMSG_UPDATEBEGIN = 103 + IDCANCEL;
  27. const IDMSG_UPDATEPROGRESS = 104 + IDCANCEL;
  28. const IDMSG_ADJUSTPROBAR = 105 + IDCANCEL;
  29. const TID_UPDATE = 7405; // TimerID
  30. const TID_STATISTICS = 1243; // TimerID for statistics update
  31. #define SHRESTARTDIALOG_ORDINAL 59 // restart only exported by ordinal
  32. typedef BOOL (WINAPI *SHRESTARTDIALOG)( HWND, LPTSTR, DWORD );
  33. CUpdateAgent * g_pUpdate = NULL;
  34. BOOL CUpdateDialog::m_bDetail = FALSE;
  35. CDialHelper::CDialHelper() : m_cRef(1),
  36. m_iDialerStatus(DIALER_OFFLINE)
  37. {
  38. ASSERT(0 == m_cConnection);
  39. ASSERT(NULL == m_pController);
  40. }
  41. STDMETHODIMP_(ULONG) CDialHelper::AddRef(void)
  42. {
  43. // DBG("CDialHelper::AddRef");
  44. return ++m_cRef;
  45. }
  46. STDMETHODIMP_(ULONG) CDialHelper::Release(void)
  47. {
  48. // DBG("CDialHelper::Release");
  49. if( 0L != --m_cRef )
  50. return m_cRef;
  51. DBG("CDialHelper::Release, ref count down to 0");
  52. ASSERT(!m_cConnection);
  53. ASSERT(m_iDialerStatus == DIALER_OFFLINE);
  54. if (m_iDialerStatus != DIALER_OFFLINE) {
  55. DBG("CDialHelper::Release, send disconnect message(abnormal)");
  56. NotifyAutoDialer(NOTIFICATIONTYPE_TASKS_COMPLETED);
  57. }
  58. SAFERELEASE(m_pNotMgr);
  59. PostThreadMessage(m_ThreadID, UM_DECREASE, 0, 0);
  60. delete this;
  61. return 0L;
  62. }
  63. STDMETHODIMP CDialHelper::QueryInterface(REFIID riid, void ** ppv)
  64. {
  65. // DBG("CDialHelper::QueryInterface");
  66. *ppv = NULL;
  67. if ((IID_IUnknown == riid) ||
  68. (IID_INotificationSink == riid))
  69. {
  70. *ppv = (INotificationSink *)this;
  71. }
  72. if( NULL != *ppv )
  73. {
  74. // DBG("CDialHelper::QueryInterface/AddRef");
  75. ((LPUNKNOWN)*ppv)->AddRef();
  76. return NOERROR;
  77. }
  78. return ResultFromScode(E_NOINTERFACE);
  79. }
  80. STDMETHODIMP CDialHelper::OnNotification(
  81. LPNOTIFICATION pNotification,
  82. LPNOTIFICATIONREPORT pNotificationReport,
  83. DWORD dwReserved)
  84. {
  85. // DBG("CDialHelper::OnNotification called");
  86. ASSERT(pNotification);
  87. // Extract Notification Type
  88. HRESULT hr;
  89. NOTIFICATIONTYPE notfType;
  90. hr = pNotification->GetNotificationInfo(&notfType, NULL, NULL, NULL, 0);
  91. ASSERT(SUCCEEDED(hr));
  92. if (NOTIFICATIONTYPE_PROGRESS_REPORT == notfType) {
  93. // get hresult from notification
  94. HRESULT hrConnect;
  95. ReadSCODE(pNotification, NULL, c_szPropStatusCode, &hrConnect);
  96. if(SUCCEEDED(hrConnect))
  97. return OnInetOnline(pNotification);
  98. else
  99. return OnInetOffline(pNotification);
  100. } else {
  101. DBG("CDialHelper::OnNotification - Unknown notification");
  102. return S_OK;
  103. }
  104. }
  105. STDMETHODIMP CDialHelper::Init(CUpdateController * pController)
  106. {
  107. ASSERT(pController);
  108. m_pController = pController;
  109. ASSERT(pController->m_pNotMgr);
  110. m_pNotMgr = pController->m_pNotMgr;
  111. m_ThreadID = pController->m_ThreadID;
  112. m_pNotMgr->AddRef();
  113. return S_OK;
  114. }
  115. STDMETHODIMP CDialHelper::DialOut(void)
  116. {
  117. HRESULT hr = S_OK;
  118. if (m_iDialerStatus == DIALER_OFFLINE) {
  119. DBG("CDialHelper::DialOut - Dialing Out");
  120. hr = NotifyAutoDialer(NOTIFICATIONTYPE_AGENT_START);
  121. if (SUCCEEDED(hr)) {
  122. m_iDialerStatus = DIALER_CONNECTING;
  123. m_cConnection ++;
  124. }
  125. }
  126. return hr;
  127. }
  128. STDMETHODIMP CDialHelper::HangUp(void)
  129. {
  130. m_cConnection --;
  131. if (!m_cConnection) {
  132. if (m_iDialerStatus != DIALER_OFFLINE) {
  133. DBG("CDialHelper::HangUp - Hanging up");
  134. m_iDialerStatus = DIALER_OFFLINE;
  135. NotifyAutoDialer(NOTIFICATIONTYPE_TASKS_COMPLETED);
  136. }
  137. }
  138. return S_OK;
  139. }
  140. STDMETHODIMP CDialHelper::CleanUp()
  141. {
  142. m_pController = NULL;
  143. return S_OK;
  144. }
  145. STDMETHODIMP CDialHelper::OnInetOnline(
  146. INotification *pNotification)
  147. {
  148. HRESULT hr=S_OK;
  149. if (m_iDialerStatus == DIALER_CONNECTING)
  150. {
  151. DBG("Dial Helper: CONNECTION SUCCESSFUL, BEGINNING DOWNLOAD");
  152. m_iDialerStatus = DIALER_ONLINE;
  153. if (m_pController)
  154. m_pController->StartService();
  155. else
  156. HangUp();
  157. }
  158. return hr;
  159. }
  160. STDMETHODIMP CDialHelper::OnInetOffline(
  161. INotification *pNotification)
  162. {
  163. DBG("Dial Helper: received InetOffline, aborting");
  164. SCODE eCode = S_OK;
  165. TCHAR szCaption[128];
  166. TCHAR szString[1024];
  167. CONNECT_ERROR error;
  168. if (m_iDialerStatus == DIALER_CONNECTING) {
  169. error = E_ATTEMPT_FAILED;
  170. } else {
  171. error = E_CONNECTION_LOST;
  172. }
  173. if (SUCCEEDED(ReadSCODE(pNotification, NULL, c_szPropStatusCode, & eCode))) {
  174. UINT uID;
  175. if (eCode == E_INVALIDARG) {
  176. uID = IDS_STRING_E_CONFIG;
  177. } else if (E_ABORT == eCode) {
  178. uID = IDS_STRING_E_SECURITYCHECK;
  179. } else {
  180. uID = IDS_STRING_E_FAILURE;
  181. }
  182. MLLoadString(uID, szString , ARRAYSIZE(szString));
  183. MLLoadString(IDS_CAPTION_ERROR_CONNECTING, szCaption, ARRAYSIZE(szCaption));
  184. MessageBox(NULL, szString, szCaption, MB_ICONWARNING | MB_SYSTEMMODAL);
  185. }
  186. if (m_pController)
  187. m_pController->StopService(error);
  188. else
  189. HangUp();
  190. m_iDialerStatus = DIALER_OFFLINE;
  191. return S_OK;
  192. }
  193. STDMETHODIMP CDialHelper::NotifyAutoDialer(NOTIFICATIONTYPE pType)
  194. {
  195. HRESULT hr;
  196. INotification * pNot = NULL;
  197. ASSERT(m_pNotMgr);
  198. hr = m_pNotMgr->CreateNotification(
  199. pType,
  200. (NOTIFICATIONFLAGS) 0,
  201. NULL,
  202. &pNot,
  203. 0);
  204. if (pNot)
  205. {
  206. INotificationSink *pSink = NULL;
  207. if (pType == NOTIFICATIONTYPE_AGENT_START)
  208. {
  209. DBG("CDialHelper::NotifyAutoDialer AGENT_START");
  210. pSink = (INotificationSink *)this;
  211. // HACK HACK [darrenmi] Until DZhang yanks out the umbrella code
  212. // we need something here - tell conn agent to let this connection
  213. // slide
  214. WriteAnsiSTR(pNot, NULL, c_szPropURL, TEXT("<override>"));
  215. // have not mgr deliver for us
  216. hr = m_pNotMgr->DeliverNotification(
  217. pNot,
  218. CLSID_ConnectionAgent,
  219. DM_NEED_COMPLETIONREPORT | DM_DELIVER_DEFAULT_PROCESS,
  220. pSink, &m_pConnAgentReport, 0);
  221. } else {
  222. DBG("CDialHelper::NotifyAutoDialer TASKS_COMPLETED");
  223. if(m_pConnAgentReport) {
  224. // deliver using the sink we've already got
  225. hr = m_pConnAgentReport->DeliverUpdate(pNot, 0, 0);
  226. TraceMsg(TF_THISMODULE, "CDialHelper::NotifyAutoDialer releasing report pointer");
  227. SAFERELEASE(m_pConnAgentReport);
  228. }
  229. }
  230. SAFERELEASE(pNot);
  231. }
  232. return hr;
  233. }
  234. DWORD WINAPI DialogThreadProc(LPVOID pData)
  235. {
  236. ASSERT(pData);
  237. CUpdateDialog * pDialog = (CUpdateDialog *)pData;
  238. MSG msg;
  239. pDialog->m_ThreadID = GetCurrentThreadId();
  240. while (GetMessage(&msg, NULL, 0, 0)) {
  241. switch (msg.message) {
  242. case UM_READY:
  243. {
  244. pDialog->Init(NULL, (CUpdateController *)msg.lParam);
  245. pDialog->Show(TRUE);
  246. }
  247. break;
  248. default:
  249. IsDialogMessage(pDialog->m_hDlg, &msg);
  250. break;
  251. }
  252. }
  253. #ifdef DEBUG
  254. if(g_fInitTable)
  255. LeakDetFunctionTable.pfnDebugMemLeak(DML_TYPE_THREAD | DML_END, TEXT(__FILE__), __LINE__);
  256. #endif
  257. DBG("DialogThreadProc returning");
  258. return 0;
  259. }
  260. // application subscription channels can force a reboot
  261. void DoReboot()
  262. {
  263. HRESULT hrReboot = S_OK;
  264. HINSTANCE hShell32Lib;
  265. DBG("UpdateThreadProc returning - attempting reboot");
  266. SHRESTARTDIALOG pfSHRESTARTDIALOG = NULL;
  267. if ((hShell32Lib = LoadLibrary("shell32.dll")) != NULL) {
  268. if (!(pfSHRESTARTDIALOG = (SHRESTARTDIALOG)
  269. GetProcAddress( hShell32Lib, MAKEINTRESOURCE(SHRESTARTDIALOG_ORDINAL)))) {
  270. hrReboot = HRESULT_FROM_WIN32(GetLastError());
  271. } else {
  272. // FEATURE: What hwnd to use?
  273. pfSHRESTARTDIALOG(NULL, NULL, EWX_REBOOT);
  274. }
  275. } else {
  276. hrReboot = HRESULT_FROM_WIN32(GetLastError());
  277. }
  278. if (hShell32Lib) {
  279. FreeLibrary(hShell32Lib);
  280. }
  281. }
  282. DWORD WINAPI UpdateThreadProc(LPVOID pData)
  283. {
  284. ASSERT(pData);
  285. CUpdateController * pController = (CUpdateController *) pData;
  286. INotification * pNotification = NULL;
  287. MSG msg;
  288. int l_cObj;
  289. BOOL bNeedReboot = FALSE;
  290. HRESULT hr = CoInitialize(NULL);
  291. if (FAILED(hr)) {
  292. DBG("UpdateThreadProc exiting, failed to CoInitialize.");
  293. return hr;
  294. }
  295. while (GetMessage(&msg, NULL, 0, 0)) {
  296. switch (msg.message) {
  297. case UM_ONREQUEST:
  298. if (!pController->m_fInit)
  299. break;
  300. pNotification = (INotification *)msg.lParam;
  301. // WARNING. There is a chance we fail in OnRequest (Failed to
  302. // send out Notification to dialer agent).
  303. hr = pController->OnRequest(pNotification);
  304. if (FAILED(hr)) {
  305. ASSERT(0);
  306. if ((!pController->m_count) && pController->m_pDialog)
  307. {
  308. PostMessage(pController->m_pDialog->m_hDlg,
  309. WM_COMMAND, IDMSG_SESSIONEND, 0);
  310. }
  311. }
  312. SAFERELEASE(pNotification);
  313. break;
  314. case UM_BACKGROUND:
  315. if (!pController->m_fInit)
  316. break;
  317. break;
  318. case UM_ONABORT:
  319. if (!pController->m_fInit)
  320. break;
  321. #ifdef DEBUG
  322. hr =
  323. #endif
  324. pController->Abort();
  325. #ifdef DEBUG
  326. ASSERT(SUCCEEDED(hr));
  327. #endif
  328. break;
  329. case UM_ONSKIP:
  330. if (!pController->m_fInit)
  331. break;
  332. #ifdef DEBUG
  333. hr =
  334. #endif
  335. pController->Skip();
  336. #ifdef DEBUG
  337. ASSERT(SUCCEEDED(hr));
  338. #endif
  339. break;
  340. case UM_ONADDSINGLE:
  341. if (!pController->m_fInit)
  342. break;
  343. MemFree((HLOCAL)msg.lParam);
  344. break;
  345. case UM_ONSKIPSINGLE:
  346. if (!pController->m_fInit)
  347. break;
  348. #ifdef DEBUG
  349. hr =
  350. #endif
  351. pController->SkipSingle((CLSID *)msg.lParam);
  352. MemFree((HLOCAL)msg.lParam);
  353. #ifdef DEBUG
  354. ASSERT(SUCCEEDED(hr));
  355. #endif
  356. break;
  357. case UM_CLEANUP:
  358. pController->CleanUp();
  359. pController->Release();
  360. break;
  361. case UM_READY:
  362. pController->AddRef();
  363. if (FAILED(pController->Init((CUpdateDialog *)msg.lParam))) {
  364. DBG("UpdateThreadProc - failed to init controller");
  365. CUpdateDialog * pDlg = (CUpdateDialog *)msg.lParam;
  366. PostMessage(pDlg->m_hDlg, WM_COMMAND, IDMSG_INITFAILED, 0);
  367. } else {
  368. l_cObj = 2;
  369. }
  370. break;
  371. case UM_DECREASE:
  372. l_cObj --;
  373. if (!l_cObj)
  374. goto QUIT;
  375. break;
  376. case UM_NEEDREBOOT:
  377. bNeedReboot = TRUE;
  378. break;
  379. default:
  380. TranslateMessage(&msg);
  381. DispatchMessage(&msg);
  382. break;
  383. }
  384. }
  385. QUIT: ;
  386. #ifdef DEBUG
  387. if(g_fInitTable)
  388. LeakDetFunctionTable.pfnDebugMemLeak(DML_TYPE_THREAD | DML_END, TEXT(__FILE__), __LINE__);
  389. #endif
  390. CoUninitialize();
  391. // This may need to be moved to a more appropriate location
  392. if (bNeedReboot)
  393. DoReboot();
  394. DBG("UpdateThreadProc returning");
  395. return 0;
  396. }
  397. STDMETHODIMP CUpdateController::ResyncData()
  398. {
  399. return S_OK;
  400. }
  401. STDMETHODIMP CUpdateController::StartPending(void)
  402. {
  403. HRESULT hr;
  404. DBG("CUpdateController::StartPending - entered");
  405. ASSERT(GetCurrentThreadId() == m_ThreadID);
  406. ASSERT(m_pDialer);
  407. ASSERT(m_pDialer->m_iDialerStatus == DIALER_ONLINE);
  408. for ( UINT ui = 0; ui < m_cReportCount; ui ++) {
  409. if (m_aReport[ui].status == ITEM_STAT_PENDING) {
  410. hr = DispatchRequest(&(m_aReport[ui]));
  411. ASSERT(SUCCEEDED(hr));
  412. }
  413. }
  414. return S_OK;
  415. }
  416. STDMETHODIMP CUpdateController::StartService(void)
  417. {
  418. HRESULT hr = S_OK;
  419. DBG("CUpdateController: Start Service");
  420. ASSERT(GetCurrentThreadId() == m_ThreadID);
  421. ASSERT(!m_cFinished);
  422. hr = StartPending();
  423. if (!m_count) {
  424. m_fSessionEnded = TRUE;
  425. m_pDialer->HangUp();
  426. if (m_pDialog)
  427. PostMessage(m_pDialog->m_hDlg, WM_COMMAND, IDMSG_SESSIONEND, 0);
  428. } else if (m_pDialog)
  429. PostMessage(m_pDialog->m_hDlg, WM_COMMAND, IDMSG_UPDATEBEGIN, 0);
  430. return S_OK;
  431. }
  432. STDMETHODIMP CUpdateController::StopService(CONNECT_ERROR err)
  433. {
  434. DBG("Update Controller: Stop Service, aborting");
  435. ASSERT(GetCurrentThreadId() == m_ThreadID);
  436. HRESULT hr;
  437. if (!m_count && (err == E_ATTEMPT_FAILED))
  438. {
  439. if (m_pDialer)
  440. m_pDialer->HangUp();
  441. }
  442. for ( UINT ui = 0; ui < m_cReportCount; ui ++) {
  443. switch (m_aReport[ui].status) {
  444. case ITEM_STAT_UPDATING:
  445. case ITEM_STAT_QUEUED:
  446. hr = CancelRequest(&(m_aReport[ui]));
  447. if (FAILED(hr))
  448. break;
  449. else
  450. ; // Fall through.
  451. case ITEM_STAT_PENDING:
  452. m_aReport[ui].status = ITEM_STAT_ABORTED;
  453. if (m_pDialog)
  454. m_pDialog->RefreshStatus(&(m_aReport[ui].startCookie), NULL,
  455. m_aReport[ui].status);
  456. break;
  457. default:
  458. break;
  459. }
  460. }
  461. if (!m_count) {
  462. m_fSessionEnded = TRUE;
  463. PostMessage(m_pDialog->m_hDlg, WM_COMMAND, IDMSG_SESSIONEND, 0);
  464. }
  465. return S_OK;
  466. }
  467. STDMETHODIMP CUpdateController::IncreaseCount()
  468. {
  469. ASSERT(m_count >= 0);
  470. InterlockedIncrement(&m_count);
  471. return S_OK;
  472. }
  473. STDMETHODIMP CUpdateController::DecreaseCount(CLSID * pCookie)
  474. {
  475. InterlockedDecrement(&m_count);
  476. ASSERT(m_count >= 0);
  477. m_cFinished ++;
  478. // check for growing subscriptions (this could be better)
  479. if (m_cFinished > m_cTotal)
  480. m_cTotal = m_cFinished;
  481. if (m_count == 0) {
  482. m_pDialer->HangUp();
  483. }
  484. if (m_pDialog) {
  485. PostMessage(m_pDialog->m_hDlg, WM_COMMAND, IDMSG_UPDATEPROGRESS, 0);
  486. if (!m_count) {
  487. m_fSessionEnded = TRUE;
  488. PostMessage(m_pDialog->m_hDlg, WM_COMMAND, IDMSG_SESSIONEND, 0);
  489. }
  490. }
  491. return S_OK;
  492. }
  493. STDMETHODIMP CUpdateController::GetItemList(UINT * pNewItem)
  494. {
  495. DBG("CUpdateController::GetItemList - entered");
  496. NOTIFICATIONITEM item;
  497. item.cbSize = sizeof(NOTIFICATIONITEM);
  498. ASSERT(m_pNotMgr);
  499. IEnumNotification * pEnumNot = NULL;
  500. HRESULT hr;
  501. ULONG cItems = 0;
  502. UINT count = 0;
  503. hr = m_pNotMgr->GetEnumNotification(0, &pEnumNot);
  504. RETURN_ON_FAILURE(hr);
  505. ASSERT(pEnumNot);
  506. hr = pEnumNot->Next(1, &item, &cItems);
  507. while (SUCCEEDED(hr) && cItems)
  508. {
  509. ASSERT(item.pNotification);
  510. if ((NOTIFICATIONTYPE_AGENT_START == item.NotificationType) &&
  511. (item.pNotification) &&
  512. (TASK_FLAG_HIDDEN & ~item.TaskData.dwTaskFlags))
  513. {
  514. SCODE scodeLast;
  515. STATUS statusLast;
  516. hr = ReadSCODE(item.pNotification, NULL, c_szPropStatusCode, &scodeLast);
  517. if (FAILED(scodeLast)) {
  518. statusLast = ITEM_STAT_FAILED;
  519. } else {
  520. statusLast = ITEM_STAT_SUCCEEDED;
  521. }
  522. hr = AddEntry(&item, statusLast);
  523. if (SUCCEEDED(hr)) {
  524. count ++;
  525. #ifdef DEBUG
  526. } else {
  527. DBGIID("CUpdateController::GetItemList - Failed to add entry", item.NotificationCookie);
  528. #endif
  529. }
  530. }
  531. SAFERELEASE(item.pNotification);
  532. item.cbSize = sizeof(NOTIFICATIONITEM);
  533. hr = pEnumNot->Next(1, &item, &cItems);
  534. }
  535. if (pNewItem)
  536. *pNewItem = count;
  537. SAFERELEASE(pEnumNot);
  538. return hr;
  539. }
  540. STDMETHODIMP CUpdateController::Abort(void)
  541. {
  542. DBG("CUpdateController::Abort - entered");
  543. ASSERT(GetCurrentThreadId() == m_ThreadID);
  544. ASSERT(m_pDialer);
  545. HRESULT hr = StopService(ITEM_STAT_ABORTED);
  546. return hr;
  547. }
  548. STDMETHODIMP CUpdateController::SkipSingle(CLSID * pCookie)
  549. {
  550. ASSERT(pCookie);
  551. if (!pCookie)
  552. return E_INVALIDARG;
  553. HRESULT hr = S_OK;
  554. PReportMap pEntry = FindReportEntry(pCookie);
  555. if (pEntry) {
  556. switch (pEntry->status) {
  557. case ITEM_STAT_UPDATING:
  558. case ITEM_STAT_QUEUED:
  559. hr = CancelRequest(pEntry);
  560. if (FAILED(hr))
  561. break;
  562. else
  563. ; // Fall through.
  564. case ITEM_STAT_PENDING:
  565. pEntry->status = ITEM_STAT_SKIPPED;
  566. if (m_pDialog)
  567. {
  568. m_pDialog->RefreshStatus(pCookie, NULL, pEntry->status);
  569. //select first updating item in list, which should be skippable
  570. m_pDialog->SelectFirstUpdatingSubscription();
  571. }
  572. break;
  573. default:
  574. break;
  575. }
  576. }
  577. return hr;
  578. }
  579. STDMETHODIMP CUpdateController::Skip(void)
  580. {
  581. DBG("CUpdateController::Skip - entered");
  582. HRESULT hr = S_OK;
  583. ASSERT(GetCurrentThreadId() == m_ThreadID);
  584. ASSERT(m_pDialog);
  585. UINT selCount = 0;
  586. hr = m_pDialog->GetSelectionCount(&selCount);
  587. if (FAILED(hr))
  588. return hr;
  589. if (!selCount)
  590. return S_OK;
  591. CLSID * pSelCookies = (CLSID *)MemAlloc(LPTR, sizeof(CLSID)*selCount);
  592. if (!pSelCookies)
  593. return E_OUTOFMEMORY;
  594. hr = m_pDialog->GetSelectedCookies(pSelCookies, &selCount);
  595. if (FAILED(hr)) {
  596. MemFree(pSelCookies); pSelCookies = NULL;
  597. return hr;
  598. }
  599. for (UINT ui = 0; ui < selCount; ui ++) {
  600. SkipSingle(pSelCookies + ui);
  601. }
  602. MemFree(pSelCookies); pSelCookies = NULL;
  603. return S_OK;
  604. }
  605. const GUIDSTR_LEN = GUIDSTR_MAX - 1;
  606. STDMETHODIMP CUpdateController::AddSingle(CLSID * pCookie)
  607. {
  608. ASSERT(pCookie);
  609. if (!pCookie)
  610. return E_INVALIDARG;
  611. HRESULT hr = E_FAIL;
  612. PReportMap pEntry = FindReportEntry(pCookie);
  613. if (!pEntry) {
  614. NOTIFICATIONITEM item;
  615. item.cbSize = sizeof(NOTIFICATIONITEM);
  616. ASSERT(m_pNotMgr);
  617. hr = m_pNotMgr->FindNotification(pCookie, &item, 0);
  618. if (FAILED(hr))
  619. return hr;
  620. ASSERT(item.pNotification);
  621. hr = E_FAIL;
  622. if ((NOTIFICATIONTYPE_AGENT_START == item.NotificationType) &&
  623. (item.pNotification) &&
  624. (TASK_FLAG_HIDDEN & ~item.TaskData.dwTaskFlags))
  625. {
  626. SCODE scodeLast;
  627. STATUS statusLast;
  628. hr = ReadSCODE(item.pNotification, NULL, c_szPropStatusCode, &scodeLast);
  629. if (FAILED(scodeLast)) {
  630. statusLast = ITEM_STAT_FAILED;
  631. } else {
  632. statusLast = ITEM_STAT_SUCCEEDED;
  633. }
  634. hr = AddEntry(&item, statusLast);
  635. #ifdef DEBUG
  636. if (FAILED(hr)) {
  637. DBGIID("CUpdateController::AddSingle - Failed to add new entry", item.NotificationCookie);
  638. }
  639. #endif
  640. }
  641. SAFERELEASE(item.pNotification);
  642. item.cbSize = sizeof(NOTIFICATIONITEM); // Why is this line here?
  643. if (FAILED(hr))
  644. return hr;
  645. pEntry = FindReportEntry(pCookie);
  646. ASSERT(pEntry);
  647. }
  648. if (pEntry) {
  649. switch (pEntry->status) {
  650. case ITEM_STAT_QUEUED:
  651. case ITEM_STAT_UPDATING:
  652. hr = S_FALSE;
  653. break;
  654. #ifdef DEBUG
  655. case ITEM_STAT_IDLE:
  656. ASSERT(0);
  657. break;
  658. #endif
  659. default:
  660. pEntry->status = ITEM_STAT_PENDING;
  661. if (m_pDialog)
  662. m_pDialog->RefreshStatus(pCookie,pEntry->name,pEntry->status);
  663. hr = S_OK;
  664. break;
  665. }
  666. }
  667. return hr;
  668. }
  669. STDMETHODIMP CUpdateController::Restart(UINT count)
  670. {
  671. if (!count)
  672. return S_OK;
  673. HRESULT hr = S_OK;
  674. m_cTotal = m_cTotal + count;
  675. if (m_pDialog)
  676. PostMessage(m_pDialog->m_hDlg, WM_COMMAND, IDMSG_ADJUSTPROBAR, 0);
  677. ASSERT(m_pDialer);
  678. if (m_pDialer->IsOffline()) {
  679. hr = m_pDialer->DialOut();
  680. } else if (m_pDialer->IsConnecting()) {
  681. ; // Nothing to do;
  682. } else {
  683. hr = StartPending();
  684. }
  685. return hr;
  686. }
  687. STDMETHODIMP CUpdateController::OnRequest(INotification * pNotification)
  688. {
  689. BOOL bUpdateAll = TRUE;
  690. HRESULT hr;
  691. UINT count = 0;
  692. DBG("CUpdateController::OnRequest - entered");
  693. ASSERT(GetCurrentThreadId() == m_ThreadID);
  694. // There is a chance that we are still receiving request even through
  695. // we have already ended the session.
  696. if (m_fSessionEnded)
  697. return S_FALSE; // We don't accept any more requests.
  698. if (pNotification) {
  699. VARIANT var;
  700. VariantInit(&var);
  701. // Right now (02/21/97) urlmon can't handle the SAFEARRAY.
  702. // We assembly this array of GUIDs as a BSTR in SendUpdateRequest
  703. // and disassembly it here.
  704. hr = pNotification->Read(c_szPropGuidsArr, &var);
  705. if (var.vt == VT_BSTR) {
  706. UINT bstrLen = 0;
  707. BSTR bstr = var.bstrVal;
  708. int guidCount, i;
  709. CLSID cookie;
  710. ASSERT(bstr);
  711. DBG("CUpdateController::OnRequest - found cookie list");
  712. bstrLen = lstrlenW(bstr);
  713. guidCount = bstrLen / GUIDSTR_LEN;
  714. SYSTEMTIME stNow;
  715. DATE dtNow;
  716. NOTIFICATIONITEM item;
  717. GetSystemTime(&stNow);
  718. SystemTimeToVariantTime(&stNow, &dtNow);
  719. item.cbSize = sizeof(NOTIFICATIONITEM);
  720. for (i = 0; i < guidCount; i ++) {
  721. BSTR bstrCookie = NULL;
  722. bstrCookie = SysAllocStringLen(bstr+i*GUIDSTR_LEN, GUIDSTR_LEN);
  723. hr = CLSIDFromString(bstrCookie, &cookie);
  724. #ifdef DEBUG
  725. DBGIID(TEXT("On request to update "), cookie);
  726. #endif
  727. SysFreeString(bstrCookie);
  728. if (FAILED(hr))
  729. continue;
  730. if (S_OK == AddSingle(&cookie))
  731. count ++;
  732. }
  733. hr = Restart(count);
  734. VariantClear(&var);
  735. return hr;
  736. } else {
  737. VariantClear(&var);
  738. }
  739. }
  740. DBG("CUpdateController::OnRequest - Update all");
  741. for ( UINT ui = 0; ui < m_cReportCount; ui ++) {
  742. switch (m_aReport[ui].status) {
  743. #ifdef DEBUG
  744. case ITEM_STAT_IDLE:
  745. ASSERT(0);
  746. break;
  747. #endif
  748. case ITEM_STAT_UPDATING:
  749. case ITEM_STAT_QUEUED:
  750. break;
  751. default:
  752. m_aReport[ui].status = ITEM_STAT_PENDING;
  753. if (m_pDialog)
  754. m_pDialog->RefreshStatus(&(m_aReport[ui].startCookie),
  755. m_aReport[ui].name,
  756. m_aReport[ui].status);
  757. count ++;
  758. break;
  759. }
  760. }
  761. hr = Restart(count);
  762. return hr;
  763. }
  764. CUpdateController::CUpdateController() : m_fInit(FALSE), m_fSessionEnded(FALSE)
  765. {
  766. m_pNotMgr = NULL;
  767. m_pDialog = NULL;
  768. m_pDialer = NULL;
  769. m_cRef = 1;
  770. }
  771. CUpdateController::~CUpdateController()
  772. {
  773. ASSERT(0L == m_cRef);
  774. }
  775. STDMETHODIMP_(ULONG) CUpdateController::AddRef(void)
  776. {
  777. // DBG("CUpdateController::AddRef");
  778. return ++m_cRef;
  779. }
  780. STDMETHODIMP_(ULONG) CUpdateController::Release(void)
  781. {
  782. // DBG("CUpdateController::Release");
  783. if( 0L != --m_cRef )
  784. return m_cRef;
  785. DBG("Destroying Controller object");
  786. m_fInit = FALSE;
  787. PostThreadMessage(m_ThreadID, UM_DECREASE, 0, 0);
  788. SAFERELEASE(m_pNotMgr);
  789. if (m_pDialer) {
  790. m_pDialer->CleanUp();
  791. SAFERELEASE(m_pDialer);
  792. }
  793. m_pDialog = NULL;
  794. for (UINT ui = 0; ui < m_cReportCount; ui ++) {
  795. SAFELOCALFREE(m_aReport[ui].name);
  796. SAFELOCALFREE(m_aReport[ui].url);
  797. }
  798. SAFELOCALFREE(m_aReport);
  799. delete this;
  800. return 0L;
  801. }
  802. STDMETHODIMP CUpdateController::QueryInterface(REFIID riid, void ** ppv)
  803. {
  804. // DBG("CUpdateController::QueryInterface");
  805. *ppv = NULL;
  806. if ((IID_IUnknown == riid) ||
  807. (IID_INotificationSink == riid))
  808. {
  809. *ppv = (INotificationSink *)this;
  810. }
  811. if( NULL != *ppv )
  812. {
  813. ((LPUNKNOWN)*ppv)->AddRef();
  814. return S_OK;
  815. }
  816. return E_NOINTERFACE;
  817. }
  818. STDMETHODIMP CUpdateController::Init(CUpdateDialog * pDialog)
  819. {
  820. DBG("CUpdateController::Init");
  821. ASSERT( !m_pNotMgr );
  822. ASSERT(pDialog);
  823. ASSERT(!m_fInit);
  824. m_pDialog = pDialog;
  825. m_cReportCount = m_cReportCapacity = 0;
  826. m_ThreadID = GetCurrentThreadId();
  827. ASSERT (!m_aReport);
  828. m_aReport = (PReportMap)MemAlloc(LPTR, sizeof(ReportMapEntry) * CUC_ENTRY_INCRE);
  829. if (!m_aReport) {
  830. DBG("CUpdateController::Init - Out of mem");
  831. return E_OUTOFMEMORY;
  832. }
  833. m_cReportCapacity = CUC_ENTRY_INCRE;
  834. HRESULT hr = CoCreateInstance(CLSID_StdNotificationMgr, NULL,
  835. CLSCTX_INPROC_SERVER, IID_INotificationMgr,(void **)&m_pNotMgr);
  836. if (SUCCEEDED(hr)) {
  837. m_pDialer = new CDialHelper;
  838. if (!m_pDialer) {
  839. DBG("CUpdateController::Init - Failed to dialer");
  840. hr = E_OUTOFMEMORY;
  841. } else {
  842. m_pDialer->AddRef();
  843. hr = m_pDialer->Init(this);
  844. }
  845. }
  846. if (SUCCEEDED(hr)) {
  847. m_cFinished = m_cTotal = 0;
  848. m_count = 0;
  849. m_fInit = TRUE;
  850. GetItemList(NULL);
  851. if ((!m_cReportCount) && (m_pDialog)) { // Didn't find nothing.
  852. PostMessage(m_pDialog->m_hDlg, WM_COMMAND, IDMSG_NOTHING, 0);
  853. }
  854. } else {
  855. SAFERELEASE(m_pNotMgr);
  856. SAFERELEASE(m_pDialer);
  857. }
  858. return hr;
  859. }
  860. // REARCHITECT: Copied from NotificationMgr code (notifctn.hxx)
  861. #define WZ_COOKIE L"Notification_COOKIE"
  862. //
  863. // INotificationSink member(s)
  864. //
  865. STDMETHODIMP CUpdateController::OnNotification(
  866. LPNOTIFICATION pNotification,
  867. LPNOTIFICATIONREPORT pNotificationReport,
  868. DWORD dwReserved)
  869. {
  870. DBG("CUpdateController::OnNotification called");
  871. ASSERT(pNotification);
  872. HRESULT hr;
  873. NOTIFICATIONTYPE notfType;
  874. ASSERT(GetCurrentThreadId() == m_ThreadID);
  875. // Extract Notification Type
  876. hr = pNotification->GetNotificationInfo(&notfType, NULL, NULL, NULL, 0);
  877. ASSERT(SUCCEEDED(hr));
  878. if (FAILED(hr)) {
  879. return E_INVALIDARG;
  880. }
  881. if (notfType == NOTIFICATIONTYPE_END_REPORT)
  882. {
  883. //
  884. // Except those we fail to DeliverNotification in the first place for
  885. // each request we will get an End Report when we finished the current
  886. // update or aborted/skipped the current update.
  887. //
  888. DBG("CUpdateController::OnNotification - END REPORT");
  889. CLSID cookie;
  890. PReportMap pEntry = NULL;
  891. if (SUCCEEDED(ReadGUID(pNotification, NULL, c_szStartCookie, &cookie)))
  892. {
  893. pEntry = FindReportEntry(&cookie);
  894. }
  895. if (!pEntry) {
  896. DBGIID("CUpdateController::OnNotification(END_REPORT) - invalid cookie", cookie);
  897. return E_FAIL;
  898. }
  899. //update count of total kbytes downloaded with size of this site from end report
  900. DWORD dwCrawlKBytes;
  901. if (SUCCEEDED (ReadDWORD (pNotification, NULL, c_szPropCrawlActualSize, &dwCrawlKBytes)))
  902. {
  903. if (m_pDialog) {
  904. DWORD dwKBytesPrevious = m_pDialog->SetSiteDownloadSize (&cookie, dwCrawlKBytes);
  905. m_pDialog->m_cDlKBytes += dwCrawlKBytes - dwKBytesPrevious;
  906. SendMessage (m_pDialog->m_hDlg, WM_TIMER, TID_STATISTICS, 0); //force update
  907. }
  908. }
  909. switch (pEntry->status) {
  910. case ITEM_STAT_UPDATING :
  911. {
  912. SCODE eCode = S_OK;
  913. hr = ReadSCODE(pNotification, NULL, c_szPropStatusCode, & eCode);
  914. ASSERT(SUCCEEDED(hr));
  915. if (FAILED(eCode)) {
  916. pEntry->status = ITEM_STAT_FAILED;
  917. } else {
  918. pEntry->status = ITEM_STAT_SUCCEEDED;
  919. }
  920. if (m_pDialog) {
  921. m_pDialog->RefreshStatus(&cookie, NULL, pEntry->status);
  922. PostMessage(m_pDialog->m_hDlg, WM_COMMAND,
  923. IDMSG_UPDATEPROGRESS, 100 - pEntry->progress);
  924. }
  925. pEntry->progress = 0;
  926. break;
  927. }
  928. case ITEM_STAT_SKIPPED:
  929. case ITEM_STAT_ABORTED:
  930. ASSERT(!(pEntry->progress));
  931. break;
  932. default:
  933. ASSERT(0);
  934. break;
  935. }
  936. return S_OK;
  937. }
  938. else if (notfType == NOTIFICATIONTYPE_TASKS_COMPLETED
  939. || notfType == NOTIFICATIONTYPE_TASKS_ERROR)
  940. {
  941. DBG("CUpdateController::OnNotification - TASKS_ENDED");
  942. CLSID cookie;
  943. PReportMap pEntry = NULL;
  944. if (SUCCEEDED(ReadGUID(pNotification, NULL, WZ_COOKIE, &cookie)))
  945. {
  946. pEntry = FindReportEntry(&cookie);
  947. }
  948. if (!pEntry) {
  949. DBGIID("\t(TASKS_ENDED) - invalid cookie ", cookie);
  950. return E_FAIL;
  951. } else {
  952. DBGIID("\t(TASKS_ENDED) - cookie ", cookie);
  953. }
  954. DecreaseCount(&cookie);
  955. switch (pEntry->status) {
  956. case ITEM_STAT_UPDATING :
  957. {
  958. if (notfType == NOTIFICATIONTYPE_TASKS_ERROR) {
  959. pEntry->status = ITEM_STAT_FAILED;
  960. } else {
  961. pEntry->status = ITEM_STAT_SUCCEEDED;
  962. }
  963. if (m_pDialog) {
  964. m_pDialog->RefreshStatus(&cookie, NULL, pEntry->status);
  965. PostMessage(m_pDialog->m_hDlg, WM_COMMAND,
  966. IDMSG_UPDATEPROGRESS, 100 - pEntry->progress);
  967. }
  968. pEntry->progress = 0;
  969. break;
  970. }
  971. case ITEM_STAT_SKIPPED:
  972. case ITEM_STAT_ABORTED:
  973. ASSERT(!(pEntry->progress));
  974. break;
  975. case ITEM_STAT_QUEUED:
  976. pEntry->status = ITEM_STAT_ABORTED;
  977. if (m_pDialog) {
  978. m_pDialog->RefreshStatus(&cookie, NULL, pEntry->status);
  979. PostMessage(m_pDialog->m_hDlg, WM_COMMAND,
  980. IDMSG_UPDATEPROGRESS, 100 - pEntry->progress);
  981. }
  982. pEntry->progress = 0;
  983. break;
  984. default:
  985. ASSERT(!(pEntry->progress));
  986. break;
  987. }
  988. return S_OK;
  989. }
  990. else if (notfType == NOTIFICATIONTYPE_PROGRESS_REPORT)
  991. {
  992. DBG("CUpdateController::OnNotification - progress report");
  993. CLSID cookie;
  994. PReportMap pEntry = NULL;
  995. if (SUCCEEDED(ReadGUID(pNotification, NULL, c_szStartCookie, &cookie)))
  996. {
  997. pEntry = FindReportEntry(&cookie);
  998. }
  999. if (!pEntry) {
  1000. DBGIID("CUpdateController::OnNotification(PROGRESS_REPORT) - invalid cookie", cookie);
  1001. return E_FAIL;
  1002. }
  1003. //start a document dl -- update count and status indicators
  1004. if (m_pDialog) {
  1005. BSTR bCurrentUrl;
  1006. TCHAR szCurrentUrl[MAX_URL + 1];
  1007. if (SUCCEEDED(ReadBSTR(pNotification, NULL, c_szPropCurrentURL, &bCurrentUrl)))
  1008. {
  1009. //does not appear to be a real BSTR (with length byte) -- just an OLESTR
  1010. MyOleStrToStrN (szCurrentUrl, MAX_URL, bCurrentUrl);
  1011. SAFEFREEBSTR(bCurrentUrl);
  1012. m_pDialog->RefreshStatus(&cookie, NULL, pEntry->status, szCurrentUrl);
  1013. //update size of download
  1014. DWORD dwKBytesCurrent;
  1015. if (SUCCEEDED (ReadDWORD (pNotification, NULL, c_szPropCurrentSize, &dwKBytesCurrent))
  1016. && (dwKBytesCurrent != -1))
  1017. {
  1018. DWORD dwKBytesPrevious = m_pDialog->SetSiteDownloadSize (&cookie, dwKBytesCurrent);
  1019. m_pDialog->m_cDlKBytes += dwKBytesCurrent - dwKBytesPrevious;
  1020. }
  1021. ++m_pDialog->m_cDlDocs; //increase number of docs downloaded
  1022. SendMessage (m_pDialog->m_hDlg, WM_TIMER, TID_STATISTICS, 0); //force update
  1023. }
  1024. }
  1025. DWORD dwProgress;
  1026. DWORD dwProgressMax;
  1027. if (SUCCEEDED(ReadDWORD(pNotification, NULL, c_szPropProgressMax, &dwProgressMax)) && SUCCEEDED(ReadDWORD(pNotification, NULL, c_szPropProgress, &dwProgress)))
  1028. {
  1029. // (INT)dwProgressMax could be -1!
  1030. if ((((INT)dwProgress) >= 0) && (((INT)dwProgressMax) >= 0)) {
  1031. ASSERT(dwProgress <= dwProgressMax);
  1032. // The progress report is sent at the beginning of current
  1033. // download. We should substrat Progress by 1.
  1034. UINT cProgress, cProgressMax, newPercentage;
  1035. cProgress = (dwProgress)?dwProgress - 1:0;
  1036. cProgressMax = dwProgressMax;
  1037. newPercentage = MulDiv(cProgress, 100, cProgressMax);
  1038. if ((newPercentage > pEntry->progress) && m_pDialog) {
  1039. PostMessage(m_pDialog->m_hDlg, WM_COMMAND,
  1040. IDMSG_UPDATEPROGRESS,
  1041. (LPARAM)(newPercentage - pEntry->progress));
  1042. }
  1043. pEntry->progress = newPercentage;
  1044. }
  1045. }
  1046. return S_OK;
  1047. }
  1048. else if (notfType == NOTIFICATIONTYPE_BEGIN_REPORT)
  1049. {
  1050. DBG("CUpdateController::OnNotification - begin report");
  1051. CLSID cookie;
  1052. PReportMap pEntry = NULL;
  1053. if (SUCCEEDED(ReadGUID(pNotification, NULL, c_szStartCookie, &cookie)))
  1054. {
  1055. pEntry = FindReportEntry(&cookie);
  1056. }
  1057. if (!pEntry) {
  1058. DBGIID("CUpdateController::OnNotification(BEGIN_REPORT) - invalid cookie", cookie);
  1059. return E_FAIL;
  1060. }
  1061. if (pEntry->status == ITEM_STAT_UPDATING)
  1062. return S_OK;
  1063. // Note there is a case that we send out the 'Abort' notification to
  1064. // the agent, and the agent sends 'begin report' at almost the same
  1065. // time. In that case we can get begin-report when we think we already
  1066. // cancelled the update.
  1067. if (pEntry->status != ITEM_STAT_QUEUED) {
  1068. ASSERT((pEntry->status == ITEM_STAT_SKIPPED) ||
  1069. (pEntry->status == ITEM_STAT_ABORTED));
  1070. return S_OK; // We bail out.
  1071. }
  1072. pEntry->status = ITEM_STAT_UPDATING;
  1073. if (m_pDialog)
  1074. m_pDialog->RefreshStatus(&cookie, NULL, ITEM_STAT_UPDATING);
  1075. return S_OK;
  1076. }
  1077. else if (notfType == NOTIFICATIONTYPE_TASKS_STARTED)
  1078. {
  1079. DBG("CUpdateController::OnNotification - TASKS_STARTED");
  1080. CLSID cookie;
  1081. PReportMap pEntry = NULL;
  1082. if (SUCCEEDED(ReadGUID(pNotification, NULL, WZ_COOKIE, &cookie)))
  1083. {
  1084. pEntry = FindReportEntry(&cookie);
  1085. }
  1086. if (!pEntry) {
  1087. DBGIID("\t(TASKS_STARTED) - invalid cookie ", cookie);
  1088. return E_FAIL;
  1089. } else {
  1090. DBGIID("\t(TASKS_STARTED) - cookie ", cookie);
  1091. }
  1092. ASSERT(pEntry->status == ITEM_STAT_QUEUED);
  1093. if (pEntry->status != ITEM_STAT_QUEUED) {
  1094. ASSERT((pEntry->status == ITEM_STAT_SKIPPED) ||
  1095. (pEntry->status == ITEM_STAT_ABORTED));
  1096. return S_OK; // We bail out.
  1097. }
  1098. pEntry->status = ITEM_STAT_UPDATING;
  1099. if (m_pDialog)
  1100. m_pDialog->RefreshStatus(&cookie, NULL, ITEM_STAT_UPDATING);
  1101. return S_OK;
  1102. }
  1103. else
  1104. {
  1105. DBG("CUpdateController::OnNotification - unknown notification");
  1106. return S_OK;
  1107. }
  1108. }
  1109. STDMETHODIMP CUpdateController::DispatchRequest(PReportMap pEntry)
  1110. {
  1111. DBG("CUpdateController::Dispatch - entered");
  1112. ASSERT(pEntry);
  1113. ASSERT(m_pNotMgr);
  1114. ASSERT(m_pDialog);
  1115. ASSERT(ITEM_STAT_PENDING == pEntry->status);
  1116. HRESULT hr;
  1117. NOTIFICATIONITEM item;
  1118. item.cbSize = sizeof(item);
  1119. hr = m_pNotMgr->FindNotification(&(pEntry->startCookie), &item, 0);
  1120. ASSERT(SUCCEEDED(hr));
  1121. if (SUCCEEDED(hr)) {
  1122. hr = m_pNotMgr->DeliverNotification(item.pNotification,
  1123. item.clsidDest,
  1124. DM_DELIVER_DEFAULT_PROCESS |
  1125. DM_NEED_COMPLETIONREPORT |
  1126. DM_NEED_PROGRESSREPORT |
  1127. DM_THROTTLE_MODE,
  1128. (INotificationSink *)this,
  1129. NULL,
  1130. 0);
  1131. SAFERELEASE(item.pNotification);
  1132. if (FAILED(hr)) {
  1133. DBG("CUpdateController::Dispatch - failed to DeliverNotification");
  1134. m_pDialog->RefreshStatus(&(pEntry->startCookie), NULL, ITEM_STAT_FAILED);
  1135. } else {
  1136. DBG("Increase Count");
  1137. pEntry->status = ITEM_STAT_QUEUED;
  1138. pEntry->progress = 0;
  1139. IncreaseCount();
  1140. }
  1141. }
  1142. return hr;
  1143. }
  1144. // In CancelRequest() we only attempt to send out the notification of
  1145. // abort. The count on agent side will be decreased when we get end report.
  1146. // So matched number of request and end report is crucial.
  1147. STDMETHODIMP CUpdateController::CancelRequest(PReportMap pEntry)
  1148. {
  1149. ASSERT(pEntry);
  1150. if ((ITEM_STAT_UPDATING != pEntry->status)
  1151. && (ITEM_STAT_QUEUED != pEntry->status))
  1152. return S_OK;
  1153. ASSERT(m_pNotMgr);
  1154. HRESULT hr = S_OK;
  1155. INotification *pNot = NULL;
  1156. hr = m_pNotMgr->CreateNotification(NOTIFICATIONTYPE_TASKS_ABORT,
  1157. (NOTIFICATIONFLAGS)0,
  1158. NULL,
  1159. &pNot,
  1160. 0);
  1161. ASSERT(SUCCEEDED(hr));
  1162. if (SUCCEEDED(hr))
  1163. {
  1164. if (SUCCEEDED(hr))
  1165. {
  1166. hr = m_pNotMgr->DeliverReport(pNot, &(pEntry->startCookie), 0);
  1167. if (SUCCEEDED(hr)) {
  1168. if (m_pDialog) {
  1169. PostMessage(m_pDialog->m_hDlg, WM_COMMAND,
  1170. IDMSG_UPDATEPROGRESS, 100 - pEntry->progress);
  1171. }
  1172. pEntry->progress = 0;
  1173. // This is the default status afterwards.
  1174. pEntry->status = ITEM_STAT_ABORTED;
  1175. } else {
  1176. TraceMsg(TF_THISMODULE, TEXT("CancelRequest:Error:%x"), hr);
  1177. }
  1178. } else {
  1179. DBG("CUpdateController::Stop failed");
  1180. }
  1181. SAFERELEASE(pNot);
  1182. }
  1183. return hr;
  1184. }
  1185. PReportMap CUpdateController::FindReportEntry(CLSID * pCookie)
  1186. {
  1187. ASSERT(pCookie);
  1188. for (UINT ui = 0; ui < m_cReportCount; ui ++) {
  1189. if (m_aReport[ui].startCookie == * pCookie) {
  1190. return &(m_aReport[ui]);
  1191. }
  1192. }
  1193. return NULL;
  1194. }
  1195. STDMETHODIMP CUpdateController::GetLocationOf(CLSID * pCookie, LPTSTR pszText, UINT cchTextMax)
  1196. {
  1197. ASSERT(pCookie && pszText);
  1198. PReportMap pEntry = FindReportEntry(pCookie);
  1199. if (pEntry) {
  1200. lstrcpyn(pszText, pEntry->url, cchTextMax);
  1201. } else {
  1202. lstrcpyn(pszText, c_szStrEmpty, cchTextMax);
  1203. }
  1204. return S_OK;
  1205. }
  1206. SUBSCRIPTIONTYPE CUpdateController::GetSubscriptionType(CLSID * pCookie)
  1207. {
  1208. ASSERT(pCookie);
  1209. SUBSCRIPTIONTYPE subType = SUBSTYPE_EXTERNAL;
  1210. PReportMap pEntry = FindReportEntry(pCookie);
  1211. if (pEntry) {
  1212. subType = pEntry->subType;
  1213. }
  1214. return subType;
  1215. }
  1216. BOOL CUpdateController::IsSkippable(CLSID * pCookie)
  1217. {
  1218. ASSERT(pCookie);
  1219. PReportMap pEntry = FindReportEntry(pCookie);
  1220. if (pEntry)
  1221. if (pEntry->status == ITEM_STAT_PENDING ||
  1222. pEntry->status == ITEM_STAT_QUEUED ||
  1223. pEntry->status == ITEM_STAT_UPDATING)
  1224. {
  1225. return TRUE;
  1226. }
  1227. return FALSE;
  1228. }
  1229. STDMETHODIMP CUpdateController::AddEntry(NOTIFICATIONITEM *pItem, STATUS status)
  1230. {
  1231. ASSERT(pItem);
  1232. ASSERT(m_cReportCount <= m_cReportCapacity);
  1233. if (m_cReportCount == m_cReportCapacity) {
  1234. UINT newSize = m_cReportCapacity + CUC_ENTRY_INCRE;
  1235. ASSERT(newSize <= CUC_MAX_ENTRY);
  1236. HLOCAL newBuf = MemReAlloc(m_aReport, newSize * sizeof(ReportMapEntry), LHND);
  1237. if (!newBuf) {
  1238. DBG("CUpdateController::AddEntry - Failed to realloc");
  1239. return E_OUTOFMEMORY;
  1240. }
  1241. m_aReport = (PReportMap)(newBuf);
  1242. m_cReportCapacity = newSize;
  1243. }
  1244. m_aReport[m_cReportCount].startCookie = pItem->NotificationCookie;
  1245. m_aReport[m_cReportCount].progress = 0;
  1246. m_aReport[m_cReportCount].status = status;
  1247. OOEBuf ooeBuf;
  1248. DWORD dwSize = 0;
  1249. ZeroMemory((void *)&ooeBuf, sizeof(ooeBuf));
  1250. HRESULT hr = LoadOOEntryInfo(&ooeBuf, pItem, &dwSize);
  1251. if (S_OK != hr)
  1252. {
  1253. if (FAILED(hr))
  1254. return hr;
  1255. else
  1256. return E_FAIL;
  1257. }
  1258. LPTSTR nameStr = NULL, urlStr = NULL;
  1259. nameStr = (LPTSTR)MemAlloc(LPTR, (lstrlen(ooeBuf.m_Name) + 1) * sizeof(TCHAR));
  1260. urlStr = (LPTSTR)MemAlloc(LPTR, (lstrlen(ooeBuf.m_URL) + 1) * sizeof(TCHAR));
  1261. if (!(nameStr && urlStr)) {
  1262. SAFELOCALFREE(nameStr);
  1263. SAFELOCALFREE(urlStr);
  1264. return E_OUTOFMEMORY;
  1265. }
  1266. lstrcpy(nameStr, ooeBuf.m_Name);
  1267. lstrcpy(urlStr, ooeBuf.m_URL);
  1268. m_aReport[m_cReportCount].name = nameStr;
  1269. m_aReport[m_cReportCount].url = urlStr;
  1270. m_aReport[m_cReportCount].subType = GetItemCategory(&ooeBuf);
  1271. m_cReportCount ++;
  1272. return S_OK;
  1273. }
  1274. STDMETHODIMP CUpdateController::CleanUp()
  1275. {
  1276. m_pDialog = NULL;
  1277. return S_OK;
  1278. }
  1279. //////////////////////////////////////////////////////////////////////////
  1280. //
  1281. // CUpdateAgent
  1282. //
  1283. // The only reason we need this class is that so we can create the
  1284. // dialog in the different thread.
  1285. CUpdateAgent::CUpdateAgent()
  1286. {
  1287. DBG("Creating CUpdateAgent object");
  1288. ASSERT(!(m_pDialog || m_pController));
  1289. }
  1290. CUpdateAgent::~CUpdateAgent()
  1291. {
  1292. DBG("Destroying CUpdateAgent object");
  1293. if (m_pController) {
  1294. PostThreadMessage(m_ThreadID, UM_CLEANUP, 0,0);
  1295. m_pController = NULL;
  1296. }
  1297. if (m_pDialog) {
  1298. // delete m_pDialog;
  1299. // m_pDialog will be destroyed by m_pController in CleanUp.
  1300. m_pDialog = NULL;
  1301. }
  1302. g_pUpdate = NULL;
  1303. }
  1304. STDMETHODIMP CUpdateAgent::Init(void)
  1305. {
  1306. DBG("CUpdateAgent::Init");
  1307. HRESULT hr = S_OK;
  1308. ASSERT(!(m_pDialog || m_pController));
  1309. if (SUCCEEDED(hr)) {
  1310. m_pDialog = new CUpdateDialog;
  1311. if (!m_pDialog) {
  1312. DBG("CUpdateAgent::Init - Failed to create dialog");
  1313. hr = E_OUTOFMEMORY;
  1314. }
  1315. }
  1316. if (SUCCEEDED(hr)) {
  1317. m_pController = new CUpdateController;
  1318. if (!m_pController) {
  1319. DBG("CUpdateAgent::Init - Failed to create download controller");
  1320. hr = E_OUTOFMEMORY;
  1321. }
  1322. }
  1323. if (SUCCEEDED(hr)) {
  1324. HANDLE hThread;
  1325. hThread = CreateThread(NULL, 0, DialogThreadProc,
  1326. (LPVOID)m_pDialog, 0, &m_DialogThreadID);
  1327. if (!hThread) {
  1328. DBG("CUpdateAgent::Init - Failed to create dialog thread");
  1329. hr = E_FAIL;
  1330. } else {
  1331. int i = 0;
  1332. while ( i < 3) {
  1333. if (PostThreadMessage(m_DialogThreadID, UM_READY, 0, (LPARAM)m_pController))
  1334. break;
  1335. i ++;
  1336. Sleep(1000);
  1337. }
  1338. // Is there a safer way to do this?
  1339. if (i >= 3) {
  1340. ASSERT(0);
  1341. hr = E_FAIL;
  1342. }
  1343. CloseHandle(hThread);
  1344. }
  1345. }
  1346. if (SUCCEEDED(hr)) {
  1347. HANDLE hThread;
  1348. hThread = CreateThread(NULL, 0, UpdateThreadProc,
  1349. (LPVOID)m_pController, 0, &m_ThreadID);
  1350. if (!hThread) {
  1351. DBG("CUpdateAgent::Init - Failed to create thread");
  1352. hr = E_FAIL;
  1353. } else {
  1354. int i = 0;
  1355. while ( i < 3) {
  1356. if (PostThreadMessage(m_ThreadID, UM_READY, 0, (LPARAM)m_pDialog))
  1357. break;
  1358. i ++;
  1359. Sleep(1000);
  1360. }
  1361. // FEATURE: Is there a safer way to do this?
  1362. if (i >= 3) {
  1363. ASSERT(0);
  1364. hr = E_FAIL;
  1365. }
  1366. SetThreadPriority(hThread, THREAD_PRIORITY_IDLE);
  1367. CloseHandle(hThread);
  1368. }
  1369. if (FAILED(hr)) {
  1370. PostThreadMessage(m_DialogThreadID, WM_QUIT, 0, 0);
  1371. }
  1372. }
  1373. if (FAILED(hr)) {
  1374. if (m_pController) {
  1375. delete m_pController;
  1376. m_pController = NULL;
  1377. }
  1378. if (m_pDialog) {
  1379. delete m_pDialog;
  1380. m_pDialog = NULL;
  1381. }
  1382. }
  1383. return hr;
  1384. }
  1385. BOOL ListView_OnNotify(HWND hDlg, NM_LISTVIEW* plvn, CUpdateController * pController)
  1386. {
  1387. ASSERT(plvn && pController);
  1388. CUpdateDialog * pDialog = pController->m_pDialog;
  1389. if (!pDialog)
  1390. return FALSE; // If m_pDialog is NULL, we haven't call Init
  1391. // for pController on second thread yet.
  1392. HRESULT hr;
  1393. switch (plvn->hdr.code) {
  1394. case LVN_ITEMCHANGED:
  1395. {
  1396. if (!(plvn->uChanged & LVIF_STATE))
  1397. break;
  1398. UINT uOldState = plvn->uOldState & LVIS_SELECTED;
  1399. UINT uNewState = plvn->uNewState & LVIS_SELECTED;
  1400. UINT count = 0;
  1401. hr = pDialog->GetSelectionCount(&count);
  1402. if (FAILED(hr))
  1403. break;
  1404. HWND hButton = GetDlgItem(hDlg, IDCMD_SKIP);
  1405. BOOL fEnable = FALSE;
  1406. if (count) {
  1407. CLSID cookie;
  1408. int iItem = plvn->iItem;
  1409. hr = pDialog->IItem2Cookie(iItem, &cookie);
  1410. if (SUCCEEDED(hr)) {
  1411. fEnable = pController->IsSkippable(&cookie);
  1412. }
  1413. }
  1414. Button_Enable(hButton, fEnable);
  1415. return TRUE;
  1416. }
  1417. default:
  1418. break;
  1419. }
  1420. return FALSE;
  1421. }
  1422. void ResizeDialog(HWND hDlg, BOOL bShowDetail)
  1423. {
  1424. ASSERT(hDlg);
  1425. RECT rcDlg, rcChild;
  1426. HWND hSplitter, hLV;
  1427. TCHAR szButton[32];
  1428. //calculate margin (upper-left position of IDC_SIZENODETAILS)
  1429. GetWindowRect(GetDlgItem (hDlg, IDC_SIZENODETAILS), &rcChild);
  1430. MapWindowPoints(NULL, hDlg, (LPPOINT)&rcChild, 2);
  1431. int iMargin = rcChild.left;
  1432. GetWindowRect(hDlg, &rcDlg);
  1433. if (bShowDetail) {
  1434. hLV = GetDlgItem(hDlg, IDL_SUBSCRIPTION);
  1435. ASSERT(hLV);
  1436. GetWindowRect(hLV, &rcChild);
  1437. rcDlg.bottom = rcChild.bottom + iMargin + GetSystemMetrics (SM_CXSIZEFRAME);
  1438. rcDlg.right = rcChild.right + iMargin + GetSystemMetrics (SM_CYSIZEFRAME);
  1439. LONG dwStyle = GetWindowLong (hDlg, GWL_STYLE);
  1440. dwStyle = dwStyle | WS_MAXIMIZEBOX | WS_THICKFRAME;
  1441. SetWindowLong (hDlg, GWL_STYLE, dwStyle);
  1442. rcDlg.left -= (GetSystemMetrics (SM_CXSIZEFRAME) - GetSystemMetrics (SM_CXFIXEDFRAME));
  1443. rcDlg.top -= (GetSystemMetrics (SM_CYSIZEFRAME) - GetSystemMetrics (SM_CYFIXEDFRAME));
  1444. MoveWindow(hDlg, rcDlg.left, rcDlg.top,
  1445. rcDlg.right - rcDlg.left,
  1446. rcDlg.bottom - rcDlg.top,
  1447. TRUE);
  1448. MLLoadString(IDS_NODETAILS, szButton, ARRAYSIZE(szButton));
  1449. } else {
  1450. hSplitter = GetDlgItem(hDlg, IDC_SIZENODETAILS);
  1451. ASSERT(hSplitter);
  1452. GetWindowRect(hSplitter, &rcChild);
  1453. LONG dwStyle = GetWindowLong (hDlg, GWL_STYLE);
  1454. dwStyle = dwStyle & ~WS_MAXIMIZEBOX & ~WS_THICKFRAME;
  1455. SetWindowLong (hDlg, GWL_STYLE, dwStyle);
  1456. MoveWindow(hDlg, rcDlg.left + (GetSystemMetrics (SM_CXSIZEFRAME) - GetSystemMetrics (SM_CXFIXEDFRAME)),
  1457. rcDlg.top + (GetSystemMetrics (SM_CYSIZEFRAME) - GetSystemMetrics (SM_CYFIXEDFRAME)),
  1458. rcChild.right - rcDlg.left,
  1459. rcChild.bottom - rcDlg.top,
  1460. TRUE);
  1461. MLLoadString(IDS_DETAILS, szButton, ARRAYSIZE(szButton));
  1462. }
  1463. SetDlgItemText(hDlg, IDCMD_DETAILS, szButton);
  1464. }
  1465. void UpdateStatistics (HWND hDlg, int nFiles, int nKBytes, int nSeconds)
  1466. {
  1467. TCHAR szStats[128], szFormat[64];
  1468. MLLoadString (IDS_STATISTICS, szFormat, ARRAYSIZE(szFormat));
  1469. wnsprintf (szStats, ARRAYSIZE(szStats), szFormat,
  1470. nFiles, nKBytes, nSeconds/60, nSeconds%60);
  1471. SetDlgItemText (hDlg, IDC_STATISTICS, szStats);
  1472. }
  1473. void DrawResizeWidget (HWND hDlg) //copied from athena's CGroupListDlg::OnPaint
  1474. {
  1475. PAINTSTRUCT ps;
  1476. RECT rc;
  1477. GetClientRect(hDlg, &rc);
  1478. rc.left = rc.right - GetSystemMetrics(SM_CXSMICON);
  1479. rc.top = rc.bottom - GetSystemMetrics(SM_CYSMICON);
  1480. BeginPaint(hDlg, &ps);
  1481. if (CUpdateDialog::m_bDetail && !IsZoomed(hDlg))
  1482. DrawFrameControl(ps.hdc, &rc, DFC_SCROLL, DFCS_SCROLLSIZEGRIP);
  1483. CUpdateDialog * pDialog = (CUpdateDialog *)GetWindowLong(hDlg, DWL_USER);
  1484. if (pDialog != NULL)
  1485. {
  1486. pDialog->m_cxWidget = rc.left;
  1487. pDialog->m_cyWidget = rc.top;
  1488. }
  1489. EndPaint(hDlg, &ps);
  1490. }
  1491. void EraseResizeWidget (HWND hDlg)
  1492. {
  1493. CUpdateDialog * pDialog = (CUpdateDialog *)GetWindowLong(hDlg, DWL_USER);
  1494. RECT rWidget;
  1495. if (pDialog != NULL)
  1496. {
  1497. //invalidate resize widget
  1498. rWidget.left = pDialog->m_cxWidget;
  1499. rWidget.top = pDialog->m_cyWidget;
  1500. rWidget.right = pDialog->m_cxWidget + GetSystemMetrics(SM_CXSMICON);
  1501. rWidget.bottom = pDialog->m_cyWidget + GetSystemMetrics(SM_CYSMICON);
  1502. InvalidateRect(hDlg, &rWidget, FALSE);
  1503. // pDialog->m_cxWidget = rWidget.left;
  1504. // pDialog->m_cxWidget = rWidget.top;
  1505. }
  1506. }
  1507. extern BOOL GetSubscriptionFolderPath(LPTSTR);
  1508. //----------------------------------------------------------------------------
  1509. // UpdateDlgProc function
  1510. //----------------------------------------------------------------------------
  1511. BOOL CALLBACK UpdateDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1512. {
  1513. static DWORD dwStartTicks;
  1514. CUpdateDialog * pDialog = (CUpdateDialog *)GetWindowLong(hDlg, DWL_USER);
  1515. CUpdateController * pController = (pDialog)?pDialog->m_pController:NULL;
  1516. switch (uMsg)
  1517. {
  1518. case WM_INITDIALOG :
  1519. {
  1520. DBG("DLGBOX: Creating dialog box.");
  1521. ASSERT(lParam);
  1522. ASSERT(GetWindowLong(hDlg, DWL_USER) == 0);
  1523. SetWindowLong(hDlg, DWL_USER, lParam);
  1524. SetForegroundWindow(hDlg);
  1525. TCHAR szString[1024];
  1526. MLLoadString(IDS_CONNECTING, szString, ARRAYSIZE(szString));
  1527. SetDlgItemText(hDlg, IDC_AGENTSTATUS, szString);
  1528. ResizeDialog(hDlg, CUpdateDialog::m_bDetail);
  1529. SetTimer (hDlg, TID_STATISTICS, 1000, NULL);
  1530. dwStartTicks = GetTickCount();
  1531. // Check current keyboard layout is IME or not
  1532. if (((DWORD)GetKeyboardLayout(0) & 0xF0000000L) == 0xE0000000L)
  1533. {
  1534. HWND hwndIME = ImmGetDefaultIMEWnd(hDlg);
  1535. if (hwndIME)
  1536. SendMessage(hwndIME, WM_IME_NOTIFY, IMN_CLOSESTATUSWINDOW, 0);
  1537. }
  1538. return FALSE; // keep the focus on the dialog
  1539. }
  1540. case WM_ACTIVATE:
  1541. if (LOWORD(wParam) != WA_INACTIVE)
  1542. {
  1543. // Check current keyboard layout is IME or not
  1544. if (((DWORD)GetKeyboardLayout(0) & 0xF0000000L) == 0xE0000000L)
  1545. {
  1546. HWND hwndIME = ImmGetDefaultIMEWnd(hDlg);
  1547. if (hwndIME)
  1548. SendMessage(hwndIME, WM_IME_NOTIFY, IMN_CLOSESTATUSWINDOW, 0);
  1549. }
  1550. }
  1551. break;
  1552. case WM_NOTIFY :
  1553. switch (LOWORD (wParam)) {
  1554. case IDL_SUBSCRIPTION:
  1555. if (!pController)
  1556. break;
  1557. return ListView_OnNotify(hDlg, (NM_LISTVIEW *)lParam, pController);
  1558. default:
  1559. return FALSE;
  1560. }
  1561. break;
  1562. case WM_TIMER:
  1563. switch (wParam)
  1564. {
  1565. case TID_UPDATE:
  1566. KillTimer(hDlg, wParam);
  1567. pDialog->CleanUp();
  1568. SetWindowLong(hDlg, DWL_USER, 0);
  1569. delete pDialog;
  1570. return TRUE;
  1571. case TID_STATISTICS:
  1572. UpdateStatistics (hDlg, pDialog->m_cDlDocs, pDialog->m_cDlKBytes,
  1573. (GetTickCount() - dwStartTicks)/1000);
  1574. return TRUE;
  1575. }
  1576. break;
  1577. case WM_GETMINMAXINFO :
  1578. if (CUpdateDialog::m_bDetail)
  1579. {
  1580. LPMINMAXINFO lpmmi = (LPMINMAXINFO)lParam;
  1581. DWORD style = GetWindowLong (hDlg, GWL_STYLE);
  1582. RECT smallest;
  1583. GetWindowRect (GetDlgItem (hDlg, IDC_MINBORDER), &smallest);
  1584. AdjustWindowRect (&smallest, style, FALSE);
  1585. lpmmi->ptMinTrackSize.x = smallest.right - smallest.left;
  1586. lpmmi->ptMinTrackSize.y = smallest.bottom - smallest.top;
  1587. return 0;
  1588. }
  1589. break;
  1590. case WM_PAINT:
  1591. DrawResizeWidget (hDlg);
  1592. break;
  1593. case WM_SIZE:
  1594. if (wParam == SIZE_MAXIMIZED || wParam == SIZE_RESTORED)
  1595. {
  1596. const int CHILDREN[] = { IDCMD_HIDE, IDCMD_ABORT, IDCMD_DETAILS, IDCMD_SKIP };
  1597. int width = LOWORD(lParam), height = HIWORD(lParam);
  1598. RECT rChild;
  1599. int child;
  1600. //calculate margin (upper-left position of IDC_SIZENODETAILS)
  1601. GetWindowRect(GetDlgItem (hDlg, IDC_SIZENODETAILS), &rChild);
  1602. // Use MapWindowPints for mirroring
  1603. MapWindowPoints(NULL, hDlg, (LPPOINT)&rChild, 2);
  1604. int iMargin = rChild.left;
  1605. for (child = 0; child < sizeof(CHILDREN)/sizeof(CHILDREN[0]); child++)
  1606. {
  1607. GetWindowRect (GetDlgItem (hDlg, CHILDREN[child]), &rChild);
  1608. MapWindowPoints(NULL, hDlg, (LPPOINT)&rChild, 2);
  1609. SetWindowPos (GetDlgItem (hDlg, CHILDREN[child]), 0,
  1610. width - iMargin - (rChild.right - rChild.left), rChild.top,
  1611. 0, 0, SWP_NOSIZE | SWP_NOZORDER);
  1612. }
  1613. if (CUpdateDialog::m_bDetail) //only apply to bottom half
  1614. {
  1615. EraseResizeWidget (hDlg);
  1616. GetWindowRect (GetDlgItem (hDlg, IDD_SPLITTER), &rChild);
  1617. MapWindowPoints(NULL, hDlg, (LPPOINT)&rChild, 2); SetWindowPos (GetDlgItem (hDlg, IDD_SPLITTER), 0,
  1618. 0, 0, width - 2 * rChild.left, rChild.bottom - rChild.top,
  1619. SWP_NOMOVE | SWP_NOZORDER | SWP_NOCOPYBITS); //for some reason there's a weird redraw bug on this control -- NOCOPYBITS fixes it
  1620. GetWindowRect (GetDlgItem (hDlg, IDL_SUBSCRIPTION), &rChild);
  1621. MapWindowPoints(NULL, hDlg, (LPPOINT)&rChild, 2); SetWindowPos (GetDlgItem (hDlg, IDL_SUBSCRIPTION), 0,
  1622. 0, 0, width - rChild.left - iMargin, height - rChild.top - iMargin,
  1623. SWP_NOMOVE | SWP_NOZORDER);
  1624. }
  1625. return 0;
  1626. }
  1627. break;
  1628. case WM_CLOSE:
  1629. KillTimer (hDlg, TID_STATISTICS);
  1630. break;
  1631. case WM_COMMAND :
  1632. {
  1633. if (!pController) {
  1634. if (IDCANCEL == LOWORD (wParam)) {
  1635. KillTimer(hDlg, TID_UPDATE);
  1636. pDialog->CleanUp();
  1637. SetWindowLong(hDlg, DWL_USER, 0);
  1638. delete pDialog;
  1639. return TRUE;
  1640. } else {
  1641. break;
  1642. }
  1643. }
  1644. HWND hProgress = GetDlgItem(hDlg, IDD_PROBAR);
  1645. HWND hAnimate = GetDlgItem(hDlg, IDD_ANIMATE);
  1646. TCHAR szString[1024];
  1647. switch (LOWORD (wParam))
  1648. {
  1649. case IDMSG_SESSIONEND: // Stop dialog, session concludes.
  1650. DBG("UpdateDlgProc - all updates are complete");
  1651. pController->m_cTotal = pController->m_cFinished = 0;
  1652. pDialog->m_pController = pController = NULL;
  1653. delete g_pUpdate;
  1654. MessageBeep(0xFFFFFFFF);
  1655. Animate_Close(hAnimate);
  1656. ShowWindow(hAnimate, SW_HIDE);
  1657. MLLoadString(IDS_SESSIONEND, szString, ARRAYSIZE(szString));
  1658. SetDlgItemText(hDlg, IDC_AGENTSTATUS, szString);
  1659. ShowWindow (GetDlgItem (hDlg, IDC_AGENTSTATUS), SW_SHOW);
  1660. Button_Enable(GetDlgItem(hDlg, IDCMD_ABORT), FALSE);
  1661. Button_Enable(GetDlgItem(hDlg, IDCMD_DETAILS), FALSE);
  1662. SetTimer(hDlg, TID_UPDATE, 3000, NULL);
  1663. KillTimer (hDlg, TID_STATISTICS);
  1664. return TRUE;
  1665. case IDMSG_UPDATEBEGIN:
  1666. {
  1667. DBG("UpdateDlgProc - Start updating");
  1668. SetForegroundWindow(hDlg);
  1669. ShowWindow (hAnimate, SW_SHOW);
  1670. ShowWindow (GetDlgItem (hDlg, IDC_AGENTSTATUS), SW_HIDE);
  1671. Animate_Open(hAnimate, IDA_DOWNLOAD);
  1672. Animate_Play(hAnimate, 0, -1, -1);
  1673. return TRUE;
  1674. }
  1675. case IDMSG_ADJUSTPROBAR:
  1676. {
  1677. ASSERT(pController->m_cTotal);
  1678. ASSERT(pController->m_cFinished <= pController->m_cTotal);
  1679. SendMessage(hProgress, PBM_SETRANGE32,
  1680. 0, pController->m_cTotal * 100);
  1681. SendMessage(hProgress, PBM_SETPOS,
  1682. pController->m_cFinished * 100, 0);
  1683. return TRUE;
  1684. }
  1685. case IDMSG_NOTHING: // Nothing to show yet.
  1686. {
  1687. DBG("UpdateDlgProc - No item found");
  1688. MLLoadString(IDS_STRING_NOTHING_TO_UPDATE,
  1689. szString , ARRAYSIZE(szString));
  1690. SetDlgItemText(hDlg, IDC_AGENTSTATUS, szString);
  1691. pController->m_cTotal = pController->m_cFinished = 0;
  1692. pDialog->m_pController = pController = NULL;
  1693. delete g_pUpdate;
  1694. MessageBeep(0xFFFFFFFF);
  1695. Button_Enable(GetDlgItem(hDlg, IDCMD_ABORT), FALSE);
  1696. Button_Enable(GetDlgItem(hDlg, IDCMD_DETAILS), FALSE);
  1697. SetTimer(hDlg, TID_UPDATE, 3000, NULL);
  1698. KillTimer (hDlg, TID_STATISTICS);
  1699. return TRUE;
  1700. }
  1701. case IDMSG_UPDATEPROGRESS:
  1702. SendMessage(hProgress, PBM_DELTAPOS, lParam, 0);
  1703. return TRUE;
  1704. case IDMSG_INITFAILED:
  1705. DBG("UpdateDlgProc - Controller Init Failed.");
  1706. SetWindowLong(hDlg, DWL_USER, 0);
  1707. pDialog->m_pController = pController = NULL;
  1708. delete g_pUpdate;
  1709. MessageBeep(0xFFFFFFFF);
  1710. Button_Enable(GetDlgItem(hDlg, IDCMD_ABORT), FALSE);
  1711. Button_Enable(GetDlgItem(hDlg, IDCMD_DETAILS), FALSE);
  1712. pDialog->CleanUp();
  1713. SetWindowLong(hDlg, DWL_USER, 0);
  1714. delete pDialog;
  1715. return TRUE;
  1716. case IDCANCEL:
  1717. {
  1718. int mbRet = SGMessageBox(hDlg, IDS_DOWNLOAD_ABORT_WARNING,
  1719. MB_YESNO | MB_ICONQUESTION |
  1720. MB_DEFBUTTON2 | MB_APPLMODAL);
  1721. if (mbRet == IDNO) {
  1722. return TRUE;
  1723. } else {
  1724. if (!pDialog->m_pController)
  1725. return TRUE;
  1726. ; // Fall through.
  1727. }
  1728. }
  1729. // Following messages are from the UI and need to be
  1730. // forward to update thread.
  1731. case IDCMD_ABORT: // Abort all updates
  1732. DBG("UpdateDlgProc - closing, all downloads aborted");
  1733. ASSERT(pController->m_ThreadID);
  1734. PostThreadMessage(pController->m_ThreadID, UM_ONABORT, 0,0);
  1735. MLLoadString(IDS_ABORTING, szString, ARRAYSIZE(szString));
  1736. SetDlgItemText(hDlg, IDC_AGENTSTATUS, szString);
  1737. Animate_Close(hAnimate);
  1738. ShowWindow(hAnimate, SW_HIDE);
  1739. ShowWindow (GetDlgItem (hDlg, IDC_AGENTSTATUS), SW_SHOW);
  1740. return TRUE;
  1741. case IDCMD_SKIP:
  1742. PostThreadMessage(pController->m_ThreadID, UM_ONSKIP, 0,0);
  1743. return TRUE;
  1744. case IDCMD_DETAILS:
  1745. {
  1746. CUpdateDialog::m_bDetail = !CUpdateDialog::m_bDetail;
  1747. ResizeDialog(hDlg, CUpdateDialog::m_bDetail);
  1748. return TRUE;
  1749. }
  1750. case IDCMD_HIDE:
  1751. ShowWindow(hDlg, SW_SHOWMINIMIZED);
  1752. return TRUE;
  1753. default:
  1754. break;
  1755. }
  1756. break;
  1757. }
  1758. }
  1759. return FALSE;
  1760. }
  1761. HRESULT GetActiveUpdateAgent(CUpdateAgent ** ppUpdate)
  1762. {
  1763. ASSERT (ppUpdate);
  1764. // We are assuming the Update agent is free threaded.
  1765. *ppUpdate = NULL;
  1766. if (g_pUpdate == NULL) {
  1767. DBG("GetActiveUpdateAgent - Creating new agent");
  1768. g_pUpdate = new CUpdateAgent();
  1769. if (!g_pUpdate) {
  1770. DBG("GetActiveUpdateAgent - Failed to create new agent");
  1771. return E_OUTOFMEMORY;
  1772. }
  1773. HRESULT hr = g_pUpdate->Init();
  1774. if (FAILED(hr)) {
  1775. DBG("GetActiveUpdateAgent - Failed to init new agent");
  1776. return hr;
  1777. }
  1778. }
  1779. *ppUpdate = g_pUpdate;
  1780. return NOERROR;
  1781. }
  1782. DWORD WINAPI BackgroundUpdate(void)
  1783. {
  1784. DBG("BackgroundUpdate entered");
  1785. HRESULT hr;
  1786. CUpdateAgent * pAgent = NULL;
  1787. hr = GetActiveUpdateAgent(&pAgent);
  1788. if (SUCCEEDED(hr)) {
  1789. ASSERT(pAgent);
  1790. ASSERT(pAgent->m_ThreadID);
  1791. // APPCOMPAT: Even when we succeed here, there are chances that we won't
  1792. // get updated because CONTROLLER CAN FAIL TO INITIALIZE AND WE DON'T
  1793. // KNOW IT!
  1794. if (!PostThreadMessage(pAgent->m_ThreadID, UM_BACKGROUND,0,0))
  1795. {
  1796. hr = E_FAIL;
  1797. DBG("Failed to post ONREQUEST message.");
  1798. }
  1799. pAgent = NULL;
  1800. }
  1801. DBG("BackgroundUpdate ended");
  1802. return (DWORD)hr;
  1803. }
  1804. DWORD WINAPI UpdateRequest(UINT idCmd, INotification *pNot)
  1805. {
  1806. // DBG("UpdateRequest entered");
  1807. if (idCmd != UM_ONREQUEST)
  1808. return E_FAIL;
  1809. HRESULT hr;
  1810. CUpdateAgent * pAgent = NULL;
  1811. hr = GetActiveUpdateAgent(&pAgent);
  1812. if (SUCCEEDED(hr)) {
  1813. ASSERT(pAgent);
  1814. ASSERT(pAgent->m_ThreadID);
  1815. if (pNot)
  1816. pNot->AddRef();
  1817. // APPCOMPAT: Even when we succeed here, there are chances that we won't
  1818. // get updated because CONTROLLER CAN FAIL TO INITIALIZE AND WE DON'T
  1819. // KNOW IT!
  1820. if (!PostThreadMessage(pAgent->m_ThreadID, UM_ONREQUEST,0,(LPARAM)pNot))
  1821. {
  1822. hr = E_FAIL;
  1823. SAFERELEASE(pNot);
  1824. DBG("Failed to post ONREQUEST message.");
  1825. }
  1826. pAgent = NULL;
  1827. }
  1828. // DBG("UpdateRequest ended");
  1829. return (DWORD)hr;
  1830. }
  1831. HRESULT UpdateNotifyReboot(void)
  1832. {
  1833. DBG("UpdateNotifyReboot entered");
  1834. HRESULT hr;
  1835. CUpdateAgent * pAgent = NULL;
  1836. hr = GetActiveUpdateAgent(&pAgent);
  1837. if (SUCCEEDED(hr)) {
  1838. ASSERT(pAgent);
  1839. ASSERT(pAgent->m_ThreadID);
  1840. hr = PostThreadMessage(pAgent->m_ThreadID, UM_NEEDREBOOT, 0, 0);
  1841. }
  1842. DBG("UpdateNotifyReboot ended");
  1843. return hr;
  1844. }