|
|
//____________________________________________________________________________
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1995 - 1996.
//
// File: settings.cxx
//
// Contents:
//
// Classes:
//
// Functions:
//
// Notes: For the first release of the scheduling agent, all security
// operations are disabled under Win95, even Win95 to NT.
//
// History: 3/4/1996 RaviR Created
//
//____________________________________________________________________________
#include "..\pch\headers.hxx"
#pragma hdrstop
#include <mstask.h>
#include "..\inc\common.hxx"
#include "..\folderui\dbg.h"
#include "..\folderui\macros.h"
#include "..\folderui\util.hxx"
#if !defined(_CHICAGO_)
#include "..\inc\network.hxx"
#endif // !defined(_CHICAGO_)
#include "..\inc\dll.hxx"
#include "dlg.hxx"
#include "rc.h"
#include "defines.h"
#include "uiutil.hxx"
#include "helpids.h"
#include "schedui.hxx"
//
// (Control id, help id) list for context sensitivity help.
//
ULONG s_aSettingsPageHelpIds[] = { chk_start_on_idle, Hchk_start_on_idle, chk_stop_if_not_idle, Hchk_stop_if_not_idle, chk_dont_start_if_on_batteries, Hchk_dont_start_if_on_batteries, chk_kill_if_going_on_batteries, Hchk_kill_if_going_on_batteries, chk_delete_when_done, Hchk_delete_when_done, chk_stop_after, Hchk_stop_after, txt_stop_after_hr, Htxt_stop_after_hr, spin_stop_after_hr, Hspin_stop_after_hr, txt_stop_after_min, Htxt_stop_after_min, spin_stop_after_min, Hspin_stop_after_min, txt_idle_min, Htxt_idle_min, spin_idle_min, Hspin_idle_min, lbl_idle_deadline1, Hlbl_idle_deadline, lbl_idle_deadline2, Hlbl_idle_deadline, txt_idle_deadline, Htxt_idle_deadline, spin_idle_deadline, Hspin_idle_deadline, lbl_min, Hlbl_settings_min, lbl_hours, Hlbl_settings_hours, grp_idle_time, Hgrp_idle_time, txt_idle_minutes, Htxt_idle_minutes, grp_task_completed, Hgrp_task_completed, grp_power_management, Hgrp_power_management, btn_new, Hbtn_new, btn_delete, Hbtn_delete, chk_system_required, Hchk_system_required, 0,0 };
extern "C" TCHAR szMstaskHelp[];
//
// extern
//
extern HINSTANCE g_hInstance;
//
// All task flags included in this define will be modified when the page
// values are persisted in the _OnApply method.
//
// If we're running on NT and targeting NT, the controls for some of these
// flags will be initialized to the job's values and hidden.
//
#define TASK_FLAGS_IN_SETTINGS_PAGE (TASK_FLAG_START_ONLY_IF_IDLE | \
TASK_FLAG_KILL_ON_IDLE_END | \ TASK_FLAG_DONT_START_IF_ON_BATTERIES | \ TASK_FLAG_KILL_IF_GOING_ON_BATTERIES | \ TASK_FLAG_SYSTEM_REQUIRED | \ TASK_FLAG_DELETE_WHEN_DONE)
//____________________________________________________________________________
//____________________________________________________________________________
//________________ ______________________________________
//________________ class CSettingsPage ______________________________________
//________________ ______________________________________
//____________________________________________________________________________
//____________________________________________________________________________
class CSettingsPage : public CPropPage { public:
CSettingsPage(ITask * pIJob, LPTSTR ptszTaskPath, BOOL fPersistChanges);
~CSettingsPage();
private:
virtual LRESULT _OnInitDialog(LPARAM lParam); virtual LRESULT _OnCommand(int id, HWND hwndCtl, UINT codeNotify); virtual LRESULT _OnApply(); virtual LRESULT _OnPSMQuerySibling(WPARAM wParam, LPARAM lParam); virtual LRESULT _OnPSNSetActive(LPARAM lParam); virtual LRESULT _OnPSNKillActive(LPARAM lParam); virtual LRESULT _OnHelp(HANDLE hRequesting, UINT uiHelpCommand);
void _ReadIdleSettings();
void _ErrorDialog(int idsErr, LONG error = 0, UINT idsHelpHint = 0) { SchedUIErrorDialog(Hwnd(), idsErr, error, idsHelpHint); }
BOOL _PerformSanityChk();
ITask * m_pIJob;
DWORD m_dwFlags; DWORD m_dwMaxRunTime; WORD m_wIdleWait; WORD m_wIdleDeadline;
//
// Should we save on Apply or OK.
//
BOOL m_fPersistChanges;
}; // class CSettingsPage
inline CSettingsPage::CSettingsPage( ITask * pIJob, LPTSTR ptszTaskPath, BOOL fPersistChanges) : m_pIJob(pIJob), m_fPersistChanges(fPersistChanges), m_dwFlags(0), m_dwMaxRunTime(0), m_wIdleWait(0), m_wIdleDeadline(0), CPropPage(MAKEINTRESOURCE(settings_page), ptszTaskPath) { TRACE(CSettingsPage, CSettingsPage);
Win4Assert(m_pIJob != NULL);
pIJob->AddRef(); }
inline CSettingsPage::~CSettingsPage() { TRACE(CSettingsPage, ~CSettingsPage);
if (m_pIJob != NULL) { m_pIJob->Release(); } }
LRESULT CSettingsPage::_OnHelp( HANDLE hRequesting, UINT uiHelpCommand) { WinHelp((HWND)hRequesting, szMstaskHelp, uiHelpCommand, (DWORD_PTR)(LPSTR)s_aSettingsPageHelpIds); return TRUE; }
LRESULT CSettingsPage::_OnInitDialog( LPARAM lParam) { TRACE(CSettingsPage, _OnInitDialog);
HRESULT hr = S_OK; ITask * pIJob = m_pIJob;
Spin_SetRange(m_hPage, spin_idle_min, 1, MAX_IDLE_MINUTES); Edit_LimitText(_hCtrl(txt_idle_min), MAX_IDLE_DIGITS);
Spin_SetRange(m_hPage, spin_idle_deadline, 0, MAX_IDLE_MINUTES); Edit_LimitText(_hCtrl(txt_idle_deadline), MAX_IDLE_DIGITS);
Spin_SetRange(m_hPage, spin_stop_after_hr, 0, MAX_MAXRUNTIME_HOURS); Edit_LimitText(_hCtrl(txt_stop_after_hr), MAX_MAXRUNTIME_DIGITS);
Spin_SetRange(m_hPage, spin_stop_after_min, 0, 59); Edit_LimitText(_hCtrl(txt_stop_after_min), 2);
do { //
// Set job flags
//
hr = pIJob->GetFlags(&m_dwFlags);
CHECK_HRESULT(hr); BREAK_ON_FAIL(hr);
CheckDlgButton(m_hPage, chk_start_on_idle, (m_dwFlags & TASK_FLAG_START_ONLY_IF_IDLE));
CheckDlgButton(m_hPage, chk_stop_if_not_idle, (m_dwFlags & TASK_FLAG_KILL_ON_IDLE_END));
CheckDlgButton(m_hPage, chk_dont_start_if_on_batteries, (m_dwFlags & TASK_FLAG_DONT_START_IF_ON_BATTERIES));
CheckDlgButton(m_hPage, chk_kill_if_going_on_batteries, (m_dwFlags & TASK_FLAG_KILL_IF_GOING_ON_BATTERIES));
CheckDlgButton(m_hPage, chk_system_required, (m_dwFlags & TASK_FLAG_SYSTEM_REQUIRED));
CheckDlgButton(m_hPage, chk_delete_when_done, (m_dwFlags & TASK_FLAG_DELETE_WHEN_DONE));
//
// Not all machines have resume timers, which are used to support the
// TASK_FLAG_SYSTEM_REQUIRED flag. If the target machine doesn't
// have resume timers, hide the control.
//
if (!SupportsSystemRequired()) { RECT rcSysReq; RECT rcGroup; LONG cy;
//
// Get the distance in pixels from the top of the system required
// checkbox to the bottom of the group window.
//
// Reduce the height of the groupbox by this amount.
//
GetWindowRect(_hCtrl(chk_system_required), &rcSysReq); GetWindowRect(_hCtrl(grp_power_management), &rcGroup);
cy = rcGroup.bottom - rcSysReq.top + 1;
//
// Hide the checkbox and resize the group window
//
ShowWindow(_hCtrl(chk_system_required), SW_HIDE);
SetWindowPos(_hCtrl(grp_power_management), NULL, 0,0, rcGroup.right - rcGroup.left + 1, rcGroup.bottom - rcGroup.top - cy + 1, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); }
//
// Init idle controls
//
hr = m_pIJob->GetIdleWait(&m_wIdleWait, &m_wIdleDeadline);
CHECK_HRESULT(hr); BREAK_ON_FAIL(hr);
if (m_wIdleWait > MAX_IDLE_MINUTES) { m_wIdleWait = MAX_IDLE_MINUTES; }
if (m_wIdleDeadline > MAX_IDLE_MINUTES) { m_wIdleDeadline = MAX_IDLE_MINUTES; }
if (m_dwFlags & TASK_FLAG_START_ONLY_IF_IDLE) { Spin_Enable(m_hPage, spin_idle_min, m_wIdleWait); Spin_Enable(m_hPage, spin_idle_deadline, m_wIdleDeadline);
Spin_SetPos(m_hPage, spin_idle_min, m_wIdleWait); Spin_SetPos(m_hPage, spin_idle_deadline, m_wIdleDeadline); } else { m_wIdleWait = SCH_DEFAULT_IDLE_TIME; m_wIdleDeadline = SCH_DEFAULT_IDLE_DEADLINE; Spin_Disable(m_hPage, spin_idle_min); Spin_Disable(m_hPage, spin_idle_deadline); }
//
// Set max run time
//
hr = pIJob->GetMaxRunTime(&m_dwMaxRunTime);
CHECK_HRESULT(hr); BREAK_ON_FAIL(hr);
if (m_dwMaxRunTime != (DWORD)-1) { CheckDlgButton(m_hPage, chk_stop_after, BST_CHECKED);
//
// Convert to minutes from milliseconds. If the value is larger
// than the UI supports, reduce it.
//
m_dwMaxRunTime /= 60000;
if (m_dwMaxRunTime > (MAX_MAXRUNTIME_HOURS * 60 + 59)) { m_dwMaxRunTime = MAX_MAXRUNTIME_HOURS * 60 + 59; }
WORD wHours = (WORD) (m_dwMaxRunTime / 60); WORD wMins = (WORD) (m_dwMaxRunTime % 60); Spin_SetPos(m_hPage, spin_stop_after_hr, wHours); Spin_SetPos(m_hPage, spin_stop_after_min, wMins); } else { CheckDlgButton(m_hPage, chk_stop_after, BST_UNCHECKED);
Spin_Disable(m_hPage, spin_stop_after_hr); Spin_Disable(m_hPage, spin_stop_after_min); }
} while (0);
if (FAILED(hr)) { if (hr == E_OUTOFMEMORY) { _ErrorDialog(IERR_OUT_OF_MEMORY); } else { _ErrorDialog(IERR_SETTINGS_PAGE_INIT, hr); }
EnableWindow(Hwnd(), FALSE);
return FALSE; }
m_fDirty = FALSE;
return TRUE; }
LRESULT CSettingsPage::_OnCommand( int id, HWND hwndCtl, UINT codeNotify) { TRACE(CSettingsPage, _OnCommand);
switch (id) { case chk_stop_after: if (codeNotify != BN_CLICKED) { return TRUE; }
if (IsDlgButtonChecked(m_hPage, chk_stop_after) == BST_CHECKED) { Spin_Enable(m_hPage, spin_stop_after_hr, DEFAULT_MAXRUNTIME_HOURS);
Spin_Enable(m_hPage, spin_stop_after_min, DEFAULT_MAXRUNTIME_MINUTES); } else { Spin_Disable(m_hPage, spin_stop_after_hr); Spin_Disable(m_hPage, spin_stop_after_min); }
break;
case chk_start_on_idle: if (codeNotify != BN_CLICKED) { return TRUE; }
if (IsDlgButtonChecked(m_hPage, chk_start_on_idle) == BST_CHECKED) { Spin_Enable(m_hPage, spin_idle_min, m_wIdleWait); Spin_Enable(m_hPage, spin_idle_deadline, m_wIdleDeadline); } else { Spin_Disable(m_hPage, spin_idle_min); Spin_Disable(m_hPage, spin_idle_deadline); } break;
case txt_idle_min: case txt_idle_deadline: case txt_stop_after_hr: case txt_stop_after_min: if (codeNotify != EN_CHANGE) { return TRUE; } break;
// case spin_stop_after_hr:
// case spin_stop_after_min:
// break;
case chk_stop_if_not_idle: case chk_dont_start_if_on_batteries: case chk_kill_if_going_on_batteries: case chk_delete_when_done: case chk_system_required: if (codeNotify != BN_CLICKED) { return TRUE; }
break;
default: return FALSE; }
_EnableApplyButton();
return TRUE; }
//+--------------------------------------------------------------------------
//
// Member: CSettingsPage::_ReadIdleSettings
//
// Synopsis: Move the idle settings from the edit controls to the member
// variables, setting them on the job if they have been
// updated.
//
// History: 07-17-1997 DavidMun Created
//
//---------------------------------------------------------------------------
void CSettingsPage::_ReadIdleSettings() { ULONG ulSpinPos; WORD wIdleWait; WORD wIdleDeadline;
//
// If idle wait isn't turned on, the controls don't have meaningful
// values.
//
if (IsDlgButtonChecked(m_hPage, chk_start_on_idle) != BST_CHECKED) { return; }
ulSpinPos = Spin_GetPos(m_hPage, spin_idle_min);
if (HIWORD(ulSpinPos)) { wIdleWait = SCH_DEFAULT_IDLE_TIME; } else { wIdleWait = LOWORD(ulSpinPos); }
ulSpinPos = Spin_GetPos(m_hPage, spin_idle_deadline);
if (HIWORD(ulSpinPos)) { wIdleDeadline = SCH_DEFAULT_IDLE_DEADLINE; } else { wIdleDeadline = LOWORD(ulSpinPos); }
if (m_wIdleWait != wIdleWait || m_wIdleDeadline != wIdleDeadline) { HRESULT hr;
hr = m_pIJob->SetIdleWait(wIdleWait, wIdleDeadline);
CHECK_HRESULT(hr);
if (SUCCEEDED(hr)) { m_wIdleWait = wIdleWait; m_wIdleDeadline = wIdleDeadline; } } }
BOOL CSettingsPage::_PerformSanityChk(void) { ULONG ul;
if (IsDlgButtonChecked(m_hPage, chk_stop_after) == BST_CHECKED) { ul = GetDlgItemInt(Hwnd(), txt_stop_after_hr, NULL, FALSE);
if (!ul) { ul = GetDlgItemInt(Hwnd(), txt_stop_after_min, NULL, FALSE);
if (!ul) { Spin_SetPos(Hwnd(), spin_stop_after_min, 1); _ErrorDialog(IERR_MAXRUNTIME); return FALSE; } } }
return TRUE; }
LRESULT CSettingsPage::_OnPSNKillActive( LPARAM lParam) { TRACE(CSettingsPage, _OnPSNKillActive);
if (_PerformSanityChk() == FALSE) { // Returns TRUE to prevent the page from losing the activation
SetWindowLongPtr(m_hPage, DWLP_MSGRESULT, TRUE); return TRUE; }
//
// Make sure Schedule page is synchronized with IdleWait changes.
//
_ReadIdleSettings(); return CPropPage::_OnPSNKillActive(lParam); }
LRESULT CSettingsPage::_OnPSNSetActive(LPARAM lParam) { m_fInInit = TRUE;
//
// Make sure IdleWait is synchronized with Schedule page changes.
//
WORD wDummy;
HRESULT hr = m_pIJob->GetIdleWait(&m_wIdleWait, &wDummy);
if (SUCCEEDED(hr) && IsDlgButtonChecked(m_hPage, chk_start_on_idle) == BST_CHECKED) { Spin_SetPos(m_hPage, spin_idle_min, m_wIdleWait); } m_fInInit = FALSE;
return CPropPage::_OnPSNSetActive(lParam); }
LRESULT CSettingsPage::_OnApply(void) { TRACE(CSettingsPage, _OnApply); //DbxDisplay("CSettingsPage::_OnApply");
if (m_fDirty == FALSE) { return TRUE; }
if (_PerformSanityChk() == FALSE) { SetWindowLongPtr(Hwnd(), DWLP_MSGRESULT, FALSE); return FALSE; }
HRESULT hr = S_OK; ITask * pIJob = m_pIJob; DWORD dwFlags = 0;
do { if (IsDlgButtonChecked(m_hPage, chk_start_on_idle) == BST_CHECKED) { dwFlags |= TASK_FLAG_START_ONLY_IF_IDLE; }
if (IsDlgButtonChecked(m_hPage, chk_stop_if_not_idle) == BST_CHECKED) { dwFlags |= TASK_FLAG_KILL_ON_IDLE_END; }
if (IsDlgButtonChecked(m_hPage, chk_dont_start_if_on_batteries) == BST_CHECKED) { dwFlags |= TASK_FLAG_DONT_START_IF_ON_BATTERIES; }
if (IsDlgButtonChecked(m_hPage, chk_kill_if_going_on_batteries) == BST_CHECKED) { dwFlags |= TASK_FLAG_KILL_IF_GOING_ON_BATTERIES; }
if (IsDlgButtonChecked(m_hPage, chk_system_required) == BST_CHECKED) { dwFlags |= TASK_FLAG_SYSTEM_REQUIRED; }
if (IsDlgButtonChecked(m_hPage, chk_delete_when_done) == BST_CHECKED) { dwFlags |= TASK_FLAG_DELETE_WHEN_DONE; }
if ((m_dwFlags & TASK_FLAGS_IN_SETTINGS_PAGE) != dwFlags) { hr = pIJob->GetFlags(&m_dwFlags);
CHECK_HRESULT(hr); BREAK_ON_FAIL(hr);
dwFlags |= (m_dwFlags & ~TASK_FLAGS_IN_SETTINGS_PAGE);
hr = pIJob->SetFlags(dwFlags);
CHECK_HRESULT(hr); BREAK_ON_FAIL(hr);
m_dwFlags = dwFlags; }
_ReadIdleSettings();
DWORD dwMins = (DWORD)-1;
if (IsDlgButtonChecked(m_hPage, chk_stop_after) == BST_CHECKED) { ULONG ulSpinPos = Spin_GetPos(m_hPage, spin_stop_after_hr);
if (HIWORD(ulSpinPos)) { dwMins = DEFAULT_MAXRUNTIME_HOURS * 60; } else { dwMins = LOWORD(ulSpinPos) * 60; }
ulSpinPos = Spin_GetPos(m_hPage, spin_stop_after_min);
if (HIWORD(ulSpinPos)) { dwMins += DEFAULT_MAXRUNTIME_MINUTES; } else { dwMins += LOWORD(ulSpinPos); } }
Win4Assert(dwMins != 0);
if (m_dwMaxRunTime != dwMins) { // Max run time is in milliseconds
hr = pIJob->SetMaxRunTime( ((dwMins == (DWORD)-1) ? (DWORD)-1 : (dwMins * 60000)));
CHECK_HRESULT(hr); BREAK_ON_FAIL(hr);
m_dwMaxRunTime = dwMins; }
//
// reset dirty flag
//
m_fDirty = FALSE;
//
// If evrything went well see if the other pages are ready to
// save the job to storage.
//
if ((m_fPersistChanges == TRUE) && (PropSheet_QuerySiblings(GetParent(Hwnd()), QUERY_READY_TO_BE_SAVED, 0)) == 0) { //
// Save the job file to storage.
//
// First, fetch general page task, application dirty status flags.
// Default to not dirty if the general page isn't present.
//
#if !defined(_CHICAGO_)
BOOL fTaskApplicationChange = FALSE; PropSheet_QuerySiblings(GetParent(Hwnd()), QUERY_TASK_APPLICATION_DIRTY_STATUS, (LPARAM)&fTaskApplicationChange); BOOL fTaskAccountChange = FALSE; PropSheet_QuerySiblings(GetParent(Hwnd()), QUERY_TASK_ACCOUNT_INFO_DIRTY_STATUS, (LPARAM)&fTaskAccountChange); BOOL fSuppressAccountInfoRequest = FALSE; PropSheet_QuerySiblings(GetParent(Hwnd()), QUERY_SUPPRESS_ACCOUNT_INFO_REQUEST_FLAG, (LPARAM)&fSuppressAccountInfoRequest); #endif // !defined(_CHICAGO_)
hr = JFSaveJob(Hwnd(), pIJob, #if !defined(_CHICAGO_)
this->GetPlatformId() == VER_PLATFORM_WIN32_NT && this->IsTaskInTasksFolder(), fTaskAccountChange, fTaskApplicationChange, fSuppressAccountInfoRequest); #else
FALSE, FALSE, FALSE); #endif // !defined(_CHICAGO_)
CHECK_HRESULT(hr); BREAK_ON_FAIL(hr);
#if !defined(_CHICAGO_)
PropSheet_QuerySiblings(GetParent(Hwnd()), RESET_TASK_APPLICATION_DIRTY_STATUS, 0); PropSheet_QuerySiblings(GetParent(Hwnd()), RESET_TASK_ACCOUNT_INFO_DIRTY_STATUS, 0); PropSheet_QuerySiblings(GetParent(Hwnd()), RESET_SUPPRESS_ACCOUNT_INFO_REQUEST_FLAG, 0);
//
// Instruct the general page to refresh account information.
//
PropSheet_QuerySiblings(GetParent(Hwnd()), TASK_ACCOUNT_CHANGE_NOTIFY, 0); #endif // !defined(_CHICAGO_)
}
} while (0);
if (FAILED(hr)) { if (hr == E_OUTOFMEMORY) { _ErrorDialog(IERR_OUT_OF_MEMORY); } else if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) { _ErrorDialog(IERR_FILE_NOT_FOUND); } else if (hr == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED)) { _ErrorDialog(IERR_ACCESS_DENIED); } else { _ErrorDialog(IERR_INTERNAL_ERROR, hr); } }
return TRUE; }
LRESULT CSettingsPage::_OnPSMQuerySibling( WPARAM wParam, LPARAM lParam) { int iRet = 0;
switch (wParam) { case QUERY_READY_TO_BE_SAVED: iRet = (int)m_fDirty; break; }
SetWindowLongPtr(Hwnd(), DWLP_MSGRESULT, iRet);
return iRet; }
HRESULT GetSettingsPage( ITask * pIJob, LPTSTR ptszTaskPath, BOOL fPersistChanges, HPROPSHEETPAGE * phpage) { Win4Assert(pIJob != NULL); Win4Assert(phpage != NULL);
LPTSTR ptszPath = NULL; HRESULT hr = S_OK; WORD cTriggers = 0;
do { //
// Get the job name.
//
if (ptszTaskPath != NULL) { //
// Use passed-in path
//
ptszPath = ptszTaskPath; } else { //
// Obtain the job path from the interfaces.
//
hr = GetJobPath(pIJob, &ptszPath); BREAK_ON_FAIL(hr); }
hr = pIJob->GetTriggerCount(&cTriggers);
if (FAILED(hr)) { CHECK_HRESULT(hr); break; }
CSettingsPage * pPage = new CSettingsPage( pIJob, ptszPath, fPersistChanges);
if (pPage == NULL) { hr = E_OUTOFMEMORY; CHECK_HRESULT(hr); break; }
HPROPSHEETPAGE hpage = CreatePropertySheetPage(&pPage->m_psp);
if (hpage == NULL) { delete pPage;
hr = E_OUTOFMEMORY; CHECK_HRESULT(hr); break; }
*phpage = hpage;
} while (0);
//
// If we made a copy of pIJob's path string, free it.
//
if (ptszPath != ptszTaskPath) { delete [] ptszPath; }
return hr; }
HRESULT AddSettingsPage( PROPSHEETHEADER &psh, ITask * pIJob) { HPROPSHEETPAGE hpage = NULL;
HRESULT hr = GetSettingsPage(pIJob, NULL, TRUE, &hpage);
if (SUCCEEDED(hr)) { psh.phpage[psh.nPages++] = hpage; }
return hr; }
HRESULT AddSettingsPage( LPFNADDPROPSHEETPAGE lpfnAddPage, LPARAM cookie, ITask * pIJob) { HPROPSHEETPAGE hpage = NULL;
HRESULT hr = GetSettingsPage(pIJob, NULL, TRUE, &hpage);
CHECK_HRESULT(hr);
if (SUCCEEDED(hr)) { if (!lpfnAddPage(hpage, cookie)) { DestroyPropertySheetPage(hpage);
hr = E_FAIL; CHECK_HRESULT(hr); } }
return hr; }
|