///////////////////////////////////////////////////////////////////////////// // // Copyright (c) 1999-2002 Microsoft Corporation // // Module Name: // ExtObj.cpp // // Description: // Implementation of the CExtObject class, which implements the // extension interfaces required by a Microsoft Windows NT Cluster // Administrator Extension DLL. // // Author: // David Potter (DavidP) March 24, 1999 // // Revision History: // // Notes: // ///////////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "ClNetResEx.h" #include "ExtObj.h" #include "Dhcp.h" #include "Wins.h" ///////////////////////////////////////////////////////////////////////////// // Global Variables ///////////////////////////////////////////////////////////////////////////// const WCHAR g_wszResourceTypeNames[] = L"DHCP Service\0" L"WINS Service\0" ; const DWORD g_cchResourceTypeNames = sizeof( g_wszResourceTypeNames ) / sizeof( WCHAR ); static CRuntimeClass * g_rgprtcDhcpResPSPages[] = { RUNTIME_CLASS( CDhcpParamsPage ), NULL }; static CRuntimeClass * g_rgprtcWinsResPSPages[] = { RUNTIME_CLASS( CWinsParamsPage ), NULL }; static CRuntimeClass ** g_rgpprtcResPSPages[] = { g_rgprtcDhcpResPSPages, g_rgprtcWinsResPSPages, }; static CRuntimeClass ** g_rgpprtcResWizPages[] = { g_rgprtcDhcpResPSPages, g_rgprtcWinsResPSPages, }; ///////////////////////////////////////////////////////////////////////////// // CExtObject ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// //++ // // CExtObject::CExtObject // // Description: // Default constructor. // // Arguments: // None. // // Return Value: // None. // //-- ///////////////////////////////////////////////////////////////////////////// CExtObject::CExtObject( void ) { m_piData = NULL; m_piWizardCallback = NULL; m_bWizard = FALSE; m_istrResTypeName = 0; m_lcid = NULL; m_hfont = NULL; m_hicon = NULL; m_hcluster = NULL; m_cobj = 0; m_podObjData = NULL; } //*** CExtObject::CExtObject() ///////////////////////////////////////////////////////////////////////////// //++ // // CExtObject::~CExtObject // // Description: // Destructor. // // Arguments: // None. // // Return Value: // None. // //-- ///////////////////////////////////////////////////////////////////////////// CExtObject::~CExtObject( void ) { // Release the data interface. if ( PiData() != NULL ) { PiData()->Release(); m_piData = NULL; } // if: we have a data interface pointer // Release the wizard callback interface. if ( PiWizardCallback() != NULL ) { PiWizardCallback()->Release(); m_piWizardCallback = NULL; } // if: we have a wizard callback interface pointer // Delete the pages. { POSITION pos; pos = Lpg().GetHeadPosition(); while ( pos != NULL ) { delete Lpg().GetNext(pos); } // while: more pages in the list } // Delete the pages delete m_podObjData; } //*** CExtObject::~CExtObject() ///////////////////////////////////////////////////////////////////////////// // ISupportErrorInfo Implementation ///////////////////////////////////////////////////////////////////////////// //++ // // CExtObject::InterfaceSupportsErrorInfo (ISupportErrorInfo) // // Routine Description: // Indicates whether an interface suportes the IErrorInfo interface. // This interface is provided by ATL. // // Arguments: // riid Interface ID. // // Return Value: // S_OK Interface supports IErrorInfo. // S_FALSE Interface does not support IErrorInfo. // //-- ///////////////////////////////////////////////////////////////////////////// STDMETHODIMP CExtObject::InterfaceSupportsErrorInfo( REFIID riid ) { static const IID * _rgiid[] = { &IID_IWEExtendPropertySheet, &IID_IWEExtendWizard, }; int _iiid; for ( _iiid = 0 ; _iiid < sizeof( _rgiid ) / sizeof( _rgiid[ 0 ] ) ; _iiid++ ) { if ( ::InlineIsEqualGUID( *_rgiid[ _iiid ], riid ) ) { return S_OK; } // if: found a matching IID } return S_FALSE; } //*** CExtObject::InterfaceSupportsErrorInfo() ///////////////////////////////////////////////////////////////////////////// // IWEExtendPropertySheet Implementation ///////////////////////////////////////////////////////////////////////////// //++ // // CExtObject::CreatePropertySheetPages (IWEExtendPropertySheet) // // Description: // Create property sheet pages and add them to the sheet. // // Arguments: // piData [IN] // IUnkown pointer from which to obtain interfaces for obtaining data // describing the object for which the sheet is being displayed. // // piCallback [IN] // Pointer to an IWCPropertySheetCallback interface for adding pages // to the sheet. // // Return Value: // NOERROR Pages added successfully. // E_INVALIDARG Invalid arguments to the function. // E_OUTOFMEMORY Error allocating memory. // E_FAIL Error creating a page. // E_NOTIMPL Not implemented for this type of data. // _hr Any error codes from HrGetUIInfo() or HrSaveData(). // //-- ///////////////////////////////////////////////////////////////////////////// STDMETHODIMP CExtObject::CreatePropertySheetPages( IN IUnknown * piData, IN IWCPropertySheetCallback * piCallback ) { HRESULT _hr = NOERROR; CException _exc( FALSE /*bAutoDelete*/ ); CRuntimeClass ** _pprtc = NULL; int _irtc; CBasePropertyPage * _ppage; AFX_MANAGE_STATE( AfxGetStaticModuleState() ); // Validate the parameters. if ( (piData == NULL) || (piCallback == NULL) ) { return E_INVALIDARG; } // if: all interfaces not specified try { // Get info about displaying UI. _hr = HrGetUIInfo( piData ); if ( _hr != NOERROR ) { throw &_exc; } // if: error getting UI info // Save the data. _hr = HrSaveData( piData ); if ( _hr != NOERROR ) { throw &_exc; } // if: error saving data from host // Delete any previous pages. { POSITION pos; pos = Lpg().GetHeadPosition(); while ( pos != NULL ) { delete Lpg().GetNext( pos ); } // while: more pages in the list Lpg().RemoveAll(); } // Delete any previous pages // Create property pages. ASSERT( PodObjData() != NULL ); switch ( PodObjData()->m_cot ) { case CLUADMEX_OT_RESOURCE: _pprtc = g_rgpprtcResPSPages[ IstrResTypeName() ]; break; default: _hr = E_NOTIMPL; throw &_exc; break; } // switch: object type // Create each page. for ( _irtc = 0 ; _pprtc[ _irtc ] != NULL ; _irtc++ ) { // Create the page. _ppage = static_cast< CBasePropertyPage * >( _pprtc[ _irtc ]->CreateObject() ); ASSERT( _ppage->IsKindOf( _pprtc[ _irtc ] ) ); // Add it to the list. Lpg().AddTail( _ppage ); // Initialize the property page. _hr = _ppage->HrInit( this ); if ( FAILED( _hr ) ) { throw &_exc; } // if: error initializing the page // Create the page. _hr = _ppage->HrCreatePage(); if ( FAILED( _hr ) ) { throw &_exc; } // if: error creating the page // Add it to the property sheet. _hr = piCallback->AddPropertySheetPage( reinterpret_cast< LONG * >( _ppage->Hpage() ) ); if ( _hr != NOERROR ) { throw &_exc; } // if: error adding the page to the sheet } // for: each page in the list } // try catch ( CMemoryException * _pme ) { TRACE( _T("CExtObject::CreatePropetySheetPages() - Failed to add property page\n") ); _pme->Delete(); _hr = E_OUTOFMEMORY; } // catch: anything catch ( CException * _pe ) { TRACE( _T("CExtObject::CreatePropetySheetPages() - Failed to add property page\n") ); _pe->Delete(); if ( _hr == NOERROR ) { _hr = E_FAIL; } // if: _hr hasn't beeen set yet } // catch: anything if ( _hr != NOERROR ) { piData->Release(); m_piData = NULL; } // if: error occurred piCallback->Release(); return _hr; } //*** CExtObject::CreatePropertySheetPages() ///////////////////////////////////////////////////////////////////////////// // IWEExtendWizard Implementation ///////////////////////////////////////////////////////////////////////////// //++ // // CExtObject::CreateWizardPages (IWEExtendWizard) // // Description: // Create property sheet pages and add them to the wizard. // // Arguments: // piData [IN] // IUnkown pointer from which to obtain interfaces for obtaining data // describing the object for which the wizard is being displayed. // // piCallback [IN] // Pointer to an IWCPropertySheetCallback interface for adding pages // to the sheet. // // Return Value: // NOERROR Pages added successfully. // E_INVALIDARG Invalid arguments to the function. // E_OUTOFMEMORY Error allocating memory. // E_FAIL Error creating a page. // E_NOTIMPL Not implemented for this type of data. // _hr Any error codes from HrGetUIInfo() or HrSaveData(). // //-- ///////////////////////////////////////////////////////////////////////////// STDMETHODIMP CExtObject::CreateWizardPages( IN IUnknown * piData, IN IWCWizardCallback * piCallback ) { HRESULT _hr = NOERROR; CException _exc( FALSE /*bAutoDelete*/ ); CRuntimeClass ** _pprtc = NULL; int _irtc; CBasePropertyPage * _ppage; AFX_MANAGE_STATE( AfxGetStaticModuleState() ); // Validate the parameters. if ( (piData == NULL) || (piCallback == NULL) ) { return E_INVALIDARG; } // if: all interfaces not specified try { // Get info about displaying UI. _hr = HrGetUIInfo( piData ); if ( _hr != NOERROR ) { throw &_exc; } // if: error getting UI info // Save the data. _hr = HrSaveData( piData ); if ( _hr != NOERROR ) { throw &_exc; } // if: error saving data from host // Delete any previous pages. { POSITION pos; pos = Lpg().GetHeadPosition(); while ( pos != NULL ) { delete Lpg().GetNext( pos ); } // while: more pages in the list Lpg().RemoveAll(); } // Delete any previous pages m_piWizardCallback = piCallback; m_bWizard = TRUE; // Create property pages. ASSERT( PodObjData() != NULL ); switch ( PodObjData()->m_cot ) { case CLUADMEX_OT_RESOURCE: _pprtc = g_rgpprtcResWizPages[ IstrResTypeName() ]; break; default: _hr = E_NOTIMPL; throw &_exc; break; } // switch: object type // Create each page. for ( _irtc = 0 ; _pprtc[ _irtc ] != NULL ; _irtc++ ) { // Create the page. _ppage = static_cast< CBasePropertyPage * >( _pprtc[ _irtc ]->CreateObject() ); ASSERT( _ppage->IsKindOf( _pprtc[ _irtc ] ) ); // Add it to the list. Lpg().AddTail( _ppage ); // Initialize the property page. _hr = _ppage->HrInit( this ); if ( FAILED( _hr ) ) { throw &_exc; } // if: error initializing the page // Create the page. _hr = _ppage->HrCreatePage(); if ( FAILED( _hr ) ) { throw &_exc; } // if: error creating the page // Add it to the property sheet. _hr = piCallback->AddWizardPage( reinterpret_cast< LONG * >( _ppage->Hpage() ) ); if ( _hr != NOERROR ) { throw &_exc; } // if: error adding the page to the sheet } // for: each page in the list } // try catch ( CMemoryException * _pme ) { TRACE( _T("CExtObject::CreateWizardPages() - Failed to add wizard page\n") ); _pme->Delete(); _hr = E_OUTOFMEMORY; } // catch: anything catch ( CException * _pe ) { TRACE( _T("CExtObject::CreateWizardPages() - Failed to add wizard page\n") ); _pe->Delete(); if ( _hr == NOERROR ) { _hr = E_FAIL; } // if: _hr hasn't beeen set yet } // catch: anything if ( _hr != NOERROR ) { piCallback->Release(); if ( m_piWizardCallback == piCallback ) { m_piWizardCallback = NULL; } // if: already saved interface pointer piData->Release(); m_piData = NULL; } // if: error occurred return _hr; } //*** CExtObject::CreateWizardPages() ///////////////////////////////////////////////////////////////////////////// //++ // // CExtObject::HrGetUIInfo // // Description: // Get info about displaying UI. // // Arguments: // piData [IN] // IUnkown pointer from which to obtain interfaces for obtaining data // describing the object. // // Return Value: // NOERROR // Data saved successfully. // // E_NOTIMPL // Not implemented for this type of data. // // _hr // Any error codes from IUnknown::QueryInterface(), // HrGetObjectName(), or HrGetResourceName(). // //-- ///////////////////////////////////////////////////////////////////////////// HRESULT CExtObject::HrGetUIInfo( IN IUnknown * piData ) { HRESULT _hr = NOERROR; ASSERT( piData != NULL ); // Save info about all types of objects. { IGetClusterUIInfo * _pi; _hr = piData->QueryInterface( IID_IGetClusterUIInfo, reinterpret_cast< LPVOID * >( &_pi ) ); if ( _hr != NOERROR ) { return _hr; } // if: error querying for interface m_lcid = _pi->GetLocale(); m_hfont = _pi->GetFont(); m_hicon = _pi->GetIcon(); _pi->Release(); } // Save info about all types of objects return _hr; } //*** CExtObject::HrGetUIInfo() ///////////////////////////////////////////////////////////////////////////// //++ // // CExtObject::HrSaveData // // Routine Description: // Save data from the object so that it can be used for the life // of the object. // // Arguments: // piData [IN] // IUnkown pointer from which to obtain interfaces for obtaining data // describing the object. // // Return Value: // NOERROR // Data saved successfully. // // E_NOTIMPL // Not implemented for this type of data. // // _hr // Any error codes from IUnknown::QueryInterface(), // HrGetObjectName(), or HrGetResourceName(). // //-- ///////////////////////////////////////////////////////////////////////////// HRESULT CExtObject::HrSaveData( IN IUnknown * piData ) { HRESULT _hr = NOERROR; ASSERT( piData != NULL ); if ( piData != m_piData ) { if ( m_piData != NULL ) { m_piData->Release(); } // if: interface queried for previously m_piData = piData; } // if: different data interface pointer // Save info about all types of objects. { IGetClusterDataInfo * _pi; _hr = piData->QueryInterface( IID_IGetClusterDataInfo, reinterpret_cast< LPVOID * >( &_pi ) ); if ( _hr != NOERROR ) { return _hr; } // if: error querying for interface m_hcluster = _pi->GetClusterHandle(); m_cobj = _pi->GetObjectCount(); if ( Cobj() != 1 ) // Only have support for one selected object. { _hr = E_NOTIMPL; } // if: too many objects for us to handle _pi->Release(); if ( _hr != NOERROR ) { return _hr; } // if: error occurred before here } // Save info about all types of objects // Save info about this object. _hr = HrGetObjectInfo(); return _hr; } //*** CExtObject::HrSaveData() ///////////////////////////////////////////////////////////////////////////// //++ // // CExtObject::HrGetObjectInfo // // Description: // Get information about the object. // // Arguments: // None. // // Return Value: // NOERROR // Data saved successfully. // // E_OUTOFMEMORY /// Error allocating memory. // // E_NOTIMPL // Not implemented for this type of data. // // _hr // Any error codes from IUnknown::QueryInterface(), // HrGetObjectName(), or HrGetResourceTypeName(). // //-- ///////////////////////////////////////////////////////////////////////////// HRESULT CExtObject::HrGetObjectInfo( void ) { HRESULT _hr = NOERROR; IGetClusterObjectInfo * _piGcoi; CLUADMEX_OBJECT_TYPE _cot = CLUADMEX_OT_NONE; CException _exc( FALSE /*bAutoDelete*/ ); const CString * _pstrResTypeName = NULL; ASSERT( PiData() != NULL ); // Get object info. { // Get an IGetClusterObjectInfo interface pointer. _hr = PiData()->QueryInterface( IID_IGetClusterObjectInfo, reinterpret_cast< LPVOID * >( &_piGcoi ) ); if ( _hr != NOERROR ) { return _hr; } // if: error querying for interface // Read the object data. try { // Delete the previous object data. delete m_podObjData; m_podObjData = NULL; // Get the type of the object. _cot = _piGcoi->GetObjectType( 0 ); switch ( _cot ) { case CLUADMEX_OT_RESOURCE: { IGetClusterResourceInfo * _pi; m_podObjData = new CResData; if ( m_podObjData == NULL ) { _hr = E_OUTOFMEMORY; throw &_exc; } // if: error allocating memory // Get an IGetClusterResourceInfo interface pointer. _hr = PiData()->QueryInterface( IID_IGetClusterResourceInfo, reinterpret_cast< LPVOID * >( &_pi ) ); if ( _hr != NOERROR ) { throw &_exc; } // if: error querying for interface PrdResDataRW()->m_hresource = _pi->GetResourceHandle( 0 ); ASSERT( PrdResDataRW()->m_hresource != NULL ); if ( PrdResDataRW()->m_hresource == NULL ) { _hr = E_INVALIDARG; } // if invalid resource handle else { _hr = HrGetResourceTypeName( _pi ); } // else: resource handle is valid _pi->Release(); if ( _hr != NOERROR ) { throw &_exc; } // if: error occurred above _pstrResTypeName = &PrdResDataRW()->m_strResTypeName; } // if: object is a resource break; case CLUADMEX_OT_RESOURCETYPE: { m_podObjData = new CObjData; if ( m_podObjData == NULL ) { _hr = E_OUTOFMEMORY; throw &_exc; } _pstrResTypeName = &PodObjDataRW()->m_strName; } // if: object is a resource type break; default: _hr = E_NOTIMPL; throw &_exc; break; } // switch: object type PodObjDataRW()->m_cot = _cot; _hr = HrGetObjectName( _piGcoi ); } // try catch ( CException * _pe ) { if ( !FAILED (_hr) ) { _hr = E_FAIL; } _pe->Delete(); } // catch: CException _piGcoi->Release(); // If we failed to initialize _pstrResTypeName, then bail. // We are doing this because of PREFIX, which assumes that the // new operator for OT_RESOURCETYPE above can fail - // but it should never happen that the new should perform a throw. if ( _pstrResTypeName == NULL ) { _hr = E_OUTOFMEMORY; } if ( _hr != NOERROR ) { return _hr; } // if: error occurred above } // Get object info // If this is a resource or resource type, see if we know about this type. if ( ( (_cot == CLUADMEX_OT_RESOURCE) || (_cot == CLUADMEX_OT_RESOURCETYPE) ) && (_hr == NOERROR) ) { LPCWSTR _pwszResTypeName; // Find the resource type name in our list. // Save the index for use in other arrays. for ( m_istrResTypeName = 0, _pwszResTypeName = g_wszResourceTypeNames ; *_pwszResTypeName != L'\0' ; m_istrResTypeName++, _pwszResTypeName += lstrlenW( _pwszResTypeName ) + 1 ) { if ( _pstrResTypeName->CompareNoCase( _pwszResTypeName ) == 0 ) { break; } // if: found resource type name } // for: each resource type in the list if ( *_pwszResTypeName == L'\0' ) { _hr = E_NOTIMPL; } // if: resource type name not found } // See if we know about this resource type return _hr; } //*** CExtObject::HrGetObjectInfo() ///////////////////////////////////////////////////////////////////////////// //++ // // CExtObject::HrGetObjectName // // Description: // Get the name of the object. // // Arguments: // piData [IN] // IGetClusterObjectInfo interface pointer for getting the object // name. // // Return Value: // NOERROR // Data saved successfully. // // E_OUTOFMEMORY // Error allocating memory. // // E_NOTIMPL // Not implemented for this type of data. // // _hr // Any error codes from IGetClusterObjectInfo::GetObjectInfo(). // //-- ///////////////////////////////////////////////////////////////////////////// HRESULT CExtObject::HrGetObjectName( IN IGetClusterObjectInfo * pi ) { HRESULT _hr = NOERROR; WCHAR * _pwszName = NULL; LONG _cchName; BSTR _bstr = NULL; ASSERT( pi != NULL ); _hr = pi->GetObjectName( 0, NULL, &_cchName ); if ( _hr != NOERROR ) { goto Cleanup; } // if: error getting object name _bstr = SysAllocStringLen( NULL, _cchName ); if ( _bstr != NULL ) { try { _hr = pi->GetObjectName( 0, _bstr, &_cchName ); if ( _hr == NOERROR ) { _pwszName = new WCHAR[_cchName]; _hr = StringCchCopyW( _pwszName, _cchName, _bstr ); if ( FAILED( _hr ) ) { goto Cleanup; } _pwszName[ _cchName - 1 ] = L'\0'; } PodObjDataRW()->m_strName = _pwszName; } // try catch ( CMemoryException * _pme ) { _pme->Delete(); _hr = E_OUTOFMEMORY; } // catch: CMemoryException SysFreeString( _bstr ); } // if: ( _bstr != NULL ) else { _hr = E_OUTOFMEMORY; } Cleanup: delete [] _pwszName; return _hr; } //*** CExtObject::HrGetObjectName() ///////////////////////////////////////////////////////////////////////////// //++ // // CExtObject::HrGetResourceTypeName // // Routine Description: // Get the name of the resource's type. // // Arguments: // piData [IN] // IGetClusterResourceInfo interface pointer for getting the resource // type name. // // Return Value: // NOERROR // Data saved successfully. // // E_OUTOFMEMORY // Error allocating memory. // // E_NOTIMPL // Not implemented for this type of data. // // _hr // Any error codes from IGetClusterResourceInfo // ::GetResourceTypeName(). // //-- ///////////////////////////////////////////////////////////////////////////// HRESULT CExtObject::HrGetResourceTypeName( IN IGetClusterResourceInfo * pi ) { HRESULT _hr = NOERROR; WCHAR * _pwszName = NULL; LONG _cchName; BSTR _bstr = NULL; ASSERT( pi != NULL ); _hr = pi->GetResourceTypeName( 0, NULL, &_cchName ); if ( _hr != NOERROR ) { goto Cleanup; } // if: error getting resource type name _bstr = SysAllocStringLen( NULL, _cchName ); if ( _bstr != NULL ) { try { _hr = pi->GetResourceTypeName( 0, _bstr, &_cchName ); if ( _hr == NOERROR ) { _pwszName = new WCHAR[_cchName]; _hr = StringCchCopyW( _pwszName, _cchName, _bstr ); if ( FAILED( _hr ) ) { goto Cleanup; } _pwszName[ _cchName - 1 ] = L'\0'; } PrdResDataRW()->m_strResTypeName = _pwszName; } // try catch ( CMemoryException * _pme ) { _pme->Delete(); _hr = E_OUTOFMEMORY; } // catch: CMemoryException SysFreeString( _bstr ); } // if: ( _bstr != NULL ) else { _hr = E_OUTOFMEMORY; } Cleanup: delete [] _pwszName; return _hr; } //*** CExtObject::HrGetResourceTypeName()