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.

1281 lines
32 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 2000
  6. //
  7. // File: prsheet.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. #include "pch.h"
  11. #include "shellapi.h"
  12. #include "htmlhelp.h"
  13. #pragma hdrstop
  14. #define IDH_LETWINDOWS 3000
  15. #define IDH_AUTOUPDATE_OPTION1 3001
  16. #define IDH_AUTOUPDATE_OPTION2 3002
  17. #define IDH_AUTOUPDATE_OPTION3 3003
  18. #define IDH_DAYDROPDOWN 3004
  19. #define IDH_TIMEDROPDOWN 3005
  20. #define IDH_AUTOUPDATE_RESTOREHIDDEN 3006
  21. #define IDH_NOHELP -1
  22. const TCHAR g_szAutoUpdateItems[] = TEXT("AutoUpdateItems");
  23. //
  24. // Create a structure for Updates Object data. This structure
  25. // is used to pass data between the property page and the
  26. // Updates Object thread. Today all we use is the "option" value
  27. // but there may be more later.
  28. //
  29. enum UPDATESOBJ_DATA_ITEMS
  30. {
  31. UODI_OPTION = 0x00000001,
  32. UODI_ALL = 0xFFFFFFFF
  33. };
  34. struct UPDATESOBJ_DATA
  35. {
  36. DWORD fMask; // UPDATESOBJ_DATA_ITEMS mask
  37. AUOPTION Option; // Updates option setting.
  38. };
  39. //
  40. // Private window message sent from the Updates Object thread proc
  41. // to the property page telling the page that the object has been
  42. // initialized.
  43. //
  44. // lParam - points to a UPATESOBJ_DATA structure containing
  45. // the initial configuration of the update's object with
  46. // which to initialize the UI. If wParam is 0, this
  47. // may be NULL.
  48. //
  49. // wParam - BOOL (0/1) indicating if object intialization was
  50. // successful or not. If wParam is 0, lParam may be NULL.
  51. //
  52. const UINT PWM_INITUPDATESOBJECT = WM_USER + 1;
  53. //
  54. // Message sent from the property page to the Updates Object thread
  55. // to tell it to configure the Auto Updates service.
  56. //
  57. // lParam - points to a UPDATESOBJ_DATA structure containing the
  58. // data to set.
  59. //
  60. // wParam - Unused. Set to 0.
  61. //
  62. const UINT UOTM_SETDATA = WM_USER + 2;
  63. //
  64. // Message cracker for WM_HELP. Not sure why windowsx.h doesn't have one.
  65. //
  66. // void Cls_OnHelp(HWND hwnd, HELPINFO *pHelpInfo)
  67. //
  68. #define HANDLE_WM_HELP(hwnd, wParam, lParam, fn) \
  69. ((fn)((hwnd), (HELPINFO *)(lParam)))
  70. #define FORWARD_WM_HELP(hwnd, pHelpInfo, fn) \
  71. (void)(fn)((hwnd), WM_HELP, (WPARAM)0, (LPARAM)pHelpInfo)
  72. //
  73. // Message cracker for PWM_INITUPDATESOBJECT.
  74. //
  75. #define HANDLE_PWM_INITUPDATESOBJECT(hwnd, wParam, lParam, fn) \
  76. ((fn)((hwnd), (BOOL)(wParam), (UPDATESOBJ_DATA *)(lParam)))
  77. class CAutoUpdatePropSheet : public IShellExtInit,
  78. public IShellPropSheetExt
  79. {
  80. public:
  81. ~CAutoUpdatePropSheet(void);
  82. //
  83. // IUnknown
  84. //
  85. STDMETHOD(QueryInterface)(REFIID riid, void **ppv);
  86. STDMETHOD_(ULONG, AddRef)(void);
  87. STDMETHOD_(ULONG, Release)(void);
  88. //
  89. // IShellExtInit
  90. //
  91. STDMETHOD(Initialize)(LPCITEMIDLIST pidl, LPDATAOBJECT pdtobj, HKEY hkey);
  92. //
  93. // IShellPropSheetExt
  94. //
  95. STDMETHOD(AddPages)(LPFNADDPROPSHEETPAGE lpfnAddPage, LPARAM lParam);
  96. STDMETHOD(ReplacePage)(UINT uPageID, LPFNADDPROPSHEETPAGE lpfnAddPage, LPARAM lParam);
  97. //
  98. // Instance generator.
  99. //
  100. static HRESULT CreateInstance(HINSTANCE hInstance, REFIID riid, void **ppv);
  101. private:
  102. LONG m_cRef;
  103. HINSTANCE m_hInstance;
  104. DWORD m_idUpdatesObjectThread;
  105. HANDLE m_hThreadUpdatesObject;
  106. static const DWORD s_rgHelpIDs[];
  107. BOOL _OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam);
  108. BOOL _OnNotify(HWND hwnd, UINT idFrom, LPNMHDR pnmhdr);
  109. BOOL _OnPSN_Apply(HWND hwnd);
  110. BOOL _OnDestroy(HWND hwnd);
  111. BOOL _OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify);
  112. BOOL _OnContextMenu(HWND hwnd, HWND hwndContext, UINT xPos, UINT yPos);
  113. BOOL _OnHelp(HWND hwnd, HELPINFO *pHelpInfo);
  114. BOOL _OkToDisplayPage(void);
  115. BOOL _OnInitUpdatesObject(HWND hwnd, BOOL bObjectInit, UPDATESOBJ_DATA *pData);
  116. //newly added methods : a-josem
  117. BOOL _EnableOptions(HWND hwnd, BOOL bState);
  118. BOOL _EnableCombo(HWND hwnd, BOOL bState);
  119. BOOL _SetDefault(HWND hwnd);
  120. void _GetDayAndTimeFromUI( HWND hWnd, LPDWORD lpdwSchedInstallDay,LPDWORD lpdwSchedInstallTime);
  121. BOOL _FillDaysCombo(HWND hwnd, DWORD dwSchedInstallDay);
  122. void _OnKeepUptoDate(HWND hwnd);
  123. static INT_PTR CALLBACK _DlgRestoreProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam);
  124. void LaunchLinkAction(HWND hwnd, UINT uCtrlId);
  125. void LaunchHelp(LPCTSTR szURL);
  126. //end of newly added methods,
  127. HRESULT _OnOptionSelected(HWND hwnd, int idOption);
  128. HRESULT _OnRestoreHiddenItems(void);
  129. HRESULT _EnableControls(HWND hwnd, BOOL bEnable);
  130. HRESULT _SetHeaderText(HWND hwnd, UINT idsText);
  131. HRESULT _AddPage(LPFNADDPROPSHEETPAGE lpfnAddPage, LPARAM lParam);
  132. static DWORD WINAPI _UpdatesObjectThreadProc(LPVOID pvParam);
  133. static HRESULT _QueryUpdatesObjectData(HWND hwnd, IUpdates *pUpdates, UPDATESOBJ_DATA *pData);
  134. static HRESULT _SetUpdatesObjectData(HWND hwnd, IUpdates *pUpdates, UPDATESOBJ_DATA *pData);
  135. static UINT CALLBACK _PageCallback(HWND hwnd, UINT uMsg, LPPROPSHEETPAGE ppsp);
  136. static INT_PTR CALLBACK _DlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  137. //
  138. // Allow public creation through instance generator only.
  139. //
  140. CAutoUpdatePropSheet(HINSTANCE hInstance);
  141. //
  142. // Prevent copy.
  143. //
  144. CAutoUpdatePropSheet(const CAutoUpdatePropSheet& rhs); // not implemented.
  145. CAutoUpdatePropSheet& operator = (const CAutoUpdatePropSheet& rhs); // not implemented.
  146. };
  147. CAutoUpdatePropSheet::CAutoUpdatePropSheet(
  148. HINSTANCE hInstance
  149. ) : m_cRef(1),
  150. m_hInstance(hInstance),
  151. m_idUpdatesObjectThread(0),
  152. m_hThreadUpdatesObject(NULL)
  153. {
  154. DllAddRef();
  155. }
  156. CAutoUpdatePropSheet::~CAutoUpdatePropSheet(
  157. void
  158. )
  159. {
  160. if (NULL != m_hThreadUpdatesObject)
  161. {
  162. CloseHandle(m_hThreadUpdatesObject);
  163. }
  164. DllRelease();
  165. }
  166. HRESULT
  167. CAutoUpdatePropSheet::CreateInstance(
  168. HINSTANCE hInstance,
  169. REFIID riid,
  170. void **ppvOut
  171. )
  172. {
  173. HRESULT hr = E_OUTOFMEMORY;
  174. if (NULL == ppvOut)
  175. {
  176. return E_INVALIDARG;
  177. }
  178. *ppvOut = NULL;
  179. CAutoUpdatePropSheet *pSheet = new CAutoUpdatePropSheet(hInstance);
  180. if (NULL != pSheet)
  181. {
  182. hr = pSheet->QueryInterface(riid, ppvOut);
  183. pSheet->Release();
  184. }
  185. return hr;
  186. }
  187. STDMETHODIMP
  188. CAutoUpdatePropSheet::QueryInterface(
  189. REFIID riid,
  190. void **ppvOut
  191. )
  192. {
  193. HRESULT hr = E_NOINTERFACE;
  194. if (NULL == ppvOut)
  195. return E_INVALIDARG;
  196. *ppvOut = NULL;
  197. if (IID_IUnknown == riid ||
  198. IID_IShellExtInit == riid)
  199. {
  200. *ppvOut = static_cast<IShellExtInit *>(this);
  201. }
  202. else if (IID_IShellPropSheetExt == riid)
  203. {
  204. *ppvOut = static_cast<IShellPropSheetExt *>(this);
  205. }
  206. if (NULL != *ppvOut)
  207. {
  208. ((LPUNKNOWN)*ppvOut)->AddRef();
  209. hr = NOERROR;
  210. }
  211. return hr;
  212. }
  213. STDMETHODIMP_(ULONG)
  214. CAutoUpdatePropSheet::AddRef(
  215. void
  216. )
  217. {
  218. return InterlockedIncrement(&m_cRef);
  219. }
  220. STDMETHODIMP_(ULONG)
  221. CAutoUpdatePropSheet::Release(
  222. void
  223. )
  224. {
  225. if (InterlockedDecrement(&m_cRef))
  226. return m_cRef;
  227. delete this;
  228. return 0;
  229. }
  230. //
  231. // IShellExtInit::Initialize impl.
  232. //
  233. STDMETHODIMP
  234. CAutoUpdatePropSheet::Initialize(
  235. LPCITEMIDLIST /*pidlFolder*/,
  236. LPDATAOBJECT /*pdtobj*/,
  237. HKEY /*hkeyProgID*/
  238. )
  239. {
  240. return NOERROR;
  241. }
  242. //
  243. // IShellPropSheetExt::AddPages impl.
  244. //
  245. STDMETHODIMP
  246. CAutoUpdatePropSheet::AddPages(
  247. LPFNADDPROPSHEETPAGE lpfnAddPage,
  248. LPARAM lParam
  249. )
  250. {
  251. HRESULT hr = E_FAIL; // Assume failure.
  252. if (_OkToDisplayPage())
  253. {
  254. hr = _AddPage(lpfnAddPage, lParam);
  255. }
  256. return hr;
  257. }
  258. //
  259. // IShellPropSheetExt::ReplacePage impl.
  260. //
  261. STDMETHODIMP
  262. CAutoUpdatePropSheet::ReplacePage(
  263. UINT /*uPageID*/,
  264. LPFNADDPROPSHEETPAGE /*lpfnAddPage*/,
  265. LPARAM /*lParam*/
  266. )
  267. {
  268. return E_NOTIMPL;
  269. }
  270. //
  271. // Determines if it's OK to display the auto-update prop page.
  272. // Reasons for NOT displaying:
  273. //
  274. // 1. User is not an administrator.
  275. // 2. The "NoAutoUpdate" policy restriction is in place.
  276. //
  277. //
  278. BOOL
  279. CAutoUpdatePropSheet::_OkToDisplayPage(
  280. void
  281. )
  282. {
  283. BOOL bOkToDisplay = TRUE;
  284. if (!IsNTAdmin(0,0))
  285. {
  286. bOkToDisplay = FALSE;
  287. }
  288. else
  289. {
  290. bOkToDisplay = fAccessibleToAU();
  291. }
  292. return bOkToDisplay;
  293. }
  294. //
  295. // Add our page to the property sheet.
  296. //
  297. HRESULT
  298. CAutoUpdatePropSheet::_AddPage(
  299. LPFNADDPROPSHEETPAGE lpfnAddPage,
  300. LPARAM lParam
  301. )
  302. {
  303. HRESULT hr = E_FAIL;
  304. PROPSHEETPAGE psp;
  305. ZeroMemory(&psp, sizeof(psp));
  306. psp.dwSize = sizeof(PROPSHEETPAGE);
  307. psp.dwFlags = PSP_USECALLBACK;
  308. psp.hInstance = m_hInstance;
  309. psp.pszTemplate = MAKEINTRESOURCE(IDD_AUTOUPDATE);
  310. psp.pszTitle = NULL;
  311. psp.pfnDlgProc = CAutoUpdatePropSheet::_DlgProc;
  312. psp.pfnCallback = CAutoUpdatePropSheet::_PageCallback;
  313. psp.lParam = (LPARAM)this;
  314. HPROPSHEETPAGE hPage = CreatePropertySheetPage(&psp);
  315. if (NULL != hPage)
  316. {
  317. if (lpfnAddPage(hPage, lParam))
  318. {
  319. hr = S_OK;
  320. }
  321. else
  322. {
  323. DestroyPropertySheetPage(hPage);
  324. }
  325. }
  326. return hr;
  327. }
  328. //
  329. // We implement the page callback to manage the lifetime of the
  330. // C++ object attached to the property page.
  331. // We also use the callback to defer creation of the IUpdates object.
  332. //
  333. UINT CALLBACK
  334. CAutoUpdatePropSheet::_PageCallback( // [static]
  335. HWND /*hwnd*/,
  336. UINT uMsg,
  337. LPPROPSHEETPAGE ppsp
  338. )
  339. {
  340. UINT uReturn = 1;
  341. if (NULL == ppsp)
  342. {
  343. return uReturn;
  344. }
  345. CAutoUpdatePropSheet *pThis = (CAutoUpdatePropSheet *)ppsp->lParam;
  346. switch(uMsg)
  347. {
  348. case PSPCB_ADDREF:
  349. pThis->AddRef();
  350. break;
  351. case PSPCB_RELEASE:
  352. pThis->Release();
  353. break;
  354. }
  355. return uReturn;
  356. }
  357. //
  358. // ISSUE-2000/10/12-BrianAu Need help IDs.
  359. //
  360. const DWORD CAutoUpdatePropSheet::s_rgHelpIDs[] = {
  361. IDC_CHK_KEEPUPTODATE, DWORD(IDH_LETWINDOWS),
  362. IDC_OPTION1, DWORD(IDH_AUTOUPDATE_OPTION1),
  363. IDC_OPTION2, DWORD(IDH_AUTOUPDATE_OPTION2),
  364. IDC_OPTION3, DWORD(IDH_AUTOUPDATE_OPTION3),
  365. IDC_CMB_DAYS, DWORD(IDH_DAYDROPDOWN),
  366. IDC_CMB_HOURS, DWORD(IDH_TIMEDROPDOWN),
  367. IDC_RESTOREHIDDEN, DWORD(IDH_AUTOUPDATE_RESTOREHIDDEN),
  368. IDC_GRP_OPTIONS, DWORD(IDH_NOHELP),
  369. IDI_AUTOUPDATE, DWORD(IDH_NOHELP),
  370. 0, 0
  371. };
  372. INT_PTR CALLBACK
  373. CAutoUpdatePropSheet::_DlgProc( // [static]
  374. HWND hwnd,
  375. UINT uMsg,
  376. WPARAM wParam,
  377. LPARAM lParam
  378. )
  379. {
  380. CAutoUpdatePropSheet *pThis = NULL;
  381. if (WM_INITDIALOG == uMsg)
  382. {
  383. PROPSHEETPAGE *psp = (PROPSHEETPAGE *)lParam;
  384. pThis = (CAutoUpdatePropSheet *)psp->lParam;
  385. if (!SetProp(hwnd, g_szPropDialogPtr, (HANDLE)pThis))
  386. {
  387. pThis = NULL;
  388. }
  389. }
  390. else
  391. {
  392. pThis = (CAutoUpdatePropSheet *)GetProp(hwnd, g_szPropDialogPtr);
  393. }
  394. if (NULL != pThis)
  395. {
  396. switch(uMsg)
  397. {
  398. HANDLE_MSG(hwnd, WM_INITDIALOG, pThis->_OnInitDialog);
  399. HANDLE_MSG(hwnd, WM_COMMAND, pThis->_OnCommand);
  400. HANDLE_MSG(hwnd, WM_DESTROY, pThis->_OnDestroy);
  401. HANDLE_MSG(hwnd, WM_NOTIFY, pThis->_OnNotify);
  402. HANDLE_MSG(hwnd, WM_CONTEXTMENU, pThis->_OnContextMenu);
  403. HANDLE_MSG(hwnd, WM_HELP, pThis->_OnHelp);
  404. HANDLE_MSG(hwnd, PWM_INITUPDATESOBJECT, pThis->_OnInitUpdatesObject);
  405. default:
  406. break;
  407. }
  408. }
  409. return FALSE;
  410. }
  411. void EnableRestoreDeclinedItems(HWND hWnd, BOOL fEnable)
  412. {
  413. EnableWindow(GetDlgItem(hWnd, IDC_RESTOREHIDDEN), fEnable);
  414. }
  415. //
  416. // PWM_INITUPDATESOBJECT handler.
  417. // This is called when the Updates Object thread has either successfully
  418. // CoCreated the Updates object or CoCreation has failed.
  419. // It's possible that the Windows Update Service is not running.
  420. // This is how we handle that condition.
  421. //
  422. BOOL
  423. CAutoUpdatePropSheet::_OnInitUpdatesObject(
  424. HWND hwnd,
  425. BOOL bObjectInitSuccessful,
  426. UPDATESOBJ_DATA *pData
  427. )
  428. {
  429. if (bObjectInitSuccessful)
  430. {
  431. if (NULL == pData)
  432. {
  433. return FALSE;
  434. }
  435. //
  436. // Updates object was created and initialized. The
  437. // pData pointer refers to the initial state information retrieved
  438. // from the object. Initialize the property page.
  439. //
  440. _SetHeaderText(hwnd, IDS_HEADER_CONNECTED);
  441. _EnableControls(hwnd, TRUE);
  442. EnableRestoreDeclinedItems( hwnd, FHiddenItemsExist());
  443. switch(pData->Option.dwOption)
  444. {
  445. case AUOPTION_AUTOUPDATE_DISABLE:
  446. CheckRadioButton(hwnd, IDC_OPTION1, IDC_OPTION3, IDC_OPTION1);
  447. _EnableOptions(hwnd, FALSE);
  448. _EnableCombo(hwnd, FALSE);
  449. SendMessage(GetDlgItem(hwnd,IDC_CHK_KEEPUPTODATE),BM_SETCHECK,BST_UNCHECKED,0);
  450. break;
  451. case AUOPTION_PREDOWNLOAD_NOTIFY:
  452. CheckRadioButton(hwnd, IDC_OPTION1, IDC_OPTION3, IDC_OPTION1);
  453. _EnableCombo(hwnd, FALSE);
  454. SendMessage(GetDlgItem(hwnd,IDC_CHK_KEEPUPTODATE),BM_SETCHECK,BST_CHECKED,0);
  455. break;
  456. case AUOPTION_INSTALLONLY_NOTIFY:
  457. CheckRadioButton(hwnd, IDC_OPTION1, IDC_OPTION3, IDC_OPTION2);
  458. _EnableCombo(hwnd, FALSE);
  459. SendMessage(GetDlgItem(hwnd,IDC_CHK_KEEPUPTODATE),BM_SETCHECK,BST_CHECKED,0);
  460. break;
  461. case AUOPTION_SCHEDULED:
  462. CheckRadioButton(hwnd, IDC_OPTION1, IDC_OPTION3, IDC_OPTION3);
  463. _EnableCombo(hwnd, TRUE);
  464. SendMessage(GetDlgItem(hwnd,IDC_CHK_KEEPUPTODATE),BM_SETCHECK,BST_CHECKED,0);
  465. break;
  466. default:
  467. _SetDefault(hwnd);
  468. break;
  469. }
  470. _FillDaysCombo(hwnd, pData->Option.dwSchedInstallDay);
  471. FillHrsCombo(hwnd, pData->Option.dwSchedInstallTime);
  472. if (pData->Option.fDomainPolicy)
  473. {
  474. DisableUserInput(hwnd);
  475. }
  476. }
  477. else
  478. {
  479. //
  480. // Something failed when creating the Updates object.
  481. // Most likely, the Windows Update service is not running.
  482. //
  483. _SetHeaderText(hwnd, IDS_HEADER_UNAVAILABLE);
  484. }
  485. return FALSE;
  486. }
  487. //
  488. // WM_INITDIALOG handler.
  489. //
  490. BOOL
  491. CAutoUpdatePropSheet::_OnInitDialog(
  492. HWND hwnd,
  493. HWND /*hwndFocus*/,
  494. LPARAM /*lParam*/
  495. )
  496. {
  497. //
  498. // If the thread is created, the threadproc will call
  499. // DllRelease();
  500. //
  501. DllAddRef();
  502. //
  503. // Disable all page controls and display a message in the
  504. // header indicating that we're trying to connect to the
  505. // Windows Update service.
  506. //
  507. _SetHeaderText(hwnd, IDS_HEADER_CONNECTING);
  508. _EnableControls(hwnd, FALSE);
  509. //
  510. // Create the thread on which the Updates object lives.
  511. // Communication between the thread and the property page is
  512. // through the messages PWM_INITUPDATESOBJECT and UOTM_SETDATA.
  513. //
  514. m_hThreadUpdatesObject = CreateThread(NULL,
  515. 0,
  516. _UpdatesObjectThreadProc,
  517. (LPVOID)hwnd,
  518. 0,
  519. &m_idUpdatesObjectThread);
  520. if (NULL == m_hThreadUpdatesObject)
  521. {
  522. DllRelease();
  523. }
  524. return TRUE;
  525. }
  526. //
  527. // WM_DESTROY handler.
  528. //
  529. BOOL
  530. CAutoUpdatePropSheet::_OnDestroy(
  531. HWND hwnd
  532. )
  533. {
  534. RemoveProp(hwnd, g_szPropDialogPtr);
  535. if (0 != m_idUpdatesObjectThread)
  536. {
  537. //
  538. // Terminate the Update Objects thread.
  539. //
  540. if (0 != PostThreadMessage(m_idUpdatesObjectThread, WM_QUIT, 0, 0))
  541. {
  542. //
  543. // Wait for normal thread termination.
  544. //
  545. WaitForSingleObject(m_hThreadUpdatesObject, 5000);
  546. }
  547. }
  548. return FALSE;
  549. }
  550. //
  551. // WM_COMMAND handler.
  552. //
  553. BOOL
  554. CAutoUpdatePropSheet::_OnCommand(
  555. HWND hwnd,
  556. int id,
  557. HWND /*hwndCtl*/,
  558. UINT codeNotify
  559. )
  560. {
  561. INT Result;
  562. switch(id)
  563. {
  564. case IDC_CHK_KEEPUPTODATE:
  565. if (BN_CLICKED == codeNotify)
  566. {
  567. _OnKeepUptoDate(hwnd);
  568. }
  569. break;
  570. case IDC_OPTION1:
  571. case IDC_OPTION2:
  572. case IDC_OPTION3:
  573. if(BN_CLICKED == codeNotify)
  574. {
  575. _OnOptionSelected(hwnd, id);
  576. }
  577. break;
  578. case IDC_CMB_DAYS:
  579. case IDC_CMB_HOURS:
  580. if(CBN_SELCHANGE == codeNotify)
  581. {
  582. //
  583. // Enable the "Apply" button.
  584. //
  585. SendMessage(GetParent(hwnd), PSM_CHANGED, (WPARAM)hwnd, 0);
  586. }
  587. break;
  588. case IDC_RESTOREHIDDEN:
  589. Result = (INT)DialogBoxParam(m_hInstance,
  590. MAKEINTRESOURCE(IDD_RESTOREUPDATE),
  591. hwnd,
  592. (DLGPROC)CAutoUpdatePropSheet::_DlgRestoreProc,
  593. (LPARAM)NULL);
  594. if (Result == TRUE)
  595. {
  596. if (SUCCEEDED (_OnRestoreHiddenItems()))
  597. {
  598. EnableRestoreDeclinedItems( hwnd, FALSE);
  599. }
  600. }
  601. break;
  602. default:
  603. return FALSE;
  604. }
  605. return TRUE;
  606. }
  607. INT_PTR CALLBACK CAutoUpdatePropSheet::_DlgRestoreProc(
  608. HWND hwnd,
  609. UINT uMsg,
  610. WPARAM wParam,
  611. LPARAM lParam
  612. )
  613. {
  614. if (uMsg == WM_INITDIALOG)
  615. {
  616. HWND hwndOwner;
  617. RECT rc, rcDlg, rcOwner;
  618. // Get the owner window and dialog box rectangles.
  619. if ((hwndOwner = GetParent(hwnd)) == NULL)
  620. {
  621. hwndOwner = GetDesktopWindow();
  622. }
  623. GetWindowRect(hwndOwner, &rcOwner);
  624. GetWindowRect(hwnd, &rcDlg);
  625. CopyRect(&rc, &rcOwner);
  626. // Offset the owner and dialog box rectangles so that
  627. // right and bottom values represent the width and
  628. // height, and then offset the owner again to discard
  629. // space taken up by the dialog box.
  630. OffsetRect(&rcDlg, -rcDlg.left, -rcDlg.top);
  631. OffsetRect(&rc, -rc.left, -rc.top);
  632. OffsetRect(&rc, -rcDlg.right, -rcDlg.bottom);
  633. // The new position is the sum of half the remaining
  634. // space and the owner's original position.
  635. SetWindowPos(hwnd,
  636. HWND_TOP,
  637. rcOwner.left + (rc.right / 2),
  638. rcOwner.top + (rc.bottom / 2),
  639. 0, 0, // ignores size arguments
  640. SWP_NOSIZE);
  641. }
  642. if (uMsg == WM_COMMAND)
  643. {
  644. switch (LOWORD(wParam))
  645. {
  646. case IDOK:
  647. EndDialog(hwnd, TRUE);
  648. return TRUE;
  649. case IDCANCEL:
  650. EndDialog(hwnd, FALSE);
  651. return TRUE;
  652. }
  653. }
  654. return FALSE;
  655. }
  656. //
  657. // WM_NOTIFY handler.
  658. //
  659. BOOL
  660. CAutoUpdatePropSheet::_OnNotify(
  661. HWND hwnd,
  662. UINT idFrom,
  663. LPNMHDR pnmhdr
  664. )
  665. {
  666. switch(pnmhdr->code)
  667. {
  668. case PSN_APPLY:
  669. _OnPSN_Apply(hwnd);
  670. break;
  671. case NM_RETURN:
  672. case NM_CLICK:
  673. if (idFrom == IDC_AUTOUPDATELINK || idFrom == IDC_SCHINSTALLINK)
  674. LaunchLinkAction(hwnd, idFrom);
  675. break;
  676. default:
  677. break;
  678. }
  679. return FALSE;
  680. }
  681. void CAutoUpdatePropSheet::LaunchLinkAction(HWND hwnd, UINT uCtrlId)
  682. {
  683. switch (uCtrlId)
  684. {
  685. case IDC_AUTOUPDATELINK:
  686. LaunchHelp(gtszAUOverviewUrl);
  687. break;
  688. case IDC_SCHINSTALLINK:
  689. LaunchHelp(gtszAUXPSchedInstallUrl);
  690. break;
  691. }
  692. return;
  693. }
  694. //
  695. // Called when the user presses the "Apply" button or the "OK"
  696. // button when the page has been changed.
  697. //
  698. BOOL
  699. CAutoUpdatePropSheet::_OnPSN_Apply(
  700. HWND hwnd
  701. )
  702. {
  703. HRESULT hr = E_FAIL;
  704. //
  705. // Create a structure that can be passed to the Updates Object thread
  706. // by way of the UOTM_SETDATA thread message. The thread will free
  707. // the buffer when it's finished with it.
  708. //
  709. UPDATESOBJ_DATA *pData = (UPDATESOBJ_DATA *)LocalAlloc(LPTR, sizeof(*pData));
  710. if (NULL == pData)
  711. {
  712. hr = E_OUTOFMEMORY;
  713. }
  714. else
  715. {
  716. pData->Option.dwSchedInstallDay = -1;
  717. pData->Option.dwSchedInstallTime = -1;
  718. pData->fMask = UODI_ALL;
  719. static const struct
  720. {
  721. UINT idCtl;
  722. DWORD dwOption;
  723. } rgMap[] = {
  724. { IDC_OPTION1, AUOPTION_PREDOWNLOAD_NOTIFY },
  725. { IDC_OPTION2, AUOPTION_INSTALLONLY_NOTIFY },
  726. { IDC_OPTION3, AUOPTION_SCHEDULED }
  727. };
  728. if (IsDlgButtonChecked(hwnd, IDC_CHK_KEEPUPTODATE) == BST_CHECKED)
  729. {
  730. //
  731. // Determine the WAU option based on the radio button configuration.
  732. //
  733. for (int i = 0; i < ARRAYSIZE(rgMap); i++)
  734. {
  735. if (IsDlgButtonChecked(hwnd, rgMap[i].idCtl) == BST_CHECKED)
  736. {
  737. pData->Option.dwOption = rgMap[i].dwOption;
  738. break;
  739. }
  740. }
  741. }
  742. else
  743. pData->Option.dwOption = AUOPTION_AUTOUPDATE_DISABLE;
  744. if (AUOPTION_SCHEDULED == pData->Option.dwOption)
  745. {
  746. _GetDayAndTimeFromUI(hwnd, &(pData->Option.dwSchedInstallDay), &(pData->Option.dwSchedInstallTime));
  747. }
  748. if (0 != m_idUpdatesObjectThread)
  749. {
  750. if (0 != PostThreadMessage(m_idUpdatesObjectThread,
  751. UOTM_SETDATA,
  752. 0,
  753. (LPARAM)pData))
  754. {
  755. hr = S_OK;
  756. pData = NULL;
  757. }
  758. }
  759. if (NULL != pData)
  760. {
  761. LocalFree(pData);
  762. pData = NULL;
  763. }
  764. }
  765. if (SUCCEEDED(hr))
  766. {
  767. //
  768. // Inform the property sheet the update was successful and
  769. // disable the "Apply" button.
  770. //
  771. SetWindowLongPtr(hwnd, DWLP_MSGRESULT, PSNRET_NOERROR);
  772. SendMessage(GetParent(hwnd), PSM_UNCHANGED, (WPARAM)hwnd, 0);
  773. }
  774. return FALSE;
  775. }
  776. //
  777. // WM_CONTEXTMENU handler.
  778. //
  779. BOOL
  780. CAutoUpdatePropSheet::_OnContextMenu(
  781. HWND hwnd,
  782. HWND hwndContext,
  783. UINT /*xPos*/,
  784. UINT /*yPos*/
  785. )
  786. {
  787. if ((hwndContext == GetDlgItem(hwnd,IDC_CHK_KEEPUPTODATE))||
  788. (hwndContext == GetDlgItem(hwnd,IDC_OPTION1))||
  789. (hwndContext == GetDlgItem(hwnd,IDC_OPTION2))||
  790. (hwndContext == GetDlgItem(hwnd,IDC_OPTION3))||
  791. (hwndContext == GetDlgItem(hwnd,IDC_CMB_DAYS))||
  792. (hwndContext == GetDlgItem(hwnd,IDC_CMB_HOURS))||
  793. (hwndContext == GetDlgItem(hwnd,IDC_RESTOREHIDDEN)))
  794. {
  795. HtmlHelp(hwndContext,g_szHelpFile,HH_TP_HELP_CONTEXTMENU,(DWORD_PTR)((LPTSTR)s_rgHelpIDs));
  796. }
  797. return FALSE;
  798. }
  799. //
  800. // WM_HELP handler.
  801. //
  802. BOOL
  803. CAutoUpdatePropSheet::_OnHelp(
  804. HWND hwnd,
  805. HELPINFO *pHelpInfo
  806. )
  807. {
  808. if (NULL == pHelpInfo)
  809. {
  810. return TRUE;
  811. }
  812. if (HELPINFO_WINDOW == pHelpInfo->iContextType)
  813. {
  814. if ((pHelpInfo->hItemHandle == GetDlgItem(hwnd,IDC_CHK_KEEPUPTODATE))||
  815. (pHelpInfo->hItemHandle == GetDlgItem(hwnd,IDC_OPTION1))||
  816. (pHelpInfo->hItemHandle == GetDlgItem(hwnd,IDC_OPTION2))||
  817. (pHelpInfo->hItemHandle == GetDlgItem(hwnd,IDC_OPTION3))||
  818. (pHelpInfo->hItemHandle == GetDlgItem(hwnd,IDC_CMB_DAYS))||
  819. (pHelpInfo->hItemHandle == GetDlgItem(hwnd,IDC_CMB_HOURS))||
  820. (pHelpInfo->hItemHandle == GetDlgItem(hwnd,IDC_RESTOREHIDDEN))
  821. )
  822. HtmlHelp((HWND)pHelpInfo->hItemHandle,
  823. g_szHelpFile,
  824. HH_TP_HELP_WM_HELP,
  825. (DWORD_PTR)((LPTSTR)s_rgHelpIDs));
  826. }
  827. return TRUE;
  828. }
  829. //
  830. // Called when user selects one of the 3 options radio buttons.
  831. //
  832. HRESULT
  833. CAutoUpdatePropSheet::_OnOptionSelected(
  834. HWND hwnd,
  835. int idOption
  836. )
  837. {
  838. const UINT idFirst = IDC_OPTION1;
  839. const UINT idLast = IDC_OPTION3;
  840. CheckRadioButton(hwnd, idFirst, idLast, idOption);
  841. if (idOption == IDC_OPTION3)
  842. _EnableCombo(hwnd, TRUE);
  843. else
  844. _EnableCombo(hwnd, FALSE);
  845. //
  846. // Enable the "Apply" button.
  847. //
  848. SendMessage(GetParent(hwnd), PSM_CHANGED, (WPARAM)hwnd, 0);
  849. return S_OK;
  850. }
  851. //
  852. // Called when the user presses the "Restore Hidden Items" button
  853. //
  854. HRESULT
  855. CAutoUpdatePropSheet::_OnRestoreHiddenItems(
  856. void
  857. )
  858. {
  859. return RemoveHiddenItems() ? S_OK : E_FAIL;
  860. }
  861. //
  862. // Enable or disable all controls on the property page.
  863. // All but the header text control.
  864. //
  865. HRESULT
  866. CAutoUpdatePropSheet::_EnableControls(
  867. HWND hwnd,
  868. BOOL bEnable
  869. )
  870. {
  871. static const UINT rgidCtls[] = {
  872. IDC_CHK_KEEPUPTODATE,
  873. IDC_OPTION1,
  874. IDC_OPTION2,
  875. IDC_OPTION3,
  876. IDC_RESTOREHIDDEN,
  877. IDC_GRP_OPTIONS,
  878. IDC_CMB_DAYS,
  879. IDC_STATICAT,
  880. IDC_CMB_HOURS,
  881. IDC_SCHINSTALLINK,
  882. IDC_AUTOUPDATELINK
  883. };
  884. for (int i = 0; i < ARRAYSIZE(rgidCtls); i++)
  885. {
  886. EnableWindow(GetDlgItem(hwnd, rgidCtls[i]), bEnable);
  887. }
  888. return S_OK;
  889. }
  890. //
  891. // Set the text to the right of the icon.
  892. //
  893. HRESULT
  894. CAutoUpdatePropSheet::_SetHeaderText(
  895. HWND hwnd,
  896. UINT idsText
  897. )
  898. {
  899. HRESULT hr;
  900. TCHAR szText[300] ;
  901. //ZeroMemory(szText, sizeof(szText));
  902. if (0 < LoadString(m_hInstance, idsText, szText, ARRAYSIZE(szText)))
  903. {
  904. SetWindowText(GetDlgItem(hwnd, IDC_TXT_HEADER), szText);
  905. hr = S_OK;
  906. }
  907. else
  908. {
  909. const DWORD dwErr = GetLastError();
  910. hr = HRESULT_FROM_WIN32(dwErr);
  911. }
  912. return hr;
  913. }
  914. //
  915. // This thread is where the Updates object lives. This allows us to
  916. // CoCreate the object without blocking the UI. If the Windows Update
  917. // service is not running, CoCreate can take several seconds. Without
  918. // placing this on another thread, this can make the UI appear to be
  919. // hung.
  920. //
  921. // *pvParam is the HWND of the property page window.
  922. //
  923. DWORD WINAPI
  924. CAutoUpdatePropSheet::_UpdatesObjectThreadProc( // [static]
  925. LPVOID pvParam
  926. )
  927. {
  928. HWND hwndClient = (HWND)pvParam;
  929. HRESULT hr = CoInitialize(NULL);
  930. if (SUCCEEDED(hr))
  931. {
  932. IUpdates *pUpdates;
  933. hr = CoCreateInstance(__uuidof(Updates),
  934. NULL,
  935. CLSCTX_LOCAL_SERVER,
  936. IID_IUpdates,
  937. (void **)&pUpdates);
  938. if (SUCCEEDED(hr))
  939. {
  940. //
  941. // Query the object for it's current data and send it
  942. // to the property page.
  943. //
  944. UPDATESOBJ_DATA data;
  945. data.fMask = UODI_ALL;
  946. HRESULT hrQuery = _QueryUpdatesObjectData(hwndClient, pUpdates, &data);
  947. SendMessage(hwndClient, PWM_INITUPDATESOBJECT, (WPARAM)SUCCEEDED(hrQuery), (LPARAM)&data);
  948. //
  949. // Now sit waiting for thread messages from the UI. We receive
  950. // either messages to configure Windows Update or a
  951. // WM_QUIT indicating it's time to go.
  952. //
  953. bool bDone = false;
  954. MSG msg;
  955. while(!bDone)
  956. {
  957. if (0 == GetMessage(&msg, NULL, 0, 0))
  958. {
  959. bDone = true;
  960. }
  961. else switch(msg.message)
  962. {
  963. case UOTM_SETDATA:
  964. if (NULL != msg.lParam)
  965. {
  966. UPDATESOBJ_DATA *pData = (UPDATESOBJ_DATA *)msg.lParam;
  967. _SetUpdatesObjectData(hwndClient, pUpdates, pData);
  968. LocalFree(pData);
  969. }
  970. break;
  971. default:
  972. TranslateMessage(&msg);
  973. DispatchMessage(&msg);
  974. break;
  975. }
  976. }
  977. pUpdates->Release();
  978. }
  979. CoUninitialize();
  980. }
  981. if (FAILED(hr))
  982. {
  983. //
  984. // Something failed. Notify the property page.
  985. // Most likely, the Windows Update service is not available.
  986. // That's the principal case this separate thread is addressing.
  987. //
  988. DEBUGMSG("AU cpl fails to create IUpdates object with error %#lx", hr);
  989. SendMessage(hwndClient, PWM_INITUPDATESOBJECT, FALSE, (LPARAM)NULL);
  990. }
  991. //
  992. // DllAddRef() was called before CreateThread in _OnInitDialog.
  993. //
  994. DllRelease();
  995. return 0;
  996. }
  997. HRESULT
  998. CAutoUpdatePropSheet::_QueryUpdatesObjectData( // [static]
  999. HWND /*hwnd*/,
  1000. IUpdates *pUpdates,
  1001. UPDATESOBJ_DATA *pData
  1002. )
  1003. {
  1004. HRESULT hr = S_OK;
  1005. if (NULL == pData)
  1006. {
  1007. return E_INVALIDARG;
  1008. }
  1009. if (UODI_OPTION & pData->fMask)
  1010. {
  1011. hr = pUpdates->get_Option(&(pData->Option));
  1012. if (FAILED(hr))
  1013. {
  1014. DEBUGMSG("AU cpl fail to get option with error %#lx", hr);
  1015. //
  1016. // ISSUE-2000/10/18-BrianAu Display error UI?
  1017. //
  1018. }
  1019. }
  1020. return hr;
  1021. }
  1022. HRESULT
  1023. CAutoUpdatePropSheet::_SetUpdatesObjectData( // [static]
  1024. HWND /*hwnd*/,
  1025. IUpdates *pUpdates,
  1026. UPDATESOBJ_DATA *pData
  1027. )
  1028. {
  1029. HRESULT hr = S_OK;
  1030. if (NULL == pData)
  1031. {
  1032. return E_INVALIDARG;
  1033. }
  1034. if (UODI_OPTION & pData->fMask)
  1035. {
  1036. hr = pUpdates->put_Option(pData->Option);
  1037. }
  1038. return hr;
  1039. }
  1040. //
  1041. // Exported instance generator. External coupling is reduced
  1042. // to this single function.
  1043. //
  1044. HRESULT
  1045. CAutoUpdatePropSheet_CreateInstance(
  1046. HINSTANCE hInstance,
  1047. REFIID riid,
  1048. void **ppv
  1049. )
  1050. {
  1051. return CAutoUpdatePropSheet::CreateInstance(hInstance, riid, ppv);
  1052. }
  1053. void CAutoUpdatePropSheet::_GetDayAndTimeFromUI(
  1054. HWND hWnd,
  1055. LPDWORD lpdwSchedInstallDay,
  1056. LPDWORD lpdwSchedInstallTime
  1057. )
  1058. {
  1059. HWND hComboDays = GetDlgItem(hWnd,IDC_CMB_DAYS);
  1060. HWND hComboHrs = GetDlgItem(hWnd,IDC_CMB_HOURS);
  1061. LRESULT nDayIndex = SendMessage(hComboDays,CB_GETCURSEL,0,(LPARAM)0);
  1062. LRESULT nTimeIndex = SendMessage(hComboHrs,CB_GETCURSEL,0,(LPARAM)0);
  1063. *lpdwSchedInstallDay = (DWORD)SendMessage(hComboDays,CB_GETITEMDATA, nDayIndex, (LPARAM)0);
  1064. *lpdwSchedInstallTime = (DWORD)SendMessage(hComboHrs,CB_GETITEMDATA, nTimeIndex, (LPARAM)0);
  1065. }
  1066. BOOL CAutoUpdatePropSheet::_FillDaysCombo(HWND hwnd, DWORD dwSchedInstallDay)
  1067. {
  1068. return FillDaysCombo(m_hInstance, hwnd, dwSchedInstallDay, IDS_STR_EVERYDAY, IDS_STR_SATURDAY);
  1069. }
  1070. void CAutoUpdatePropSheet::_OnKeepUptoDate(HWND hwnd)
  1071. {
  1072. LRESULT lResult = SendMessage(GetDlgItem(hwnd,IDC_CHK_KEEPUPTODATE),BM_GETCHECK,0,0);
  1073. //
  1074. // Enable the "Apply" button.
  1075. //
  1076. SendMessage(GetParent(hwnd), PSM_CHANGED, (WPARAM)hwnd, 0);
  1077. if (lResult == BST_CHECKED)
  1078. {
  1079. _EnableOptions(hwnd, TRUE);
  1080. }
  1081. else if (lResult == BST_UNCHECKED)
  1082. {
  1083. _EnableOptions(hwnd, FALSE);
  1084. }
  1085. /* //check box is either checked or not
  1086. else
  1087. {
  1088. return FALSE;
  1089. }
  1090. */
  1091. }
  1092. BOOL CAutoUpdatePropSheet::_EnableOptions(HWND hwnd, BOOL bState)
  1093. {
  1094. EnableWindow(GetDlgItem(hwnd,IDC_OPTION1),bState);
  1095. EnableWindow(GetDlgItem(hwnd,IDC_OPTION2),bState);
  1096. EnableWindow(GetDlgItem(hwnd,IDC_OPTION3),bState);
  1097. if (BST_CHECKED == SendMessage(GetDlgItem(hwnd,IDC_OPTION3),BM_GETCHECK,0,0))
  1098. {
  1099. _EnableCombo(hwnd, bState);
  1100. }
  1101. return TRUE;
  1102. }
  1103. BOOL CAutoUpdatePropSheet::_SetDefault(HWND hwnd)
  1104. {
  1105. LRESULT lResult = SendMessage(GetDlgItem(hwnd,IDC_CHK_KEEPUPTODATE),BM_SETCHECK,BST_CHECKED,0);
  1106. CheckRadioButton(hwnd, IDC_OPTION1, IDC_OPTION3, IDC_OPTION2);
  1107. return TRUE;
  1108. }
  1109. BOOL CAutoUpdatePropSheet::_EnableCombo(HWND hwnd, BOOL bState)
  1110. {
  1111. EnableWindow(GetDlgItem(hwnd,IDC_CMB_DAYS),bState);
  1112. EnableWindow(GetDlgItem(hwnd,IDC_STATICAT),bState);
  1113. EnableWindow(GetDlgItem(hwnd,IDC_CMB_HOURS),bState);
  1114. return TRUE;
  1115. }
  1116. void
  1117. CAutoUpdatePropSheet::LaunchHelp(LPCTSTR szURL)
  1118. {
  1119. HtmlHelp(NULL,szURL,HH_DISPLAY_TOPIC,NULL);
  1120. }