//+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 2000 // // File: prsheet.cpp // //-------------------------------------------------------------------------- #include "pch.h" #include "shellapi.h" #include "htmlhelp.h" #pragma hdrstop #define IDH_LETWINDOWS 3000 #define IDH_AUTOUPDATE_OPTION1 3001 #define IDH_AUTOUPDATE_OPTION2 3002 #define IDH_AUTOUPDATE_OPTION3 3003 #define IDH_DAYDROPDOWN 3004 #define IDH_TIMEDROPDOWN 3005 #define IDH_AUTOUPDATE_RESTOREHIDDEN 3006 #define IDH_NOHELP -1 const TCHAR g_szAutoUpdateItems[] = TEXT("AutoUpdateItems"); // // Create a structure for Updates Object data. This structure // is used to pass data between the property page and the // Updates Object thread. Today all we use is the "option" value // but there may be more later. // enum UPDATESOBJ_DATA_ITEMS { UODI_OPTION = 0x00000001, UODI_ALL = 0xFFFFFFFF }; struct UPDATESOBJ_DATA { DWORD fMask; // UPDATESOBJ_DATA_ITEMS mask AUOPTION Option; // Updates option setting. }; // // Private window message sent from the Updates Object thread proc // to the property page telling the page that the object has been // initialized. // // lParam - points to a UPATESOBJ_DATA structure containing // the initial configuration of the update's object with // which to initialize the UI. If wParam is 0, this // may be NULL. // // wParam - BOOL (0/1) indicating if object intialization was // successful or not. If wParam is 0, lParam may be NULL. // const UINT PWM_INITUPDATESOBJECT = WM_USER + 1; // // Message sent from the property page to the Updates Object thread // to tell it to configure the Auto Updates service. // // lParam - points to a UPDATESOBJ_DATA structure containing the // data to set. // // wParam - Unused. Set to 0. // const UINT UOTM_SETDATA = WM_USER + 2; // // Message cracker for WM_HELP. Not sure why windowsx.h doesn't have one. // // void Cls_OnHelp(HWND hwnd, HELPINFO *pHelpInfo) // #define HANDLE_WM_HELP(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (HELPINFO *)(lParam))) #define FORWARD_WM_HELP(hwnd, pHelpInfo, fn) \ (void)(fn)((hwnd), WM_HELP, (WPARAM)0, (LPARAM)pHelpInfo) // // Message cracker for PWM_INITUPDATESOBJECT. // #define HANDLE_PWM_INITUPDATESOBJECT(hwnd, wParam, lParam, fn) \ ((fn)((hwnd), (BOOL)(wParam), (UPDATESOBJ_DATA *)(lParam))) class CAutoUpdatePropSheet : public IShellExtInit, public IShellPropSheetExt { public: ~CAutoUpdatePropSheet(void); // // IUnknown // STDMETHOD(QueryInterface)(REFIID riid, void **ppv); STDMETHOD_(ULONG, AddRef)(void); STDMETHOD_(ULONG, Release)(void); // // IShellExtInit // STDMETHOD(Initialize)(LPCITEMIDLIST pidl, LPDATAOBJECT pdtobj, HKEY hkey); // // IShellPropSheetExt // STDMETHOD(AddPages)(LPFNADDPROPSHEETPAGE lpfnAddPage, LPARAM lParam); STDMETHOD(ReplacePage)(UINT uPageID, LPFNADDPROPSHEETPAGE lpfnAddPage, LPARAM lParam); // // Instance generator. // static HRESULT CreateInstance(HINSTANCE hInstance, REFIID riid, void **ppv); private: LONG m_cRef; HINSTANCE m_hInstance; DWORD m_idUpdatesObjectThread; HANDLE m_hThreadUpdatesObject; static const DWORD s_rgHelpIDs[]; BOOL _OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam); BOOL _OnNotify(HWND hwnd, UINT idFrom, LPNMHDR pnmhdr); BOOL _OnPSN_Apply(HWND hwnd); BOOL _OnDestroy(HWND hwnd); BOOL _OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify); BOOL _OnContextMenu(HWND hwnd, HWND hwndContext, UINT xPos, UINT yPos); BOOL _OnHelp(HWND hwnd, HELPINFO *pHelpInfo); BOOL _OkToDisplayPage(void); BOOL _OnInitUpdatesObject(HWND hwnd, BOOL bObjectInit, UPDATESOBJ_DATA *pData); //newly added methods : a-josem BOOL _EnableOptions(HWND hwnd, BOOL bState); BOOL _EnableCombo(HWND hwnd, BOOL bState); BOOL _SetDefault(HWND hwnd); void _GetDayAndTimeFromUI( HWND hWnd, LPDWORD lpdwSchedInstallDay,LPDWORD lpdwSchedInstallTime); BOOL _FillDaysCombo(HWND hwnd, DWORD dwSchedInstallDay); void _OnKeepUptoDate(HWND hwnd); static INT_PTR CALLBACK _DlgRestoreProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam); void LaunchLinkAction(HWND hwnd, UINT uCtrlId); void LaunchHelp(LPCTSTR szURL); //end of newly added methods, HRESULT _OnOptionSelected(HWND hwnd, int idOption); HRESULT _OnRestoreHiddenItems(void); HRESULT _EnableControls(HWND hwnd, BOOL bEnable); HRESULT _SetHeaderText(HWND hwnd, UINT idsText); HRESULT _AddPage(LPFNADDPROPSHEETPAGE lpfnAddPage, LPARAM lParam); static DWORD WINAPI _UpdatesObjectThreadProc(LPVOID pvParam); static HRESULT _QueryUpdatesObjectData(HWND hwnd, IUpdates *pUpdates, UPDATESOBJ_DATA *pData); static HRESULT _SetUpdatesObjectData(HWND hwnd, IUpdates *pUpdates, UPDATESOBJ_DATA *pData); static UINT CALLBACK _PageCallback(HWND hwnd, UINT uMsg, LPPROPSHEETPAGE ppsp); static INT_PTR CALLBACK _DlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); // // Allow public creation through instance generator only. // CAutoUpdatePropSheet(HINSTANCE hInstance); // // Prevent copy. // CAutoUpdatePropSheet(const CAutoUpdatePropSheet& rhs); // not implemented. CAutoUpdatePropSheet& operator = (const CAutoUpdatePropSheet& rhs); // not implemented. }; CAutoUpdatePropSheet::CAutoUpdatePropSheet( HINSTANCE hInstance ) : m_cRef(1), m_hInstance(hInstance), m_idUpdatesObjectThread(0), m_hThreadUpdatesObject(NULL) { DllAddRef(); } CAutoUpdatePropSheet::~CAutoUpdatePropSheet( void ) { if (NULL != m_hThreadUpdatesObject) { CloseHandle(m_hThreadUpdatesObject); } DllRelease(); } HRESULT CAutoUpdatePropSheet::CreateInstance( HINSTANCE hInstance, REFIID riid, void **ppvOut ) { HRESULT hr = E_OUTOFMEMORY; if (NULL == ppvOut) { return E_INVALIDARG; } *ppvOut = NULL; CAutoUpdatePropSheet *pSheet = new CAutoUpdatePropSheet(hInstance); if (NULL != pSheet) { hr = pSheet->QueryInterface(riid, ppvOut); pSheet->Release(); } return hr; } STDMETHODIMP CAutoUpdatePropSheet::QueryInterface( REFIID riid, void **ppvOut ) { HRESULT hr = E_NOINTERFACE; if (NULL == ppvOut) return E_INVALIDARG; *ppvOut = NULL; if (IID_IUnknown == riid || IID_IShellExtInit == riid) { *ppvOut = static_cast(this); } else if (IID_IShellPropSheetExt == riid) { *ppvOut = static_cast(this); } if (NULL != *ppvOut) { ((LPUNKNOWN)*ppvOut)->AddRef(); hr = NOERROR; } return hr; } STDMETHODIMP_(ULONG) CAutoUpdatePropSheet::AddRef( void ) { return InterlockedIncrement(&m_cRef); } STDMETHODIMP_(ULONG) CAutoUpdatePropSheet::Release( void ) { if (InterlockedDecrement(&m_cRef)) return m_cRef; delete this; return 0; } // // IShellExtInit::Initialize impl. // STDMETHODIMP CAutoUpdatePropSheet::Initialize( LPCITEMIDLIST /*pidlFolder*/, LPDATAOBJECT /*pdtobj*/, HKEY /*hkeyProgID*/ ) { return NOERROR; } // // IShellPropSheetExt::AddPages impl. // STDMETHODIMP CAutoUpdatePropSheet::AddPages( LPFNADDPROPSHEETPAGE lpfnAddPage, LPARAM lParam ) { HRESULT hr = E_FAIL; // Assume failure. if (_OkToDisplayPage()) { hr = _AddPage(lpfnAddPage, lParam); } return hr; } // // IShellPropSheetExt::ReplacePage impl. // STDMETHODIMP CAutoUpdatePropSheet::ReplacePage( UINT /*uPageID*/, LPFNADDPROPSHEETPAGE /*lpfnAddPage*/, LPARAM /*lParam*/ ) { return E_NOTIMPL; } // // Determines if it's OK to display the auto-update prop page. // Reasons for NOT displaying: // // 1. User is not an administrator. // 2. The "NoAutoUpdate" policy restriction is in place. // // BOOL CAutoUpdatePropSheet::_OkToDisplayPage( void ) { BOOL bOkToDisplay = TRUE; if (!IsNTAdmin(0,0)) { bOkToDisplay = FALSE; } else { bOkToDisplay = fAccessibleToAU(); } return bOkToDisplay; } // // Add our page to the property sheet. // HRESULT CAutoUpdatePropSheet::_AddPage( LPFNADDPROPSHEETPAGE lpfnAddPage, LPARAM lParam ) { HRESULT hr = E_FAIL; PROPSHEETPAGE psp; ZeroMemory(&psp, sizeof(psp)); psp.dwSize = sizeof(PROPSHEETPAGE); psp.dwFlags = PSP_USECALLBACK; psp.hInstance = m_hInstance; psp.pszTemplate = MAKEINTRESOURCE(IDD_AUTOUPDATE); psp.pszTitle = NULL; psp.pfnDlgProc = CAutoUpdatePropSheet::_DlgProc; psp.pfnCallback = CAutoUpdatePropSheet::_PageCallback; psp.lParam = (LPARAM)this; HPROPSHEETPAGE hPage = CreatePropertySheetPage(&psp); if (NULL != hPage) { if (lpfnAddPage(hPage, lParam)) { hr = S_OK; } else { DestroyPropertySheetPage(hPage); } } return hr; } // // We implement the page callback to manage the lifetime of the // C++ object attached to the property page. // We also use the callback to defer creation of the IUpdates object. // UINT CALLBACK CAutoUpdatePropSheet::_PageCallback( // [static] HWND /*hwnd*/, UINT uMsg, LPPROPSHEETPAGE ppsp ) { UINT uReturn = 1; if (NULL == ppsp) { return uReturn; } CAutoUpdatePropSheet *pThis = (CAutoUpdatePropSheet *)ppsp->lParam; switch(uMsg) { case PSPCB_ADDREF: pThis->AddRef(); break; case PSPCB_RELEASE: pThis->Release(); break; } return uReturn; } // // ISSUE-2000/10/12-BrianAu Need help IDs. // const DWORD CAutoUpdatePropSheet::s_rgHelpIDs[] = { IDC_CHK_KEEPUPTODATE, DWORD(IDH_LETWINDOWS), IDC_OPTION1, DWORD(IDH_AUTOUPDATE_OPTION1), IDC_OPTION2, DWORD(IDH_AUTOUPDATE_OPTION2), IDC_OPTION3, DWORD(IDH_AUTOUPDATE_OPTION3), IDC_CMB_DAYS, DWORD(IDH_DAYDROPDOWN), IDC_CMB_HOURS, DWORD(IDH_TIMEDROPDOWN), IDC_RESTOREHIDDEN, DWORD(IDH_AUTOUPDATE_RESTOREHIDDEN), IDC_GRP_OPTIONS, DWORD(IDH_NOHELP), IDI_AUTOUPDATE, DWORD(IDH_NOHELP), 0, 0 }; INT_PTR CALLBACK CAutoUpdatePropSheet::_DlgProc( // [static] HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { CAutoUpdatePropSheet *pThis = NULL; if (WM_INITDIALOG == uMsg) { PROPSHEETPAGE *psp = (PROPSHEETPAGE *)lParam; pThis = (CAutoUpdatePropSheet *)psp->lParam; if (!SetProp(hwnd, g_szPropDialogPtr, (HANDLE)pThis)) { pThis = NULL; } } else { pThis = (CAutoUpdatePropSheet *)GetProp(hwnd, g_szPropDialogPtr); } if (NULL != pThis) { switch(uMsg) { HANDLE_MSG(hwnd, WM_INITDIALOG, pThis->_OnInitDialog); HANDLE_MSG(hwnd, WM_COMMAND, pThis->_OnCommand); HANDLE_MSG(hwnd, WM_DESTROY, pThis->_OnDestroy); HANDLE_MSG(hwnd, WM_NOTIFY, pThis->_OnNotify); HANDLE_MSG(hwnd, WM_CONTEXTMENU, pThis->_OnContextMenu); HANDLE_MSG(hwnd, WM_HELP, pThis->_OnHelp); HANDLE_MSG(hwnd, PWM_INITUPDATESOBJECT, pThis->_OnInitUpdatesObject); default: break; } } return FALSE; } void EnableRestoreDeclinedItems(HWND hWnd, BOOL fEnable) { EnableWindow(GetDlgItem(hWnd, IDC_RESTOREHIDDEN), fEnable); } // // PWM_INITUPDATESOBJECT handler. // This is called when the Updates Object thread has either successfully // CoCreated the Updates object or CoCreation has failed. // It's possible that the Windows Update Service is not running. // This is how we handle that condition. // BOOL CAutoUpdatePropSheet::_OnInitUpdatesObject( HWND hwnd, BOOL bObjectInitSuccessful, UPDATESOBJ_DATA *pData ) { if (bObjectInitSuccessful) { if (NULL == pData) { return FALSE; } // // Updates object was created and initialized. The // pData pointer refers to the initial state information retrieved // from the object. Initialize the property page. // _SetHeaderText(hwnd, IDS_HEADER_CONNECTED); _EnableControls(hwnd, TRUE); EnableRestoreDeclinedItems( hwnd, FHiddenItemsExist()); switch(pData->Option.dwOption) { case AUOPTION_AUTOUPDATE_DISABLE: CheckRadioButton(hwnd, IDC_OPTION1, IDC_OPTION3, IDC_OPTION1); _EnableOptions(hwnd, FALSE); _EnableCombo(hwnd, FALSE); SendMessage(GetDlgItem(hwnd,IDC_CHK_KEEPUPTODATE),BM_SETCHECK,BST_UNCHECKED,0); break; case AUOPTION_PREDOWNLOAD_NOTIFY: CheckRadioButton(hwnd, IDC_OPTION1, IDC_OPTION3, IDC_OPTION1); _EnableCombo(hwnd, FALSE); SendMessage(GetDlgItem(hwnd,IDC_CHK_KEEPUPTODATE),BM_SETCHECK,BST_CHECKED,0); break; case AUOPTION_INSTALLONLY_NOTIFY: CheckRadioButton(hwnd, IDC_OPTION1, IDC_OPTION3, IDC_OPTION2); _EnableCombo(hwnd, FALSE); SendMessage(GetDlgItem(hwnd,IDC_CHK_KEEPUPTODATE),BM_SETCHECK,BST_CHECKED,0); break; case AUOPTION_SCHEDULED: CheckRadioButton(hwnd, IDC_OPTION1, IDC_OPTION3, IDC_OPTION3); _EnableCombo(hwnd, TRUE); SendMessage(GetDlgItem(hwnd,IDC_CHK_KEEPUPTODATE),BM_SETCHECK,BST_CHECKED,0); break; default: _SetDefault(hwnd); break; } _FillDaysCombo(hwnd, pData->Option.dwSchedInstallDay); FillHrsCombo(hwnd, pData->Option.dwSchedInstallTime); if (pData->Option.fDomainPolicy) { DisableUserInput(hwnd); } } else { // // Something failed when creating the Updates object. // Most likely, the Windows Update service is not running. // _SetHeaderText(hwnd, IDS_HEADER_UNAVAILABLE); } return FALSE; } // // WM_INITDIALOG handler. // BOOL CAutoUpdatePropSheet::_OnInitDialog( HWND hwnd, HWND /*hwndFocus*/, LPARAM /*lParam*/ ) { // // If the thread is created, the threadproc will call // DllRelease(); // DllAddRef(); // // Disable all page controls and display a message in the // header indicating that we're trying to connect to the // Windows Update service. // _SetHeaderText(hwnd, IDS_HEADER_CONNECTING); _EnableControls(hwnd, FALSE); // // Create the thread on which the Updates object lives. // Communication between the thread and the property page is // through the messages PWM_INITUPDATESOBJECT and UOTM_SETDATA. // m_hThreadUpdatesObject = CreateThread(NULL, 0, _UpdatesObjectThreadProc, (LPVOID)hwnd, 0, &m_idUpdatesObjectThread); if (NULL == m_hThreadUpdatesObject) { DllRelease(); } return TRUE; } // // WM_DESTROY handler. // BOOL CAutoUpdatePropSheet::_OnDestroy( HWND hwnd ) { RemoveProp(hwnd, g_szPropDialogPtr); if (0 != m_idUpdatesObjectThread) { // // Terminate the Update Objects thread. // if (0 != PostThreadMessage(m_idUpdatesObjectThread, WM_QUIT, 0, 0)) { // // Wait for normal thread termination. // WaitForSingleObject(m_hThreadUpdatesObject, 5000); } } return FALSE; } // // WM_COMMAND handler. // BOOL CAutoUpdatePropSheet::_OnCommand( HWND hwnd, int id, HWND /*hwndCtl*/, UINT codeNotify ) { INT Result; switch(id) { case IDC_CHK_KEEPUPTODATE: if (BN_CLICKED == codeNotify) { _OnKeepUptoDate(hwnd); } break; case IDC_OPTION1: case IDC_OPTION2: case IDC_OPTION3: if(BN_CLICKED == codeNotify) { _OnOptionSelected(hwnd, id); } break; case IDC_CMB_DAYS: case IDC_CMB_HOURS: if(CBN_SELCHANGE == codeNotify) { // // Enable the "Apply" button. // SendMessage(GetParent(hwnd), PSM_CHANGED, (WPARAM)hwnd, 0); } break; case IDC_RESTOREHIDDEN: Result = (INT)DialogBoxParam(m_hInstance, MAKEINTRESOURCE(IDD_RESTOREUPDATE), hwnd, (DLGPROC)CAutoUpdatePropSheet::_DlgRestoreProc, (LPARAM)NULL); if (Result == TRUE) { if (SUCCEEDED (_OnRestoreHiddenItems())) { EnableRestoreDeclinedItems( hwnd, FALSE); } } break; default: return FALSE; } return TRUE; } INT_PTR CALLBACK CAutoUpdatePropSheet::_DlgRestoreProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { if (uMsg == WM_INITDIALOG) { HWND hwndOwner; RECT rc, rcDlg, rcOwner; // Get the owner window and dialog box rectangles. if ((hwndOwner = GetParent(hwnd)) == NULL) { hwndOwner = GetDesktopWindow(); } GetWindowRect(hwndOwner, &rcOwner); GetWindowRect(hwnd, &rcDlg); CopyRect(&rc, &rcOwner); // Offset the owner and dialog box rectangles so that // right and bottom values represent the width and // height, and then offset the owner again to discard // space taken up by the dialog box. OffsetRect(&rcDlg, -rcDlg.left, -rcDlg.top); OffsetRect(&rc, -rc.left, -rc.top); OffsetRect(&rc, -rcDlg.right, -rcDlg.bottom); // The new position is the sum of half the remaining // space and the owner's original position. SetWindowPos(hwnd, HWND_TOP, rcOwner.left + (rc.right / 2), rcOwner.top + (rc.bottom / 2), 0, 0, // ignores size arguments SWP_NOSIZE); } if (uMsg == WM_COMMAND) { switch (LOWORD(wParam)) { case IDOK: EndDialog(hwnd, TRUE); return TRUE; case IDCANCEL: EndDialog(hwnd, FALSE); return TRUE; } } return FALSE; } // // WM_NOTIFY handler. // BOOL CAutoUpdatePropSheet::_OnNotify( HWND hwnd, UINT idFrom, LPNMHDR pnmhdr ) { switch(pnmhdr->code) { case PSN_APPLY: _OnPSN_Apply(hwnd); break; case NM_RETURN: case NM_CLICK: if (idFrom == IDC_AUTOUPDATELINK || idFrom == IDC_SCHINSTALLINK) LaunchLinkAction(hwnd, idFrom); break; default: break; } return FALSE; } void CAutoUpdatePropSheet::LaunchLinkAction(HWND hwnd, UINT uCtrlId) { switch (uCtrlId) { case IDC_AUTOUPDATELINK: LaunchHelp(gtszAUOverviewUrl); break; case IDC_SCHINSTALLINK: LaunchHelp(gtszAUXPSchedInstallUrl); break; } return; } // // Called when the user presses the "Apply" button or the "OK" // button when the page has been changed. // BOOL CAutoUpdatePropSheet::_OnPSN_Apply( HWND hwnd ) { HRESULT hr = E_FAIL; // // Create a structure that can be passed to the Updates Object thread // by way of the UOTM_SETDATA thread message. The thread will free // the buffer when it's finished with it. // UPDATESOBJ_DATA *pData = (UPDATESOBJ_DATA *)LocalAlloc(LPTR, sizeof(*pData)); if (NULL == pData) { hr = E_OUTOFMEMORY; } else { pData->Option.dwSchedInstallDay = -1; pData->Option.dwSchedInstallTime = -1; pData->fMask = UODI_ALL; static const struct { UINT idCtl; DWORD dwOption; } rgMap[] = { { IDC_OPTION1, AUOPTION_PREDOWNLOAD_NOTIFY }, { IDC_OPTION2, AUOPTION_INSTALLONLY_NOTIFY }, { IDC_OPTION3, AUOPTION_SCHEDULED } }; if (IsDlgButtonChecked(hwnd, IDC_CHK_KEEPUPTODATE) == BST_CHECKED) { // // Determine the WAU option based on the radio button configuration. // for (int i = 0; i < ARRAYSIZE(rgMap); i++) { if (IsDlgButtonChecked(hwnd, rgMap[i].idCtl) == BST_CHECKED) { pData->Option.dwOption = rgMap[i].dwOption; break; } } } else pData->Option.dwOption = AUOPTION_AUTOUPDATE_DISABLE; if (AUOPTION_SCHEDULED == pData->Option.dwOption) { _GetDayAndTimeFromUI(hwnd, &(pData->Option.dwSchedInstallDay), &(pData->Option.dwSchedInstallTime)); } if (0 != m_idUpdatesObjectThread) { if (0 != PostThreadMessage(m_idUpdatesObjectThread, UOTM_SETDATA, 0, (LPARAM)pData)) { hr = S_OK; pData = NULL; } } if (NULL != pData) { LocalFree(pData); pData = NULL; } } if (SUCCEEDED(hr)) { // // Inform the property sheet the update was successful and // disable the "Apply" button. // SetWindowLongPtr(hwnd, DWLP_MSGRESULT, PSNRET_NOERROR); SendMessage(GetParent(hwnd), PSM_UNCHANGED, (WPARAM)hwnd, 0); } return FALSE; } // // WM_CONTEXTMENU handler. // BOOL CAutoUpdatePropSheet::_OnContextMenu( HWND hwnd, HWND hwndContext, UINT /*xPos*/, UINT /*yPos*/ ) { if ((hwndContext == GetDlgItem(hwnd,IDC_CHK_KEEPUPTODATE))|| (hwndContext == GetDlgItem(hwnd,IDC_OPTION1))|| (hwndContext == GetDlgItem(hwnd,IDC_OPTION2))|| (hwndContext == GetDlgItem(hwnd,IDC_OPTION3))|| (hwndContext == GetDlgItem(hwnd,IDC_CMB_DAYS))|| (hwndContext == GetDlgItem(hwnd,IDC_CMB_HOURS))|| (hwndContext == GetDlgItem(hwnd,IDC_RESTOREHIDDEN))) { HtmlHelp(hwndContext,g_szHelpFile,HH_TP_HELP_CONTEXTMENU,(DWORD_PTR)((LPTSTR)s_rgHelpIDs)); } return FALSE; } // // WM_HELP handler. // BOOL CAutoUpdatePropSheet::_OnHelp( HWND hwnd, HELPINFO *pHelpInfo ) { if (NULL == pHelpInfo) { return TRUE; } if (HELPINFO_WINDOW == pHelpInfo->iContextType) { if ((pHelpInfo->hItemHandle == GetDlgItem(hwnd,IDC_CHK_KEEPUPTODATE))|| (pHelpInfo->hItemHandle == GetDlgItem(hwnd,IDC_OPTION1))|| (pHelpInfo->hItemHandle == GetDlgItem(hwnd,IDC_OPTION2))|| (pHelpInfo->hItemHandle == GetDlgItem(hwnd,IDC_OPTION3))|| (pHelpInfo->hItemHandle == GetDlgItem(hwnd,IDC_CMB_DAYS))|| (pHelpInfo->hItemHandle == GetDlgItem(hwnd,IDC_CMB_HOURS))|| (pHelpInfo->hItemHandle == GetDlgItem(hwnd,IDC_RESTOREHIDDEN)) ) HtmlHelp((HWND)pHelpInfo->hItemHandle, g_szHelpFile, HH_TP_HELP_WM_HELP, (DWORD_PTR)((LPTSTR)s_rgHelpIDs)); } return TRUE; } // // Called when user selects one of the 3 options radio buttons. // HRESULT CAutoUpdatePropSheet::_OnOptionSelected( HWND hwnd, int idOption ) { const UINT idFirst = IDC_OPTION1; const UINT idLast = IDC_OPTION3; CheckRadioButton(hwnd, idFirst, idLast, idOption); if (idOption == IDC_OPTION3) _EnableCombo(hwnd, TRUE); else _EnableCombo(hwnd, FALSE); // // Enable the "Apply" button. // SendMessage(GetParent(hwnd), PSM_CHANGED, (WPARAM)hwnd, 0); return S_OK; } // // Called when the user presses the "Restore Hidden Items" button // HRESULT CAutoUpdatePropSheet::_OnRestoreHiddenItems( void ) { return RemoveHiddenItems() ? S_OK : E_FAIL; } // // Enable or disable all controls on the property page. // All but the header text control. // HRESULT CAutoUpdatePropSheet::_EnableControls( HWND hwnd, BOOL bEnable ) { static const UINT rgidCtls[] = { IDC_CHK_KEEPUPTODATE, IDC_OPTION1, IDC_OPTION2, IDC_OPTION3, IDC_RESTOREHIDDEN, IDC_GRP_OPTIONS, IDC_CMB_DAYS, IDC_STATICAT, IDC_CMB_HOURS, IDC_SCHINSTALLINK, IDC_AUTOUPDATELINK }; for (int i = 0; i < ARRAYSIZE(rgidCtls); i++) { EnableWindow(GetDlgItem(hwnd, rgidCtls[i]), bEnable); } return S_OK; } // // Set the text to the right of the icon. // HRESULT CAutoUpdatePropSheet::_SetHeaderText( HWND hwnd, UINT idsText ) { HRESULT hr; TCHAR szText[300] ; //ZeroMemory(szText, sizeof(szText)); if (0 < LoadString(m_hInstance, idsText, szText, ARRAYSIZE(szText))) { SetWindowText(GetDlgItem(hwnd, IDC_TXT_HEADER), szText); hr = S_OK; } else { const DWORD dwErr = GetLastError(); hr = HRESULT_FROM_WIN32(dwErr); } return hr; } // // This thread is where the Updates object lives. This allows us to // CoCreate the object without blocking the UI. If the Windows Update // service is not running, CoCreate can take several seconds. Without // placing this on another thread, this can make the UI appear to be // hung. // // *pvParam is the HWND of the property page window. // DWORD WINAPI CAutoUpdatePropSheet::_UpdatesObjectThreadProc( // [static] LPVOID pvParam ) { HWND hwndClient = (HWND)pvParam; HRESULT hr = CoInitialize(NULL); if (SUCCEEDED(hr)) { IUpdates *pUpdates; hr = CoCreateInstance(__uuidof(Updates), NULL, CLSCTX_LOCAL_SERVER, IID_IUpdates, (void **)&pUpdates); if (SUCCEEDED(hr)) { // // Query the object for it's current data and send it // to the property page. // UPDATESOBJ_DATA data; data.fMask = UODI_ALL; HRESULT hrQuery = _QueryUpdatesObjectData(hwndClient, pUpdates, &data); SendMessage(hwndClient, PWM_INITUPDATESOBJECT, (WPARAM)SUCCEEDED(hrQuery), (LPARAM)&data); // // Now sit waiting for thread messages from the UI. We receive // either messages to configure Windows Update or a // WM_QUIT indicating it's time to go. // bool bDone = false; MSG msg; while(!bDone) { if (0 == GetMessage(&msg, NULL, 0, 0)) { bDone = true; } else switch(msg.message) { case UOTM_SETDATA: if (NULL != msg.lParam) { UPDATESOBJ_DATA *pData = (UPDATESOBJ_DATA *)msg.lParam; _SetUpdatesObjectData(hwndClient, pUpdates, pData); LocalFree(pData); } break; default: TranslateMessage(&msg); DispatchMessage(&msg); break; } } pUpdates->Release(); } CoUninitialize(); } if (FAILED(hr)) { // // Something failed. Notify the property page. // Most likely, the Windows Update service is not available. // That's the principal case this separate thread is addressing. // DEBUGMSG("AU cpl fails to create IUpdates object with error %#lx", hr); SendMessage(hwndClient, PWM_INITUPDATESOBJECT, FALSE, (LPARAM)NULL); } // // DllAddRef() was called before CreateThread in _OnInitDialog. // DllRelease(); return 0; } HRESULT CAutoUpdatePropSheet::_QueryUpdatesObjectData( // [static] HWND /*hwnd*/, IUpdates *pUpdates, UPDATESOBJ_DATA *pData ) { HRESULT hr = S_OK; if (NULL == pData) { return E_INVALIDARG; } if (UODI_OPTION & pData->fMask) { hr = pUpdates->get_Option(&(pData->Option)); if (FAILED(hr)) { DEBUGMSG("AU cpl fail to get option with error %#lx", hr); // // ISSUE-2000/10/18-BrianAu Display error UI? // } } return hr; } HRESULT CAutoUpdatePropSheet::_SetUpdatesObjectData( // [static] HWND /*hwnd*/, IUpdates *pUpdates, UPDATESOBJ_DATA *pData ) { HRESULT hr = S_OK; if (NULL == pData) { return E_INVALIDARG; } if (UODI_OPTION & pData->fMask) { hr = pUpdates->put_Option(pData->Option); } return hr; } // // Exported instance generator. External coupling is reduced // to this single function. // HRESULT CAutoUpdatePropSheet_CreateInstance( HINSTANCE hInstance, REFIID riid, void **ppv ) { return CAutoUpdatePropSheet::CreateInstance(hInstance, riid, ppv); } void CAutoUpdatePropSheet::_GetDayAndTimeFromUI( HWND hWnd, LPDWORD lpdwSchedInstallDay, LPDWORD lpdwSchedInstallTime ) { HWND hComboDays = GetDlgItem(hWnd,IDC_CMB_DAYS); HWND hComboHrs = GetDlgItem(hWnd,IDC_CMB_HOURS); LRESULT nDayIndex = SendMessage(hComboDays,CB_GETCURSEL,0,(LPARAM)0); LRESULT nTimeIndex = SendMessage(hComboHrs,CB_GETCURSEL,0,(LPARAM)0); *lpdwSchedInstallDay = (DWORD)SendMessage(hComboDays,CB_GETITEMDATA, nDayIndex, (LPARAM)0); *lpdwSchedInstallTime = (DWORD)SendMessage(hComboHrs,CB_GETITEMDATA, nTimeIndex, (LPARAM)0); } BOOL CAutoUpdatePropSheet::_FillDaysCombo(HWND hwnd, DWORD dwSchedInstallDay) { return FillDaysCombo(m_hInstance, hwnd, dwSchedInstallDay, IDS_STR_EVERYDAY, IDS_STR_SATURDAY); } void CAutoUpdatePropSheet::_OnKeepUptoDate(HWND hwnd) { LRESULT lResult = SendMessage(GetDlgItem(hwnd,IDC_CHK_KEEPUPTODATE),BM_GETCHECK,0,0); // // Enable the "Apply" button. // SendMessage(GetParent(hwnd), PSM_CHANGED, (WPARAM)hwnd, 0); if (lResult == BST_CHECKED) { _EnableOptions(hwnd, TRUE); } else if (lResult == BST_UNCHECKED) { _EnableOptions(hwnd, FALSE); } /* //check box is either checked or not else { return FALSE; } */ } BOOL CAutoUpdatePropSheet::_EnableOptions(HWND hwnd, BOOL bState) { EnableWindow(GetDlgItem(hwnd,IDC_OPTION1),bState); EnableWindow(GetDlgItem(hwnd,IDC_OPTION2),bState); EnableWindow(GetDlgItem(hwnd,IDC_OPTION3),bState); if (BST_CHECKED == SendMessage(GetDlgItem(hwnd,IDC_OPTION3),BM_GETCHECK,0,0)) { _EnableCombo(hwnd, bState); } return TRUE; } BOOL CAutoUpdatePropSheet::_SetDefault(HWND hwnd) { LRESULT lResult = SendMessage(GetDlgItem(hwnd,IDC_CHK_KEEPUPTODATE),BM_SETCHECK,BST_CHECKED,0); CheckRadioButton(hwnd, IDC_OPTION1, IDC_OPTION3, IDC_OPTION2); return TRUE; } BOOL CAutoUpdatePropSheet::_EnableCombo(HWND hwnd, BOOL bState) { EnableWindow(GetDlgItem(hwnd,IDC_CMB_DAYS),bState); EnableWindow(GetDlgItem(hwnd,IDC_STATICAT),bState); EnableWindow(GetDlgItem(hwnd,IDC_CMB_HOURS),bState); return TRUE; } void CAutoUpdatePropSheet::LaunchHelp(LPCTSTR szURL) { HtmlHelp(NULL,szURL,HH_DISPLAY_TOPIC,NULL); }