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.
2218 lines
68 KiB
2218 lines
68 KiB
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright (c) 1996-2002 Microsoft Corporation
|
|
//
|
|
// Module Name:
|
|
// BasePage.cpp
|
|
//
|
|
// Abstract:
|
|
// Implementation of the CBasePropertyPage class.
|
|
//
|
|
// Author:
|
|
// David Potter (davidp) June 28, 1996
|
|
//
|
|
// Revision History:
|
|
// 1. Removed the calls to UpdateData from OnWizardNext and OnApply
|
|
// since OnKillActive, called before both these functions does a
|
|
// data update anyway.
|
|
//
|
|
// Notes:
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "stdafx.h"
|
|
#include "CluAdmX.h"
|
|
#include "ExtObj.h"
|
|
#include "BasePage.h"
|
|
#include "BasePage.inl"
|
|
#include "PropList.h"
|
|
#include "ExcOper.h"
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CBasePropertyPage property page
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
IMPLEMENT_DYNCREATE( CBasePropertyPage, CPropertyPage )
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Message Maps
|
|
|
|
BEGIN_MESSAGE_MAP( CBasePropertyPage, CPropertyPage )
|
|
//{{AFX_MSG_MAP(CBasePropertyPage)
|
|
ON_WM_CREATE()
|
|
ON_WM_DESTROY()
|
|
ON_WM_HELPINFO()
|
|
ON_WM_CONTEXTMENU()
|
|
ON_MESSAGE(WM_COMMANDHELP, OnCommandHelp)
|
|
//}}AFX_MSG_MAP
|
|
END_MESSAGE_MAP()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CBasePropertyPage::CBasePropertyPage
|
|
//
|
|
// Routine Description:
|
|
// Default constructor.
|
|
//
|
|
// Arguments:
|
|
// None.
|
|
//
|
|
// Return Value:
|
|
// None.
|
|
//
|
|
//--
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
CBasePropertyPage::CBasePropertyPage( void )
|
|
{
|
|
CommonConstruct();
|
|
|
|
} //*** CBasePropertyPage::CBasePropertyPage()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CBasePropertyPage::CBasePropertyPage
|
|
//
|
|
// Routine Description:
|
|
// Default constructor.
|
|
//
|
|
// Arguments:
|
|
// pdwHelpMap [IN] Control-to-help ID map.
|
|
// pdwWizardHelpMap [IN] Control-to-help ID map if this is a wizard page.
|
|
//
|
|
// Return Value:
|
|
// None.
|
|
//
|
|
//--
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
CBasePropertyPage::CBasePropertyPage(
|
|
IN const DWORD * pdwHelpMap,
|
|
IN const DWORD * pdwWizardHelpMap
|
|
)
|
|
: m_dlghelp( pdwHelpMap, 0 )
|
|
{
|
|
CommonConstruct();
|
|
m_pdwWizardHelpMap = pdwWizardHelpMap;
|
|
|
|
} //*** CBasePropertyPage::CBasePropertyPage()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CBasePropertyPage::CBasePropertyPage
|
|
//
|
|
// Routine Description:
|
|
// Default constructor.
|
|
//
|
|
// Arguments:
|
|
// idd [IN] Dialog template resource ID.
|
|
// pdwHelpMap [IN] Control-to-help ID map.
|
|
// pdwWizardHelpMap [IN] Control-to-help ID map if this is a wizard page.
|
|
// nIDCaption [IN] Caption string resource ID.
|
|
//
|
|
// Return Value:
|
|
// None.
|
|
//
|
|
//--
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
CBasePropertyPage::CBasePropertyPage(
|
|
IN UINT idd,
|
|
IN const DWORD * pdwHelpMap,
|
|
IN const DWORD * pdwWizardHelpMap,
|
|
IN UINT nIDCaption
|
|
)
|
|
: CPropertyPage( idd, nIDCaption )
|
|
, m_dlghelp( pdwHelpMap, idd )
|
|
{
|
|
CommonConstruct();
|
|
m_pdwWizardHelpMap = pdwWizardHelpMap;
|
|
|
|
} //*** CBasePropertyPage::CBasePropertyPage(UINT, UINT)
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CBasePropertyPage::CommonConstruct
|
|
//
|
|
// Routine Description:
|
|
// Common construction.
|
|
//
|
|
// Arguments:
|
|
// None.
|
|
//
|
|
// Return Value:
|
|
// None.
|
|
//
|
|
//--
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
void CBasePropertyPage::CommonConstruct( void )
|
|
{
|
|
//{{AFX_DATA_INIT(CBasePropertyPage)
|
|
//}}AFX_DATA_INIT
|
|
|
|
m_peo = NULL;
|
|
m_hpage = NULL;
|
|
m_bBackPressed = FALSE;
|
|
m_bSaved = FALSE;
|
|
|
|
m_iddPropertyPage = NULL;
|
|
m_iddWizardPage = NULL;
|
|
m_idsCaption = NULL;
|
|
|
|
m_pdwWizardHelpMap = NULL;
|
|
|
|
m_bDoDetach = FALSE;
|
|
|
|
} //*** CBasePropertyPage::CommonConstruct()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CBasePropertyPage::HrInit
|
|
//
|
|
// Routine Description:
|
|
// Initialize the page.
|
|
//
|
|
// Arguments:
|
|
// peo [IN OUT] Pointer to the extension object.
|
|
//
|
|
// Return Value:
|
|
// S_OK Page initialized successfully.
|
|
// hr Error initializing the page.
|
|
//
|
|
//--
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
HRESULT CBasePropertyPage::HrInit( IN OUT CExtObject * peo )
|
|
{
|
|
ASSERT( peo != NULL );
|
|
|
|
AFX_MANAGE_STATE( AfxGetStaticModuleState() );
|
|
|
|
HRESULT hr = S_OK;
|
|
CWaitCursor wc;
|
|
|
|
m_peo = peo;
|
|
|
|
// Change the help map if this is a wizard page.
|
|
if ( Peo()->BWizard() )
|
|
{
|
|
m_dlghelp.SetMap( m_pdwWizardHelpMap );
|
|
} // if: on wizard page
|
|
|
|
// Don't display a help button.
|
|
m_psp.dwFlags &= ~PSP_HASHELP;
|
|
|
|
// Construct the property page.
|
|
if ( Peo()->BWizard() )
|
|
{
|
|
ASSERT( IddWizardPage() != NULL );
|
|
Construct( IddWizardPage(), IdsCaption() );
|
|
m_dlghelp.SetHelpMask( IddWizardPage() );
|
|
} // if: adding page to wizard
|
|
else
|
|
{
|
|
ASSERT( IddPropertyPage() != NULL );
|
|
Construct( IddPropertyPage(), IdsCaption() );
|
|
m_dlghelp.SetHelpMask( IddPropertyPage() );
|
|
} // else: adding page to property sheet
|
|
|
|
// Read the properties private to this resource and parse them.
|
|
{
|
|
DWORD sc;
|
|
CClusPropList cpl;
|
|
|
|
ASSERT( Peo() != NULL );
|
|
ASSERT( Peo()->PrdResData() != NULL );
|
|
ASSERT( Peo()->PrdResData()->m_hresource != NULL );
|
|
|
|
// Get the read-write private properties.
|
|
sc = cpl.ScGetResourceProperties(
|
|
Peo()->PrdResData()->m_hresource,
|
|
CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES
|
|
);
|
|
|
|
// Parse the properties.
|
|
if ( sc == ERROR_SUCCESS )
|
|
{
|
|
// Parse the properties.
|
|
try
|
|
{
|
|
sc = ScParseProperties( cpl );
|
|
} // try
|
|
catch ( CMemoryException * pme )
|
|
{
|
|
sc = ERROR_NOT_ENOUGH_MEMORY;
|
|
pme->Delete();
|
|
} // catch: CMemoryException
|
|
} // if: Properties read successfully.
|
|
|
|
if ( sc != ERROR_SUCCESS )
|
|
{
|
|
CNTException nte( sc, IDS_ERROR_GETTING_PROPERTIES, NULL, NULL, FALSE );
|
|
nte.ReportError();
|
|
hr = HRESULT_FROM_WIN32( sc );
|
|
goto Cleanup;
|
|
} // if: Error getting or parsing properties.
|
|
|
|
// Get the read-only private properties.
|
|
sc = cpl.ScGetResourceProperties(
|
|
Peo()->PrdResData()->m_hresource,
|
|
CLUSCTL_RESOURCE_GET_RO_PRIVATE_PROPERTIES
|
|
);
|
|
|
|
// Parse the properties.
|
|
if ( sc == ERROR_SUCCESS )
|
|
{
|
|
// Parse the properties.
|
|
try
|
|
{
|
|
sc = ScParseProperties( cpl );
|
|
} // try
|
|
catch ( CMemoryException * pme )
|
|
{
|
|
sc = ERROR_NOT_ENOUGH_MEMORY;
|
|
pme->Delete();
|
|
} // catch: CMemoryException
|
|
} // if: Properties read successfully.
|
|
|
|
if ( sc != ERROR_SUCCESS )
|
|
{
|
|
CNTException nte( sc, IDS_ERROR_GETTING_PROPERTIES, NULL, NULL, FALSE );
|
|
nte.ReportError();
|
|
hr = HRESULT_FROM_WIN32( sc );
|
|
goto Cleanup;
|
|
} // if: Error getting or parsing properties.
|
|
} // Read the properties private to this resource and parse them.
|
|
|
|
Cleanup:
|
|
return hr;
|
|
|
|
} //*** CBasePropertyPage::HrInit()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CBasePropertyPage::ScParseProperties
|
|
//
|
|
// Routine Description:
|
|
// Parse the properties of the resource. This is in a separate function
|
|
// from HrInit so that the optimizer can do a better job.
|
|
//
|
|
// Arguments:
|
|
// rcpl [IN] Cluster property list to parse.
|
|
//
|
|
// Return Value:
|
|
// ERROR_SUCCESS Properties were parsed successfully.
|
|
// Any error returns from ScParseUnknownProperty().
|
|
//
|
|
// Exceptions Thrown:
|
|
// Any exceptions from CString::operator=().
|
|
//
|
|
//--
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
DWORD CBasePropertyPage::ScParseProperties( IN CClusPropList & rcpl )
|
|
{
|
|
DWORD sc;
|
|
DWORD cprop;
|
|
const CObjectProperty * pprop;
|
|
|
|
ASSERT( rcpl.PbPropList() != NULL );
|
|
|
|
sc = rcpl.ScMoveToFirstProperty();
|
|
while ( sc == ERROR_SUCCESS )
|
|
{
|
|
//
|
|
// Parse known properties.
|
|
//
|
|
for ( pprop = Pprops(), cprop = Cprops() ; cprop > 0 ; pprop++, cprop-- )
|
|
{
|
|
if ( ClRtlStrNICmp( rcpl.PszCurrentPropertyName(), pprop->m_pwszName, rcpl.CbhCurrentPropertyName().pValue->cbLength / sizeof( WCHAR ) ) == 0 )
|
|
{
|
|
ASSERT( rcpl.CpfCurrentValueFormat() == pprop->m_propFormat );
|
|
switch ( pprop->m_propFormat )
|
|
{
|
|
case CLUSPROP_FORMAT_SZ:
|
|
case CLUSPROP_FORMAT_EXPAND_SZ:
|
|
ASSERT( ( rcpl.CbCurrentValueLength() == (wcslen( rcpl.CbhCurrentValue().pStringValue->sz ) + 1) * sizeof( WCHAR ) )
|
|
|| ( ( rcpl.CbCurrentValueLength() == 0 )
|
|
&& ( rcpl.CbhCurrentValue().pStringValue->sz[ 0 ] == L'\0' )
|
|
)
|
|
);
|
|
*pprop->m_value.pstr = rcpl.CbhCurrentValue().pStringValue->sz;
|
|
*pprop->m_valuePrev.pstr = rcpl.CbhCurrentValue().pStringValue->sz;
|
|
break;
|
|
case CLUSPROP_FORMAT_DWORD:
|
|
case CLUSPROP_FORMAT_LONG:
|
|
ASSERT( rcpl.CbCurrentValueLength() == sizeof( DWORD ) );
|
|
*pprop->m_value.pdw = rcpl.CbhCurrentValue().pDwordValue->dw;
|
|
*pprop->m_valuePrev.pdw = rcpl.CbhCurrentValue().pDwordValue->dw;
|
|
break;
|
|
case CLUSPROP_FORMAT_BINARY:
|
|
case CLUSPROP_FORMAT_MULTI_SZ:
|
|
delete [] *pprop->m_value.ppb;
|
|
*pprop->m_value.ppb = new BYTE[ rcpl.CbhCurrentValue().pBinaryValue->cbLength ];
|
|
if ( *pprop->m_value.ppb == NULL )
|
|
{
|
|
AfxThrowMemoryException();
|
|
} // if:
|
|
|
|
CopyMemory( *pprop->m_value.ppb, rcpl.CbhCurrentValue().pBinaryValue->rgb, rcpl.CbhCurrentValue().pBinaryValue->cbLength );
|
|
*pprop->m_value.pcb = rcpl.CbhCurrentValue().pBinaryValue->cbLength;
|
|
|
|
delete [] *pprop->m_valuePrev.ppb;
|
|
*pprop->m_valuePrev.ppb = new BYTE[ rcpl.CbhCurrentValue().pBinaryValue->cbLength ];
|
|
if ( *pprop->m_valuePrev.ppb == NULL )
|
|
{
|
|
AfxThrowMemoryException();
|
|
} // if:
|
|
|
|
CopyMemory( *pprop->m_valuePrev.ppb, rcpl.CbhCurrentValue().pBinaryValue->rgb, rcpl.CbhCurrentValue().pBinaryValue->cbLength );
|
|
*pprop->m_valuePrev.pcb = rcpl.CbhCurrentValue().pBinaryValue->cbLength;
|
|
break;
|
|
default:
|
|
ASSERT( 0 ); // don't know how to deal with this type
|
|
} // switch: property format
|
|
|
|
// Exit the loop since we found the parameter.
|
|
break;
|
|
} // if: found a match
|
|
} // for: each property that we know about
|
|
|
|
//
|
|
// If the property wasn't known, ask the derived class to parse it.
|
|
//
|
|
if ( cprop == 0 )
|
|
{
|
|
sc = ScParseUnknownProperty(
|
|
rcpl.CbhCurrentPropertyName().pName->sz,
|
|
rcpl.CbhCurrentValue(),
|
|
static_cast< DWORD >( rcpl.RPvlPropertyValue().CbDataLeft() )
|
|
);
|
|
if ( sc != ERROR_SUCCESS )
|
|
{
|
|
return sc;
|
|
} // if: error parsing the unknown property
|
|
} // if: property not parsed
|
|
|
|
//
|
|
// Advance the buffer pointer past the value in the value list.
|
|
//
|
|
sc = rcpl.ScMoveToNextProperty();
|
|
} // while: more properties to parse
|
|
|
|
//
|
|
// If we reached the end of the properties, fix the return code.
|
|
//
|
|
if ( sc == ERROR_NO_MORE_ITEMS )
|
|
{
|
|
sc = ERROR_SUCCESS;
|
|
} // if: ended loop after parsing all properties
|
|
|
|
return sc;
|
|
|
|
} //*** CBasePropertyPage::ScParseProperties()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CBasePropertyPage::OnCreate
|
|
//
|
|
// Routine Description:
|
|
// Handler for the WM_CREATE message.
|
|
//
|
|
// Arguments:
|
|
// lpCreateStruct [IN OUT] Window create structure.
|
|
//
|
|
// Return Value:
|
|
// -1 Error.
|
|
// 0 Success.
|
|
//
|
|
//--
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
int CBasePropertyPage::OnCreate( LPCREATESTRUCT lpCreateStruct )
|
|
{
|
|
AFX_MANAGE_STATE( AfxGetStaticModuleState() );
|
|
|
|
// Attach the window to the property page structure.
|
|
// This has been done once already in the main application, since the
|
|
// main application owns the property sheet. It needs to be done here
|
|
// so that the window handle can be found in the DLL's handle map.
|
|
if ( FromHandlePermanent( m_hWnd ) == NULL ) // is the window handle already in the handle map
|
|
{
|
|
HWND hWnd = m_hWnd;
|
|
m_hWnd = NULL;
|
|
Attach( hWnd );
|
|
m_bDoDetach = TRUE;
|
|
} // if: is the window handle in the handle map
|
|
|
|
return CPropertyPage::OnCreate( lpCreateStruct );
|
|
|
|
} //*** CBasePropertyPage::OnCreate()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CBasePropertyPage::OnDestroy
|
|
//
|
|
// Routine Description:
|
|
// Handler for the WM_DESTROY message.
|
|
//
|
|
// Arguments:
|
|
// None.
|
|
//
|
|
// Return Value:
|
|
// None.
|
|
//
|
|
//--
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
void CBasePropertyPage::OnDestroy( void )
|
|
{
|
|
AFX_MANAGE_STATE( AfxGetStaticModuleState() );
|
|
|
|
// Detach the window from the property page structure.
|
|
// This will be done again by the main application, since it owns the
|
|
// property sheet. It needs to be done here so that the window handle
|
|
// can be removed from the DLL's handle map.
|
|
if ( m_bDoDetach )
|
|
{
|
|
if ( m_hWnd != NULL )
|
|
{
|
|
HWND hWnd = m_hWnd;
|
|
|
|
Detach();
|
|
m_hWnd = hWnd;
|
|
} // if: do we have a window handle?
|
|
} // if: do we need to balance the attach we did with a detach?
|
|
|
|
CPropertyPage::OnDestroy();
|
|
|
|
} //*** CBasePropertyPage::OnDestroy()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CBasePropertyPage::DoDataExchange
|
|
//
|
|
// Routine Description:
|
|
// Do data exchange between the dialog and the class.
|
|
//
|
|
// Arguments:
|
|
// pDX [IN OUT] Data exchange object
|
|
//
|
|
// Return Value:
|
|
// None.
|
|
//
|
|
//--
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
void CBasePropertyPage::DoDataExchange( CDataExchange * pDX )
|
|
{
|
|
if ( ! pDX->m_bSaveAndValidate || !BSaved() )
|
|
{
|
|
AFX_MANAGE_STATE( AfxGetStaticModuleState() );
|
|
|
|
//{{AFX_DATA_MAP(CBasePropertyPage)
|
|
// NOTE: the ClassWizard will add DDX and DDV calls here
|
|
//}}AFX_DATA_MAP
|
|
DDX_Control( pDX, IDC_PP_ICON, m_staticIcon );
|
|
DDX_Control( pDX, IDC_PP_TITLE, m_staticTitle );
|
|
|
|
if ( pDX->m_bSaveAndValidate )
|
|
{
|
|
if ( ! BBackPressed() )
|
|
{
|
|
CWaitCursor wc;
|
|
|
|
// Validate the data.
|
|
if ( ! BSetPrivateProps( TRUE /*bValidateOnly*/ ) )
|
|
{
|
|
pDX->Fail();
|
|
} // if: error setting private properties
|
|
} // if: Back button not pressed
|
|
} // if: saving data from dialog
|
|
else
|
|
{
|
|
// Set the title.
|
|
DDX_Text( pDX, IDC_PP_TITLE, m_strTitle );
|
|
} // if: not saving data
|
|
} // if: not saving or haven't saved yet
|
|
|
|
CPropertyPage::DoDataExchange( pDX );
|
|
|
|
} //*** CBasePropertyPage::DoDataExchange()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CBasePropertyPage::OnInitDialog
|
|
//
|
|
// Routine Description:
|
|
// Handler for the WM_INITDIALOG message.
|
|
//
|
|
// Arguments:
|
|
// None.
|
|
//
|
|
// Return Value:
|
|
// TRUE We need the focus to be set for us.
|
|
// FALSE We already set the focus to the proper control.
|
|
//
|
|
//--
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
BOOL CBasePropertyPage::OnInitDialog( void )
|
|
{
|
|
ASSERT( Peo() != NULL );
|
|
|
|
AFX_MANAGE_STATE( AfxGetStaticModuleState() );
|
|
|
|
// Set the title string.
|
|
m_strTitle = Peo()->RrdResData().m_strName;
|
|
|
|
// Call the base class method.
|
|
CPropertyPage::OnInitDialog();
|
|
|
|
// Display an icon for the object.
|
|
if ( Peo()->Hicon() != NULL )
|
|
{
|
|
m_staticIcon.SetIcon( Peo()->Hicon() );
|
|
} // if: icon was specified
|
|
|
|
return TRUE; // return TRUE unless you set the focus to a control
|
|
// EXCEPTION: OCX Property Pages should return FALSE
|
|
|
|
} //*** CBasePropertyPage::OnInitDialog()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CBasePropertyPage::OnSetActive
|
|
//
|
|
// Routine Description:
|
|
// Handler for the PSN_SETACTIVE message.
|
|
//
|
|
// Arguments:
|
|
// None.
|
|
//
|
|
// Return Value:
|
|
// TRUE Page successfully initialized.
|
|
// FALSE Page not initialized.
|
|
//
|
|
//--
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
BOOL CBasePropertyPage::OnSetActive( void )
|
|
{
|
|
HRESULT hr;
|
|
|
|
AFX_MANAGE_STATE( AfxGetStaticModuleState() );
|
|
|
|
// Reread the data.
|
|
hr = Peo()->HrGetObjectInfo();
|
|
if ( hr != NOERROR )
|
|
{
|
|
return FALSE;
|
|
} // if: error getting object info
|
|
|
|
// Set the title string.
|
|
m_strTitle = Peo()->RrdResData().m_strName;
|
|
|
|
m_bBackPressed = FALSE;
|
|
m_bSaved = FALSE;
|
|
return CPropertyPage::OnSetActive();
|
|
|
|
} //*** CBasePropertyPage::OnSetActive()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CBasePropertyPage::OnApply
|
|
//
|
|
// Routine Description:
|
|
// Handler for the PSM_APPLY message.
|
|
//
|
|
// Arguments:
|
|
// None.
|
|
//
|
|
// Return Value:
|
|
// TRUE Page successfully applied.
|
|
// FALSE Error applying page.
|
|
//
|
|
//--
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
BOOL CBasePropertyPage::OnApply( void )
|
|
{
|
|
ASSERT( ! BWizard() );
|
|
|
|
AFX_MANAGE_STATE( AfxGetStaticModuleState() );
|
|
|
|
CWaitCursor wc;
|
|
|
|
if ( ! BApplyChanges() )
|
|
{
|
|
return FALSE;
|
|
} // if: error applying changes
|
|
|
|
return CPropertyPage::OnApply();
|
|
|
|
} //*** CBasePropertyPage::OnApply()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CBasePropertyPage::OnWizardBack
|
|
//
|
|
// Routine Description:
|
|
// Handler for the PSN_WIZBACK message.
|
|
//
|
|
// Arguments:
|
|
// None.
|
|
//
|
|
// Return Value:
|
|
// -1 Don't change the page.
|
|
// 0 Change the page.
|
|
//
|
|
//--
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
LRESULT CBasePropertyPage::OnWizardBack( void )
|
|
{
|
|
LRESULT lResult;
|
|
|
|
ASSERT( BWizard() );
|
|
|
|
AFX_MANAGE_STATE( AfxGetStaticModuleState() );
|
|
|
|
lResult = CPropertyPage::OnWizardBack();
|
|
if ( lResult != -1 )
|
|
{
|
|
m_bBackPressed = TRUE;
|
|
} // if: back processing performed successfully
|
|
|
|
return lResult;
|
|
|
|
} //*** CBasePropertyPage::OnWizardBack()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CBasePropertyPage::OnWizardNext
|
|
//
|
|
// Routine Description:
|
|
// Handler for the PSN_WIZNEXT message.
|
|
//
|
|
// Arguments:
|
|
// None.
|
|
//
|
|
// Return Value:
|
|
// -1 Don't change the page.
|
|
// 0 Change the page.
|
|
//
|
|
//--
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
LRESULT CBasePropertyPage::OnWizardNext( void )
|
|
{
|
|
ASSERT( BWizard() );
|
|
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
CWaitCursor _wc;
|
|
|
|
// Update the data in the class from the page.
|
|
// This necessary because, while OnKillActive() will call UpdateData(),
|
|
// it is called after this method is called, and we need to be sure that
|
|
// data has been saved before we apply them.
|
|
if ( ! UpdateData( TRUE /*bSaveAndValidate*/ ) )
|
|
{
|
|
return -1;
|
|
} // if: error updating data
|
|
|
|
// Save the data in the sheet.
|
|
if ( ! BApplyChanges() )
|
|
{
|
|
return -1;
|
|
} // if: error applying changes
|
|
|
|
// Create the object.
|
|
|
|
return CPropertyPage::OnWizardNext();
|
|
|
|
} //*** CBasePropertyPage::OnWizardNext()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CBasePropertyPage::OnWizardFinish
|
|
//
|
|
// Routine Description:
|
|
// Handler for the PSN_WIZFINISH message.
|
|
//
|
|
// Arguments:
|
|
// None.
|
|
//
|
|
// Return Value:
|
|
// FALSE Don't change the page.
|
|
// TRUE Change the page.
|
|
//
|
|
//--
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
BOOL CBasePropertyPage::OnWizardFinish( void )
|
|
{
|
|
ASSERT( BWizard() );
|
|
|
|
AFX_MANAGE_STATE( AfxGetStaticModuleState() );
|
|
|
|
CWaitCursor wc;
|
|
|
|
// BUG! There should be no need to call UpdateData in this function.
|
|
// See BUG: Finish Button Fails Data Transfer from Page to Variables
|
|
// MSDN Article ID: Q150349
|
|
|
|
// Update the data in the class from the page.
|
|
if ( ! UpdateData( TRUE /*bSaveAndValidate*/ ) )
|
|
{
|
|
return FALSE;
|
|
} // if: error updating data
|
|
|
|
// Save the data in the sheet.
|
|
if ( ! BApplyChanges() )
|
|
{
|
|
return FALSE;
|
|
} // if: error applying changes
|
|
|
|
return CPropertyPage::OnWizardFinish();
|
|
|
|
} //*** CBasePropertyPage::OnWizardFinish()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CBasePropertyPage::OnChangeCtrl
|
|
//
|
|
// Routine Description:
|
|
// Handler for the messages sent when a control is changed. This
|
|
// method can be specified in a message map if all that needs to be
|
|
// done is enable the Apply button.
|
|
//
|
|
// Arguments:
|
|
// None.
|
|
//
|
|
// Return Value:
|
|
// None.
|
|
//
|
|
//--
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
void CBasePropertyPage::OnChangeCtrl( void )
|
|
{
|
|
AFX_MANAGE_STATE( AfxGetStaticModuleState() );
|
|
|
|
SetModified( TRUE );
|
|
|
|
} //*** CBasePropertyPage::OnChangeCtrl()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CBasePropertyPage::EnableNext
|
|
//
|
|
// Routine Description:
|
|
// Enables or disables the NEXT or FINISH button.
|
|
//
|
|
// Arguments:
|
|
// bEnable [IN] TRUE = enable the button, FALSE = disable the button.
|
|
//
|
|
// Return Value:
|
|
// None.
|
|
//
|
|
//--
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
void CBasePropertyPage::EnableNext( IN BOOL bEnable /*TRUE*/ )
|
|
{
|
|
ASSERT( BWizard() );
|
|
ASSERT( PiWizardCallback() );
|
|
|
|
AFX_MANAGE_STATE( AfxGetStaticModuleState() );
|
|
|
|
PiWizardCallback()->EnableNext( (LONG *) Hpage(), bEnable );
|
|
|
|
} //*** CBasePropertyPage::EnableNext()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CBasePropertyPage::BApplyChanges
|
|
//
|
|
// Routine Description:
|
|
// Apply changes made on the page.
|
|
//
|
|
// Arguments:
|
|
// None.
|
|
//
|
|
// Return Value:
|
|
// TRUE Page successfully applied.
|
|
// FALSE Error applying page.
|
|
//
|
|
//--
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
BOOL CBasePropertyPage::BApplyChanges( void )
|
|
{
|
|
AFX_MANAGE_STATE( AfxGetStaticModuleState() );
|
|
|
|
BOOL bSuccess;
|
|
CWaitCursor wc;
|
|
|
|
// Make sure required dependencies have been set.
|
|
if ( ! BSetPrivateProps() )
|
|
{
|
|
bSuccess = FALSE;
|
|
} // if: all required dependencies are not present
|
|
else
|
|
{
|
|
// Save data.
|
|
bSuccess = BRequiredDependenciesPresent();
|
|
} // else: all required dependencies are present
|
|
|
|
return bSuccess;
|
|
|
|
} //*** CBasePropertyPage::BApplyChanges()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CBasePropertyPage::BBuildPropList
|
|
//
|
|
// Routine Description:
|
|
// Build the property list.
|
|
//
|
|
// Arguments:
|
|
// rcpl [IN OUT] Cluster property list.
|
|
// bNoNewProps [IN] TRUE = exclude properties marked with opfNew.
|
|
//
|
|
// Return Value:
|
|
// TRUE Property list built successfully.
|
|
// FALSE Error building property list.
|
|
//
|
|
// Exceptions Thrown:
|
|
// Any exceptions thrown by CClusPropList::ScAddProp().
|
|
//
|
|
//--
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
BOOL CBasePropertyPage::BBuildPropList(
|
|
IN OUT CClusPropList & rcpl,
|
|
IN BOOL bNoNewProps // = FALSE
|
|
)
|
|
{
|
|
BOOL bNewPropsFound = FALSE;
|
|
DWORD cprop;
|
|
const CObjectProperty * pprop;
|
|
|
|
for ( pprop = Pprops(), cprop = Cprops() ; cprop > 0 ; pprop++, cprop-- )
|
|
{
|
|
if ( bNoNewProps && ( pprop->m_fFlags & CObjectProperty::opfNew ) )
|
|
{
|
|
bNewPropsFound = TRUE;
|
|
continue;
|
|
} // if: no new props allowed and this is a new property
|
|
|
|
switch ( pprop->m_propFormat )
|
|
{
|
|
case CLUSPROP_FORMAT_SZ:
|
|
rcpl.ScAddProp(
|
|
pprop->m_pwszName,
|
|
*pprop->m_value.pstr,
|
|
*pprop->m_valuePrev.pstr
|
|
);
|
|
break;
|
|
case CLUSPROP_FORMAT_EXPAND_SZ:
|
|
rcpl.ScAddExpandSzProp(
|
|
pprop->m_pwszName,
|
|
*pprop->m_value.pstr,
|
|
*pprop->m_valuePrev.pstr
|
|
);
|
|
break;
|
|
case CLUSPROP_FORMAT_DWORD:
|
|
rcpl.ScAddProp(
|
|
pprop->m_pwszName,
|
|
*pprop->m_value.pdw,
|
|
*pprop->m_valuePrev.pdw
|
|
);
|
|
break;
|
|
case CLUSPROP_FORMAT_LONG:
|
|
rcpl.ScAddProp(
|
|
pprop->m_pwszName,
|
|
*pprop->m_value.pl,
|
|
*pprop->m_valuePrev.pl
|
|
);
|
|
break;
|
|
case CLUSPROP_FORMAT_BINARY:
|
|
case CLUSPROP_FORMAT_MULTI_SZ:
|
|
rcpl.ScAddProp(
|
|
pprop->m_pwszName,
|
|
*pprop->m_value.ppb,
|
|
*pprop->m_value.pcb,
|
|
*pprop->m_valuePrev.ppb,
|
|
*pprop->m_valuePrev.pcb
|
|
);
|
|
break;
|
|
default:
|
|
ASSERT( 0 ); // don't know how to deal with this type
|
|
return FALSE;
|
|
} // switch: property format
|
|
} // for: each property
|
|
|
|
return ( ! bNoNewProps || bNewPropsFound );
|
|
|
|
} //*** CBasePropertyPage::BBuildPropList()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CBasePropertyPage::BSetPrivateProps
|
|
//
|
|
// Routine Description:
|
|
// Set the private properties for this object.
|
|
//
|
|
// Arguments:
|
|
// bValidateOnly [IN] TRUE = only validate the data.
|
|
// bNoNewProps [IN] TRUE = exclude properties marked with opfNew.
|
|
//
|
|
// Return Value:
|
|
// ERROR_SUCCESS The operation was completed successfully.
|
|
// !0 Failure.
|
|
//
|
|
//--
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
BOOL CBasePropertyPage::BSetPrivateProps(
|
|
IN BOOL bValidateOnly, // = FALSE
|
|
IN BOOL bNoNewProps // = FALSE
|
|
)
|
|
{
|
|
BOOL bSuccess = TRUE;
|
|
CClusPropList cpl(BWizard() /*bAlwaysAddProp*/);
|
|
|
|
ASSERT( Peo() != NULL );
|
|
ASSERT( Peo()->PrdResData() );
|
|
ASSERT( Peo()->PrdResData()->m_hresource );
|
|
|
|
// Build the property list.
|
|
try
|
|
{
|
|
bSuccess = BBuildPropList( cpl, bNoNewProps );
|
|
} // try
|
|
catch ( CException * pe )
|
|
{
|
|
pe->ReportError();
|
|
pe->Delete();
|
|
bSuccess = FALSE;
|
|
} // catch: CException
|
|
|
|
// Set the data.
|
|
if ( bSuccess )
|
|
{
|
|
if ( ( cpl.PbPropList() != NULL ) && ( cpl.CbPropList() > 0 ) )
|
|
{
|
|
DWORD sc;
|
|
DWORD dwControlCode;
|
|
DWORD cbProps;
|
|
|
|
// Determine which control code to use.
|
|
if ( bValidateOnly )
|
|
{
|
|
dwControlCode = CLUSCTL_RESOURCE_VALIDATE_PRIVATE_PROPERTIES;
|
|
} // if: only validating
|
|
else
|
|
{
|
|
dwControlCode = CLUSCTL_RESOURCE_SET_PRIVATE_PROPERTIES;
|
|
} // else: not just validating
|
|
|
|
// Set private properties.
|
|
sc = ClusterResourceControl(
|
|
Peo()->PrdResData()->m_hresource,
|
|
NULL, // hNode
|
|
dwControlCode,
|
|
cpl.PbPropList(),
|
|
static_cast< DWORD >( cpl.CbPropList() ),
|
|
NULL, // lpOutBuffer
|
|
0, // nOutBufferSize
|
|
&cbProps
|
|
);
|
|
if ( sc != ERROR_SUCCESS )
|
|
{
|
|
if ( sc == ERROR_INVALID_PARAMETER )
|
|
{
|
|
if ( ! bNoNewProps )
|
|
{
|
|
bSuccess = BSetPrivateProps( bValidateOnly, TRUE /*bNoNewProps*/ );
|
|
} // if: new props are allowed
|
|
else
|
|
{
|
|
bSuccess = FALSE;
|
|
} // else: new props are not allowed
|
|
} // if: invalid parameter error occurred
|
|
else
|
|
{
|
|
bSuccess = FALSE;
|
|
} // else: some other error occurred
|
|
} // if: error setting/validating data
|
|
|
|
//
|
|
// If an error occurred, display an error message.
|
|
//
|
|
if ( ! bSuccess )
|
|
{
|
|
DisplaySetPropsError( sc, bValidateOnly ? IDS_ERROR_VALIDATING_PROPERTIES : IDS_ERROR_SETTING_PROPERTIES );
|
|
if ( sc == ERROR_RESOURCE_PROPERTIES_STORED )
|
|
{
|
|
bSuccess = TRUE;
|
|
} // if: properties only stored
|
|
} // if: error occurred
|
|
} // if: there is data to set
|
|
} // if: no errors building the property list
|
|
|
|
// Save data locally.
|
|
if ( ! bValidateOnly && bSuccess )
|
|
{
|
|
// Save new values as previous values.
|
|
try
|
|
{
|
|
DWORD cprop;
|
|
const CObjectProperty * pprop;
|
|
|
|
for ( pprop = Pprops(), cprop = Cprops() ; cprop > 0 ; pprop++, cprop-- )
|
|
{
|
|
switch ( pprop->m_propFormat )
|
|
{
|
|
case CLUSPROP_FORMAT_SZ:
|
|
case CLUSPROP_FORMAT_EXPAND_SZ:
|
|
ASSERT( pprop->m_value.pstr != NULL );
|
|
ASSERT( pprop->m_valuePrev.pstr != NULL );
|
|
*pprop->m_valuePrev.pstr = *pprop->m_value.pstr;
|
|
break;
|
|
case CLUSPROP_FORMAT_DWORD:
|
|
case CLUSPROP_FORMAT_LONG:
|
|
ASSERT( pprop->m_value.pdw != NULL );
|
|
ASSERT( pprop->m_valuePrev.pdw != NULL );
|
|
*pprop->m_valuePrev.pdw = *pprop->m_value.pdw;
|
|
break;
|
|
case CLUSPROP_FORMAT_BINARY:
|
|
case CLUSPROP_FORMAT_MULTI_SZ:
|
|
ASSERT( pprop->m_value.ppb != NULL );
|
|
ASSERT( *pprop->m_value.ppb != NULL );
|
|
ASSERT( pprop->m_value.pcb != NULL );
|
|
ASSERT( pprop->m_valuePrev.ppb != NULL );
|
|
ASSERT( *pprop->m_valuePrev.ppb != NULL );
|
|
ASSERT( pprop->m_valuePrev.pcb != NULL );
|
|
delete [] *pprop->m_valuePrev.ppb;
|
|
*pprop->m_valuePrev.ppb = new BYTE[ *pprop->m_value.pcb ];
|
|
if ( *pprop->m_valuePrev.ppb == NULL )
|
|
{
|
|
AfxThrowMemoryException();
|
|
} // if: error allocating memory
|
|
CopyMemory( *pprop->m_valuePrev.ppb, *pprop->m_value.ppb, *pprop->m_value.pcb );
|
|
*pprop->m_valuePrev.pcb = *pprop->m_value.pcb;
|
|
break;
|
|
default:
|
|
ASSERT( 0 ); // don't know how to deal with this type
|
|
} // switch: property format
|
|
} // for: each property
|
|
} // try
|
|
catch ( CException * pe )
|
|
{
|
|
pe->ReportError();
|
|
pe->Delete();
|
|
bSuccess = FALSE;
|
|
} // catch: CException
|
|
} // if: not just validating and successful so far
|
|
|
|
//
|
|
// Indicate we successfully saved the properties.
|
|
//
|
|
if ( ! bValidateOnly && bSuccess )
|
|
{
|
|
m_bSaved = TRUE;
|
|
} // if: successfully saved data
|
|
|
|
return bSuccess;
|
|
|
|
} //*** CBasePropertyPage::BSetPrivateProps()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CBasePropertyPage::DisplaySetPropsError
|
|
//
|
|
// Routine Description:
|
|
// Display an error caused by setting or validating properties.
|
|
//
|
|
// Arguments:
|
|
// sc [IN] Status to display error on.
|
|
// idsOper [IN] Operation message.
|
|
//
|
|
// Return Value:
|
|
// nStatus ERROR_SUCCESS = success, !0 = failure
|
|
//
|
|
//--
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
void CBasePropertyPage::DisplaySetPropsError(
|
|
IN DWORD sc,
|
|
IN UINT idsOper
|
|
) const
|
|
{
|
|
CString strErrorMsg;
|
|
CString strOperMsg;
|
|
CString strMsgIdFmt;
|
|
CString strMsgId;
|
|
CString strMsg;
|
|
|
|
strOperMsg.LoadString( IDS_ERROR_SETTING_PROPERTIES );
|
|
FormatError( strErrorMsg, sc );
|
|
strMsgIdFmt.LoadString( IDS_ERROR_MSG_ID );
|
|
strMsgId.Format( strMsgIdFmt, sc, sc );
|
|
strMsg.Format( _T("%s\n\n%s%s"), strOperMsg, strErrorMsg, strMsgId );
|
|
AfxMessageBox( strMsg );
|
|
|
|
} //*** CBasePropertyPage::DisplaySetPropsError()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CBasePropertyPage::BRequiredDependenciesPresent
|
|
//
|
|
// Routine Description:
|
|
// Determine if the specified list contains each required resource
|
|
// for this type of resource.
|
|
//
|
|
// Arguments:
|
|
// None.
|
|
//
|
|
// Return Value:
|
|
// None.
|
|
//
|
|
// Exceptions Thrown:
|
|
// Any exceptions thrown by CString::LoadString() or CString::operator=().
|
|
//
|
|
//--
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
BOOL CBasePropertyPage::BRequiredDependenciesPresent( void )
|
|
{
|
|
BOOL bFound = TRUE;
|
|
DWORD sc;
|
|
CClusPropValueList pvl;
|
|
HRESOURCE hres;
|
|
PCLUS_RESOURCE_CLASS_INFO prci = NULL;
|
|
CString strMissing;
|
|
|
|
do
|
|
{
|
|
// Collect the list of required dependencies.
|
|
sc = pvl.ScGetResourceValueList(
|
|
Peo()->PrdResData()->m_hresource,
|
|
CLUSCTL_RESOURCE_GET_REQUIRED_DEPENDENCIES
|
|
);
|
|
if ( sc != ERROR_SUCCESS )
|
|
{
|
|
CNTException nte( sc, 0, NULL, NULL, FALSE );
|
|
nte.ReportError();
|
|
break;
|
|
} // if: error collecting required dependencies
|
|
|
|
// Move to the first value.
|
|
sc = pvl.ScMoveToFirstValue();
|
|
|
|
while ( sc == ERROR_SUCCESS )
|
|
{
|
|
switch ( pvl.CptCurrentValueType() )
|
|
{
|
|
case CLUSPROP_TYPE_RESCLASS:
|
|
prci = reinterpret_cast< PCLUS_RESOURCE_CLASS_INFO >( &pvl.CbhCurrentValue().pResourceClassInfoValue->li );
|
|
hres = ResUtilGetResourceDependencyByClass(
|
|
Hcluster(),
|
|
Peo()->PrdResData()->m_hresource,
|
|
prci,
|
|
FALSE // bRecurse
|
|
);
|
|
if ( hres != NULL )
|
|
{
|
|
CloseClusterResource( hres );
|
|
} // if: found the resource
|
|
else
|
|
{
|
|
if ( ! strMissing.LoadString( IDS_RESCLASS_UNKNOWN + prci->rc ) )
|
|
{
|
|
strMissing.LoadString( IDS_RESCLASS_UNKNOWN );
|
|
} // if: unknown resource class
|
|
|
|
bFound = FALSE;
|
|
} // else: resource not found
|
|
break;
|
|
|
|
case CLUSPROP_TYPE_NAME:
|
|
hres = ResUtilGetResourceDependencyByName(
|
|
Hcluster(),
|
|
Peo()->PrdResData()->m_hresource,
|
|
pvl.CbhCurrentValue().pName->sz,
|
|
FALSE // bRecurse
|
|
);
|
|
if ( hres != NULL )
|
|
{
|
|
CloseClusterResource( hres );
|
|
} // if: found the resource
|
|
else
|
|
{
|
|
GetResTypeDisplayOrTypeName( pvl.CbhCurrentValue().pName->sz, &strMissing );
|
|
bFound = FALSE;
|
|
} // else: resource not found
|
|
break;
|
|
|
|
} // switch: value type
|
|
|
|
// If a match was not found, changes cannot be applied.
|
|
if ( ! bFound )
|
|
{
|
|
CExceptionWithOper ewo( IDS_REQUIRED_DEPENDENCY_NOT_FOUND, NULL, NULL, FALSE );
|
|
|
|
ewo.SetOperation( IDS_REQUIRED_DEPENDENCY_NOT_FOUND, static_cast< LPCWSTR >( strMissing ) );
|
|
ewo.ReportError();
|
|
|
|
break;
|
|
} // if: not found
|
|
|
|
sc = pvl.ScMoveToNextValue();
|
|
} // while: more values in the value list
|
|
|
|
} while( 0 );
|
|
|
|
return bFound;
|
|
|
|
} //*** CBasePropertyPage::BRequiredDependenciesPresent()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CBasePropertyPage::GetResTypeDisplayOrTypeName
|
|
//
|
|
// Routine Description:
|
|
// Get the display name for a resource type if possible. If any errors
|
|
// occur, just return the type name.
|
|
//
|
|
// Arguments:
|
|
// pszResTypeNameIn
|
|
// [IN] Name of resource type.
|
|
//
|
|
// pstrResTypeDisplayNameInOut
|
|
// [IN OUT] CString in which to return the display name.
|
|
//
|
|
// Return Value:
|
|
// None.
|
|
//
|
|
//--
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
void CBasePropertyPage::GetResTypeDisplayOrTypeName(
|
|
IN LPCWSTR pszResTypeNameIn,
|
|
IN OUT CString * pstrResTypeDisplayNameInOut
|
|
)
|
|
{
|
|
DWORD sc;
|
|
CClusPropList cpl;
|
|
|
|
// Get resource type properties.
|
|
sc = cpl.ScGetResourceTypeProperties(
|
|
Hcluster(),
|
|
pszResTypeNameIn,
|
|
CLUSCTL_RESOURCE_TYPE_GET_COMMON_PROPERTIES
|
|
);
|
|
if ( sc != ERROR_SUCCESS )
|
|
goto Error;
|
|
|
|
// Find the Name property.
|
|
sc = cpl.ScMoveToPropertyByName( CLUSREG_NAME_RESTYPE_NAME );
|
|
if ( sc != ERROR_SUCCESS )
|
|
goto Error;
|
|
|
|
// Move to the first value for the property.
|
|
sc = cpl.ScMoveToFirstPropertyValue();
|
|
if ( sc != ERROR_SUCCESS )
|
|
goto Error;
|
|
|
|
// Make sure the name is a string.
|
|
if ( ( cpl.CpfCurrentValueFormat() != CLUSPROP_FORMAT_SZ )
|
|
&& ( cpl.CpfCurrentValueFormat() != CLUSPROP_FORMAT_EXPAND_SZ )
|
|
&& ( cpl.CpfCurrentValueFormat() != CLUSPROP_FORMAT_EXPANDED_SZ )
|
|
)
|
|
goto Error;
|
|
|
|
// Copy the string into the output CString.
|
|
*pstrResTypeDisplayNameInOut = cpl.CbhCurrentValue().pStringValue->sz;
|
|
|
|
Cleanup:
|
|
return;
|
|
|
|
Error:
|
|
*pstrResTypeDisplayNameInOut = pszResTypeNameIn;
|
|
goto Cleanup;
|
|
|
|
} //*** CBasePropertyPage::GetResTypeDisplayOrTypeName()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CBasePropertyPage::ScReadValue
|
|
//
|
|
// Routine Description:
|
|
// Read a REG_SZ value for this item.
|
|
//
|
|
// Arguments:
|
|
// pszValueName [IN] Name of the value to read.
|
|
// rstrValue [OUT] String in which to return the value.
|
|
// hkey [IN] Handle to the registry key to read from.
|
|
//
|
|
// Return Value:
|
|
// sc ERROR_SUCCESS = success, !0 = failure
|
|
//
|
|
//--
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
DWORD CBasePropertyPage::ScReadValue(
|
|
IN LPCTSTR pszValueName,
|
|
OUT CString & rstrValue,
|
|
IN HKEY hkey
|
|
)
|
|
{
|
|
DWORD sc;
|
|
LPWSTR pwszValue = NULL;
|
|
DWORD dwValueLen;
|
|
DWORD dwValueType;
|
|
|
|
ASSERT( pszValueName != NULL );
|
|
ASSERT( hkey != NULL );
|
|
|
|
rstrValue.Empty();
|
|
|
|
try
|
|
{
|
|
// Get the size of the value.
|
|
dwValueLen = 0;
|
|
sc = ::ClusterRegQueryValue(
|
|
hkey,
|
|
pszValueName,
|
|
&dwValueType,
|
|
NULL,
|
|
&dwValueLen
|
|
);
|
|
if ( ( sc == ERROR_SUCCESS ) || ( sc == ERROR_MORE_DATA ) )
|
|
{
|
|
ASSERT( dwValueType == REG_SZ );
|
|
|
|
// Allocate enough space for the data.
|
|
pwszValue = rstrValue.GetBuffer( dwValueLen / sizeof( WCHAR ) );
|
|
if ( pwszValue == NULL )
|
|
{
|
|
AfxThrowMemoryException();
|
|
} // if: error getting the buffer
|
|
ASSERT( pwszValue != NULL );
|
|
dwValueLen += 1 * sizeof( WCHAR ); // Don't forget the final null-terminator.
|
|
|
|
// Read the value.
|
|
sc = ::ClusterRegQueryValue(
|
|
hkey,
|
|
pszValueName,
|
|
&dwValueType,
|
|
(LPBYTE) pwszValue,
|
|
&dwValueLen
|
|
);
|
|
if ( sc == ERROR_SUCCESS )
|
|
{
|
|
ASSERT( dwValueType == REG_SZ );
|
|
} // if: value read successfully
|
|
rstrValue.ReleaseBuffer();
|
|
} // if: got the size successfully
|
|
} // try
|
|
catch ( CMemoryException * pme )
|
|
{
|
|
pme->Delete();
|
|
sc = ERROR_NOT_ENOUGH_MEMORY;
|
|
} // catch: CMemoryException
|
|
|
|
return sc;
|
|
|
|
} //*** CBasePropertyPage::ScReadValue(LPCTSTR, CString&)
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CBasePropertyPage::ScReadValue
|
|
//
|
|
// Routine Description:
|
|
// Read a REG_DWORD value for this item.
|
|
//
|
|
// Arguments:
|
|
// pszValueName [IN] Name of the value to read.
|
|
// pdwValue [OUT] DWORD in which to return the value.
|
|
// hkey [IN] Handle to the registry key to read from.
|
|
//
|
|
// Return Value:
|
|
// _sc ERROR_SUCCESS = success, !0 = failure
|
|
//
|
|
//--
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
DWORD CBasePropertyPage::ScReadValue(
|
|
IN LPCTSTR pszValueName,
|
|
OUT DWORD * pdwValue,
|
|
IN HKEY hkey
|
|
)
|
|
{
|
|
DWORD _sc;
|
|
DWORD _dwValue;
|
|
DWORD _dwValueLen;
|
|
DWORD _dwValueType;
|
|
|
|
ASSERT(pszValueName != NULL);
|
|
ASSERT(pdwValue != NULL);
|
|
ASSERT(hkey != NULL);
|
|
|
|
*pdwValue = 0;
|
|
|
|
// Read the value.
|
|
_dwValueLen = sizeof(_dwValue);
|
|
_sc = ::ClusterRegQueryValue(
|
|
hkey,
|
|
pszValueName,
|
|
&_dwValueType,
|
|
(LPBYTE) &_dwValue,
|
|
&_dwValueLen
|
|
);
|
|
if (_sc == ERROR_SUCCESS)
|
|
{
|
|
ASSERT(_dwValueType == REG_DWORD);
|
|
ASSERT(_dwValueLen == sizeof(_dwValue));
|
|
*pdwValue = _dwValue;
|
|
} // if: value read successfully
|
|
|
|
return _sc;
|
|
|
|
} //*** CBasePropertyPage::ScReadValue(LPCTSTR, DWORD*)
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CBasePropertyPage::ScReadValue
|
|
//
|
|
// Routine Description:
|
|
// Read a REG_BINARY value for this item.
|
|
//
|
|
// Arguments:
|
|
// pszValueName [IN] Name of the value to read.
|
|
// ppbValue [OUT] Pointer in which to return the data. Caller
|
|
// is responsible for deallocating the data.
|
|
// hkey [IN] Handle to the registry key to read from.
|
|
//
|
|
// Return Value:
|
|
// _sc ERROR_SUCCESS = success, !0 = failure
|
|
//
|
|
//--
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
DWORD CBasePropertyPage::ScReadValue(
|
|
IN LPCTSTR pszValueName,
|
|
OUT LPBYTE * ppbValue,
|
|
IN HKEY hkey
|
|
)
|
|
{
|
|
DWORD _sc;
|
|
DWORD _dwValueLen;
|
|
DWORD _dwValueType;
|
|
|
|
ASSERT(pszValueName != NULL);
|
|
ASSERT(ppbValue != NULL);
|
|
ASSERT(hkey != NULL);
|
|
|
|
*ppbValue = NULL;
|
|
|
|
// Get the length of the value.
|
|
_dwValueLen = 0;
|
|
_sc = ::ClusterRegQueryValue(
|
|
hkey,
|
|
pszValueName,
|
|
&_dwValueType,
|
|
NULL,
|
|
&_dwValueLen
|
|
);
|
|
if (_sc != ERROR_SUCCESS)
|
|
return _sc;
|
|
|
|
ASSERT(_dwValueType == REG_BINARY);
|
|
|
|
// Allocate a buffer,
|
|
try
|
|
{
|
|
*ppbValue = new BYTE[_dwValueLen];
|
|
} // try
|
|
catch (CMemoryException *)
|
|
{
|
|
_sc = ERROR_NOT_ENOUGH_MEMORY;
|
|
return _sc;
|
|
} // catch: CMemoryException
|
|
|
|
// Read the value.
|
|
_sc = ::ClusterRegQueryValue(
|
|
hkey,
|
|
pszValueName,
|
|
&_dwValueType,
|
|
*ppbValue,
|
|
&_dwValueLen
|
|
);
|
|
if (_sc != ERROR_SUCCESS)
|
|
{
|
|
delete [] *ppbValue;
|
|
*ppbValue = NULL;
|
|
} // if: value read successfully
|
|
|
|
return _sc;
|
|
|
|
} //*** CBasePropertyPage::ScReadValue(LPCTSTR, LPBYTE)
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CBasePropertyPage::ScWriteValue
|
|
//
|
|
// Routine Description:
|
|
// Write a REG_SZ value for this item if it hasn't changed.
|
|
//
|
|
// Arguments:
|
|
// pszValueName [IN] Name of the value to write.
|
|
// rstrValue [IN] Value data.
|
|
// rstrPrevValue [IN OUT] Previous value.
|
|
// hkey [IN] Handle to the registry key to write to.
|
|
//
|
|
// Return Value:
|
|
// _sc
|
|
//
|
|
//--
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
DWORD CBasePropertyPage::ScWriteValue(
|
|
IN LPCTSTR pszValueName,
|
|
IN const CString & rstrValue,
|
|
IN OUT CString & rstrPrevValue,
|
|
IN HKEY hkey
|
|
)
|
|
{
|
|
DWORD _sc;
|
|
|
|
ASSERT(pszValueName != NULL);
|
|
ASSERT(hkey != NULL);
|
|
|
|
// Write the value if it hasn't changed.
|
|
if (rstrValue != rstrPrevValue)
|
|
{
|
|
_sc = ::ClusterRegSetValue(
|
|
hkey,
|
|
pszValueName,
|
|
REG_SZ,
|
|
(CONST BYTE *) (LPCTSTR) rstrValue,
|
|
(rstrValue.GetLength() + 1) * sizeof(TCHAR)
|
|
);
|
|
if (_sc == ERROR_SUCCESS)
|
|
rstrPrevValue = rstrValue;
|
|
} // if: value changed
|
|
else
|
|
_sc = ERROR_SUCCESS;
|
|
return _sc;
|
|
|
|
} //*** CBasePropertyPage::ScWriteValue(LPCTSTR, CString&)
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CBasePropertyPage::ScWriteValue
|
|
//
|
|
// Routine Description:
|
|
// Write a REG_DWORD value for this item if it hasn't changed.
|
|
//
|
|
// Arguments:
|
|
// pszValueName [IN] Name of the value to write.
|
|
// dwValue [IN] Value data.
|
|
// pdwPrevValue [IN OUT] Previous value.
|
|
// hkey [IN] Handle to the registry key to write to.
|
|
//
|
|
// Return Value:
|
|
// _sc
|
|
//
|
|
//--
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
DWORD CBasePropertyPage::ScWriteValue(
|
|
IN LPCTSTR pszValueName,
|
|
IN DWORD dwValue,
|
|
IN OUT DWORD * pdwPrevValue,
|
|
IN HKEY hkey
|
|
)
|
|
{
|
|
DWORD _sc;
|
|
|
|
ASSERT(pszValueName != NULL);
|
|
ASSERT(pdwPrevValue != NULL);
|
|
ASSERT(hkey != NULL);
|
|
|
|
// Write the value if it hasn't changed.
|
|
if (dwValue != *pdwPrevValue)
|
|
{
|
|
_sc = ::ClusterRegSetValue(
|
|
hkey,
|
|
pszValueName,
|
|
REG_DWORD,
|
|
(CONST BYTE *) &dwValue,
|
|
sizeof(dwValue)
|
|
);
|
|
if (_sc == ERROR_SUCCESS)
|
|
*pdwPrevValue = dwValue;
|
|
} // if: value changed
|
|
else
|
|
_sc = ERROR_SUCCESS;
|
|
return _sc;
|
|
|
|
} //*** CBasePropertyPage::ScWriteValue(LPCTSTR, DWORD)
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CBasePropertyPage::ScWriteValue
|
|
//
|
|
// Routine Description:
|
|
// Write a REG_BINARY value for this item if it hasn't changed.
|
|
//
|
|
// Arguments:
|
|
// pszValueName [IN] Name of the value to write.
|
|
// pbValue [IN] Value data.
|
|
// cbValue [IN] Size of value data.
|
|
// ppbPrevValue [IN OUT] Previous value.
|
|
// cbPrevValue [IN] Size of the previous data.
|
|
// hkey [IN] Handle to the registry key to write to.
|
|
//
|
|
// Return Value:
|
|
// _sc
|
|
//
|
|
//--
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
DWORD CBasePropertyPage::ScWriteValue(
|
|
IN LPCTSTR pszValueName,
|
|
IN const LPBYTE pbValue,
|
|
IN DWORD cbValue,
|
|
IN OUT LPBYTE * ppbPrevValue,
|
|
IN DWORD cbPrevValue,
|
|
IN HKEY hkey
|
|
)
|
|
{
|
|
DWORD _sc;
|
|
LPBYTE _pbPrevValue = NULL;
|
|
|
|
ASSERT(pszValueName != NULL);
|
|
ASSERT(pbValue != NULL);
|
|
ASSERT(ppbPrevValue != NULL);
|
|
ASSERT(cbValue > 0);
|
|
ASSERT(hkey != NULL);
|
|
|
|
// See if the data has changed.
|
|
if (cbValue == cbPrevValue)
|
|
{
|
|
if (memcmp(pbValue, *ppbPrevValue, cbValue) == 0)
|
|
return ERROR_SUCCESS;
|
|
} // if: lengths are the same
|
|
|
|
// Allocate a new buffer for the previous data pointer.
|
|
try
|
|
{
|
|
_pbPrevValue = new BYTE[cbValue];
|
|
}
|
|
catch (CMemoryException *)
|
|
{
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
} // catch: CMemoryException
|
|
::CopyMemory(_pbPrevValue, pbValue, cbValue);
|
|
|
|
// Write the value if it hasn't changed.
|
|
_sc = ::ClusterRegSetValue(
|
|
hkey,
|
|
pszValueName,
|
|
REG_BINARY,
|
|
pbValue,
|
|
cbValue
|
|
);
|
|
if (_sc == ERROR_SUCCESS)
|
|
{
|
|
delete [] *ppbPrevValue;
|
|
*ppbPrevValue = _pbPrevValue;
|
|
} // if: set was successful
|
|
else
|
|
delete [] _pbPrevValue;
|
|
|
|
return _sc;
|
|
|
|
} //*** CBasePropertyPage::ScWriteValue(LPCTSTR, const LPBYTE)
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CBasePropertyPage::OnContextMenu
|
|
//
|
|
// Routine Description:
|
|
// Handler for the WM_CONTEXTMENU message.
|
|
//
|
|
// Arguments:
|
|
// pWnd Window in which user clicked the right mouse button.
|
|
// point Position of the cursor, in screen coordinates.
|
|
//
|
|
// Return Value:
|
|
// TRUE Help processed.
|
|
// FALSE Help not processed.
|
|
//
|
|
//--
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
void CBasePropertyPage::OnContextMenu(CWnd * pWnd, CPoint point)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
m_dlghelp.OnContextMenu(pWnd, point);
|
|
|
|
} //*** CBasePropertyPage::OnContextMenu()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CBasePropertyPage::OnHelpInfo
|
|
//
|
|
// Routine Description:
|
|
// Handler for the WM_HELPINFO message.
|
|
//
|
|
// Arguments:
|
|
// pHelpInfo Structure containing info about displaying help.
|
|
//
|
|
// Return Value:
|
|
// TRUE Help processed.
|
|
// FALSE Help not processed.
|
|
//
|
|
//--
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
BOOL CBasePropertyPage::OnHelpInfo(HELPINFO * pHelpInfo)
|
|
{
|
|
BOOL _bProcessed;
|
|
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
_bProcessed = m_dlghelp.OnHelpInfo(pHelpInfo);
|
|
if (!_bProcessed)
|
|
_bProcessed = CPropertyPage::OnHelpInfo(pHelpInfo);
|
|
return _bProcessed;
|
|
|
|
} //*** CBasePropertyPage::OnHelpInfo()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CBasePropertyPage::OnCommandHelp
|
|
//
|
|
// Routine Description:
|
|
// Handler for the WM_COMMANDHELP message.
|
|
//
|
|
// Arguments:
|
|
// wParam [IN] WPARAM.
|
|
// lParam [IN] LPARAM.
|
|
//
|
|
// Return Value:
|
|
// TRUE Help processed.
|
|
// FALSE Help not processed.
|
|
//
|
|
//--
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
LRESULT CBasePropertyPage::OnCommandHelp(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
LRESULT _bProcessed;
|
|
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
_bProcessed = m_dlghelp.OnCommandHelp(wParam, lParam);
|
|
if (!_bProcessed)
|
|
_bProcessed = CPropertyPage::OnCommandHelp(wParam, lParam);
|
|
|
|
return _bProcessed;
|
|
|
|
} //*** CBasePropertyPage::OnCommandHelp()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CBasePropertyPage::ConstructDefaultDirectory
|
|
//
|
|
// Routine Description:
|
|
// Get the name of the first partition from the first storage-class
|
|
// resource on which this resource is dependent.
|
|
//
|
|
// Arguments:
|
|
// rstrDir [OUT] Directory string.
|
|
// idsFormat [IN] Resource ID for the format string.
|
|
//
|
|
// Return Value:
|
|
// None.
|
|
//
|
|
//--
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
void CBasePropertyPage::ConstructDefaultDirectory(
|
|
OUT CString & rstrDir,
|
|
IN IDS idsFormat
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
HRESOURCE _hres = NULL;
|
|
DWORD _sc = ERROR_SUCCESS;
|
|
DWORD _cbDiskInfo = sizeof(CLUSPROP_DWORD)
|
|
+ sizeof(CLUSPROP_SCSI_ADDRESS)
|
|
+ sizeof(CLUSPROP_DISK_NUMBER)
|
|
+ sizeof(CLUSPROP_PARTITION_INFO)
|
|
+ sizeof(CLUSPROP_SYNTAX);
|
|
PBYTE _pbDiskInfo = NULL;
|
|
CLUSPROP_BUFFER_HELPER _cbh;
|
|
|
|
// Get the first partition for the resource..
|
|
try
|
|
{
|
|
// Get the storage-class resource on which we are dependent.
|
|
_hres = GetDependentStorageResource();
|
|
if (_hres == NULL)
|
|
return;
|
|
|
|
// Get disk info.
|
|
_pbDiskInfo = new BYTE[_cbDiskInfo];
|
|
_sc = ClusterResourceControl(
|
|
_hres,
|
|
NULL,
|
|
CLUSCTL_RESOURCE_STORAGE_GET_DISK_INFO,
|
|
NULL,
|
|
0,
|
|
_pbDiskInfo,
|
|
_cbDiskInfo,
|
|
&_cbDiskInfo
|
|
);
|
|
if (_sc == ERROR_MORE_DATA)
|
|
{
|
|
delete [] _pbDiskInfo;
|
|
_pbDiskInfo = new BYTE[_cbDiskInfo];
|
|
_sc = ClusterResourceControl(
|
|
_hres,
|
|
NULL,
|
|
CLUSCTL_RESOURCE_STORAGE_GET_DISK_INFO,
|
|
NULL,
|
|
0,
|
|
_pbDiskInfo,
|
|
_cbDiskInfo,
|
|
&_cbDiskInfo
|
|
);
|
|
} // if: buffer too small
|
|
if (_sc == ERROR_SUCCESS)
|
|
{
|
|
// Find the first partition.
|
|
_cbh.pb = _pbDiskInfo;
|
|
while (_cbh.pSyntax->dw != CLUSPROP_SYNTAX_ENDMARK)
|
|
{
|
|
if (_cbh.pSyntax->dw == CLUSPROP_SYNTAX_PARTITION_INFO)
|
|
{
|
|
rstrDir.FormatMessage(
|
|
idsFormat,
|
|
_cbh.pPartitionInfoValue->szDeviceName
|
|
);
|
|
break;
|
|
} // if: found a partition
|
|
_cbh.pb += sizeof(*_cbh.pValue) + ALIGN_CLUSPROP(_cbh.pValue->cbLength);
|
|
} // while: not at end of list
|
|
} // if: no error getting disk info
|
|
else
|
|
{
|
|
CNTException nte( _sc, IDS_ERROR_CONSTRUCTING_DEF_DIR );
|
|
nte.ReportError();
|
|
} // else: error getting disk info
|
|
} // try
|
|
catch (CMemoryException * _pme)
|
|
{
|
|
_pme->Delete();
|
|
} // catch: CMemoryException
|
|
|
|
CloseClusterResource(_hres);
|
|
delete [] _pbDiskInfo;
|
|
|
|
} //*** CBasePropertyPage::ConstructDefaultDirectory()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CBasePropertyPage::GetDependentStorageResource
|
|
//
|
|
// Routine Description:
|
|
// Construct a default spool directory based on the drive on which
|
|
// this resource is dependent and a default value for the directory.
|
|
//
|
|
// Arguments:
|
|
// phres [OUT] Handle to dependent resource.
|
|
//
|
|
// Return Value:
|
|
// HRESOURCE for the open dependent resource, or NULL if error.
|
|
//
|
|
//--
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
HRESOURCE CBasePropertyPage::GetDependentStorageResource(void)
|
|
{
|
|
DWORD _sc = ERROR_SUCCESS;
|
|
HRESENUM _hresenum;
|
|
HRESOURCE _hres = NULL;
|
|
DWORD _ires;
|
|
DWORD _dwType;
|
|
DWORD _cchName;
|
|
DWORD _cchNameSize;
|
|
LPWSTR _pszName = NULL;
|
|
CLUS_RESOURCE_CLASS_INFO _classinfo;
|
|
DWORD _cbClassInfo;
|
|
|
|
// Open the dependency enumerator.
|
|
_hresenum = ClusterResourceOpenEnum(
|
|
Peo()->PrdResData()->m_hresource,
|
|
CLUSTER_RESOURCE_ENUM_DEPENDS
|
|
);
|
|
if (_hresenum == NULL)
|
|
return NULL;
|
|
|
|
// Allocate a default size name buffer.
|
|
_cchNameSize = 512;
|
|
_pszName = new WCHAR[_cchNameSize];
|
|
|
|
for (_ires = 0 ; ; _ires++)
|
|
{
|
|
// Get the name of the next resource.
|
|
_cchName = _cchNameSize;
|
|
_sc = ClusterResourceEnum(
|
|
_hresenum,
|
|
_ires,
|
|
&_dwType,
|
|
_pszName,
|
|
&_cchName
|
|
);
|
|
if (_sc == ERROR_MORE_DATA)
|
|
{
|
|
delete [] _pszName;
|
|
_cchNameSize = _cchName;
|
|
_pszName = new WCHAR[_cchNameSize];
|
|
_sc = ClusterResourceEnum(
|
|
_hresenum,
|
|
_ires,
|
|
&_dwType,
|
|
_pszName,
|
|
&_cchName
|
|
);
|
|
} // if: name buffer too small
|
|
if (_sc != ERROR_SUCCESS)
|
|
break;
|
|
|
|
// Open the resource.
|
|
_hres = OpenClusterResource(Hcluster(), _pszName);
|
|
if (_hres == NULL)
|
|
{
|
|
_sc = GetLastError();
|
|
break;
|
|
} // if: error opening the resource
|
|
|
|
// Get the class of the resource.
|
|
_sc = ClusterResourceControl(
|
|
_hres,
|
|
NULL,
|
|
CLUSCTL_RESOURCE_GET_CLASS_INFO,
|
|
NULL,
|
|
0,
|
|
&_classinfo,
|
|
sizeof(_classinfo),
|
|
&_cbClassInfo
|
|
);
|
|
if (_sc != ERROR_SUCCESS)
|
|
{
|
|
CNTException nte( _sc, IDS_ERROR_GET_CLASS_INFO, _pszName, NULL, FALSE /*bAutoDelete*/ );
|
|
nte.ReportError();
|
|
continue;
|
|
}
|
|
|
|
// If this is a storage-class resource, we're done.
|
|
if (_classinfo.rc == CLUS_RESCLASS_STORAGE)
|
|
break;
|
|
|
|
// Not storage-class resource.
|
|
CloseClusterResource(_hres);
|
|
_hres = NULL;
|
|
} // for each resource on which we are dependent
|
|
|
|
// Handle errors.
|
|
if ((_sc != ERROR_SUCCESS) && (_hres != NULL))
|
|
{
|
|
CloseClusterResource(_hres);
|
|
_hres = NULL;
|
|
} // if: error getting resource
|
|
|
|
// Cleanup.
|
|
ClusterResourceCloseEnum(_hresenum);
|
|
delete [] _pszName;
|
|
|
|
return _hres;
|
|
|
|
} //*** CBasePropertyPage::GetDependentStorageResource()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CBasePropertyPage::BGetClusterNetworkNameNode
|
|
//
|
|
// Routine Description:
|
|
// Get the node hosting the Network Name resource.
|
|
//
|
|
// Arguments:
|
|
// rstrNode [OUT] - receives the node name
|
|
//
|
|
// Return Value:
|
|
// BOOL -- TRUE for success, FALSE for error
|
|
//
|
|
//--
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
BOOL CBasePropertyPage::BGetClusterNetworkNameNode( OUT CString & rstrNode )
|
|
{
|
|
BOOL _bSuccess = TRUE;
|
|
DWORD _sc;
|
|
DWORD _dwFlag;
|
|
DWORD _cbData;
|
|
DWORD _ires;
|
|
DWORD _dwType;
|
|
DWORD _cchName = 0;
|
|
DWORD _cchNameCurrent;
|
|
LPWSTR _pszName = NULL;
|
|
WCHAR _szResType[ RTL_NUMBER_OF( CLUS_RESTYPE_NAME_NETNAME ) ];
|
|
WCHAR _szNode[ MAX_COMPUTERNAME_LENGTH + 1 ];
|
|
HCLUSENUM _hclusenum = NULL;
|
|
HRESOURCE _hresource = NULL;
|
|
CLUSTER_RESOURCE_STATE _crs;
|
|
CWaitCursor _wc;
|
|
|
|
try
|
|
{
|
|
// Open a cluster enumerator.
|
|
_hclusenum = ClusterOpenEnum( Hcluster(), CLUSTER_ENUM_RESOURCE );
|
|
if (_hclusenum == NULL)
|
|
{
|
|
ThrowStaticException( GetLastError() );
|
|
}
|
|
|
|
// Allocate an initial buffer.
|
|
_cchName = 256;
|
|
_pszName = new WCHAR[_cchName];
|
|
|
|
// Loop through each resource.
|
|
for ( _ires = 0 ; ; _ires++ )
|
|
{
|
|
// Get the next resource.
|
|
_cchNameCurrent = _cchName;
|
|
_sc = ClusterEnum( _hclusenum, _ires, &_dwType, _pszName, &_cchNameCurrent );
|
|
if ( _sc == ERROR_MORE_DATA )
|
|
{
|
|
delete [] _pszName;
|
|
_cchName = ++_cchNameCurrent;
|
|
_pszName = new WCHAR[_cchName];
|
|
_sc = ClusterEnum(_hclusenum, _ires, &_dwType, _pszName, &_cchNameCurrent);
|
|
} // if: buffer too small
|
|
if (_sc == ERROR_NO_MORE_ITEMS)
|
|
break;
|
|
if (_sc != ERROR_SUCCESS)
|
|
ThrowStaticException(_sc);
|
|
|
|
// Open the resource.
|
|
_hresource = OpenClusterResource(Hcluster(), _pszName);
|
|
if (_hresource == NULL)
|
|
ThrowStaticException(GetLastError());
|
|
|
|
// Get its flags.
|
|
_sc = ClusterResourceControl(
|
|
_hresource,
|
|
NULL,
|
|
CLUSCTL_RESOURCE_GET_FLAGS,
|
|
NULL,
|
|
0,
|
|
&_dwFlag,
|
|
sizeof(DWORD),
|
|
&_cbData
|
|
);
|
|
if (_sc != ERROR_SUCCESS)
|
|
{
|
|
CNTException nte( _sc, IDS_ERROR_GET_RESOURCE_FLAGS, _pszName, NULL, FALSE /*bAutoDelete*/ );
|
|
nte.ReportError();
|
|
continue;
|
|
}
|
|
|
|
// If this isn't a core resource, skip it.
|
|
if ((_dwFlag & CLUS_FLAG_CORE) == 0)
|
|
continue;
|
|
|
|
// Get its resource type name. If the buffer is too small,
|
|
// it isn't a Network Name resource so skip it.
|
|
_sc = ClusterResourceControl(
|
|
_hresource,
|
|
NULL,
|
|
CLUSCTL_RESOURCE_GET_RESOURCE_TYPE,
|
|
NULL,
|
|
0,
|
|
_szResType,
|
|
sizeof(_szResType),
|
|
&_cbData
|
|
);
|
|
if (_sc == ERROR_MORE_DATA)
|
|
continue;
|
|
if (_sc != ERROR_SUCCESS)
|
|
ThrowStaticException(_sc);
|
|
|
|
// If this is a Network Name resource, get which node it is online on.
|
|
if ( ClRtlStrNICmp( _szResType, CLUS_RESTYPE_NAME_NETNAME, RTL_NUMBER_OF( CLUS_RESTYPE_NAME_NETNAME ) ) == 0 )
|
|
{
|
|
// Get the state of the resource.
|
|
_crs = GetClusterResourceState(
|
|
_hresource,
|
|
_szNode,
|
|
&_cchName,
|
|
NULL,
|
|
NULL
|
|
);
|
|
if (_crs == ClusterResourceStateUnknown)
|
|
ThrowStaticException(GetLastError());
|
|
|
|
// Save the node name in the return argument.
|
|
rstrNode = _szNode;
|
|
|
|
break;
|
|
} // if: Network Name resource
|
|
|
|
CloseClusterResource( _hresource );
|
|
_hresource = NULL;
|
|
} // for: each resource
|
|
|
|
if (rstrNode[0] == _T('\0'))
|
|
ThrowStaticException(ERROR_FILE_NOT_FOUND, (IDS) 0);
|
|
} // try
|
|
catch (CException * _pe)
|
|
{
|
|
_pe->ReportError();
|
|
_pe->Delete();
|
|
_bSuccess = FALSE;
|
|
} // catch: CException
|
|
|
|
delete [] _pszName;
|
|
|
|
if ( _hresource != NULL )
|
|
{
|
|
CloseClusterResource( _hresource );
|
|
} // if: resource is open
|
|
if ( _hclusenum != NULL )
|
|
{
|
|
ClusterCloseEnum( _hclusenum );
|
|
} // if: enumerator is open
|
|
|
|
return _bSuccess;
|
|
|
|
} //*** CBasePropertyPage::BGetClusterNetworkNameNode()
|