#include "stdafx.h" #include "compdata.h" #include "select.h" #include "classgen.hpp" ///////////////////////////////////////////////////////////////// // ClassGeneralPage const CDialogControlsInfo ctrls[] = { { IDC_CLASS_GENERAL_DESCRIPTION_EDIT, g_Description, TRUE }, { IDC_CATEGORY_CHANGE, g_DefaultCategory, FALSE }, { IDC_CLASS_GENERAL_DISPLAYABLE_CHECK, g_ShowInAdvViewOnly, FALSE }, { IDC_CLASS_DEACTIVATE, g_isDefunct, FALSE } }; const DWORD ClassGeneralPage::help_map[] = { IDI_CLASS, NO_HELP, IDC_CLASS_GENERAL_NAME_STATIC, NO_HELP, IDC_CLASS_GENERAL_DESCRIPTION_EDIT, IDH_CLASS_GENERAL_DESCRIPTION_EDIT, IDC_CLASS_GENERAL_LDN, IDH_CLASS_GENERAL_LDN, IDC_CLASS_GENERAL_OID_EDIT, IDH_CLASS_GENERAL_OID_EDIT, IDC_CLASS_GENERAL_CATEGORY_COMBO, IDH_CLASS_GENERAL_CATEGORY_COMBO, IDC_CATEGORY_EDIT, IDH_CATEGORY_EDIT, IDC_CATEGORY_CHANGE, IDH_CATEGORY_CHANGE, IDC_CLASS_GENERAL_DISPLAYABLE_CHECK, IDH_CLASS_GENERAL_DISPLAYABLE_CHECK, IDC_CLASS_DEACTIVATE, IDH_CLASS_DEACTIVATE, IDC_CLASS_GENERAL_SYSCLASS_STATIC, NO_HELP, 0, 0 }; // // The MFC Message Map. // BEGIN_MESSAGE_MAP( ClassGeneralPage, CDialog ) ON_BN_CLICKED( IDC_CATEGORY_CHANGE, OnButtonCategoryChange ) ON_MESSAGE(WM_HELP, OnHelp) ON_MESSAGE(WM_CONTEXTMENU, OnContextHelp) ON_BN_CLICKED(IDC_CLASS_DEACTIVATE, OnDeactivateClick) END_MESSAGE_MAP() // // Class dialog box routines. // ClassGeneralPage::ClassGeneralPage( ComponentData *pScope ) : CPropertyPage( IDD_CLASS_GENERAL ), fDataLoaded( FALSE ), pIADsObject( NULL ), pObject( NULL ), pScopeControl( pScope ) { ; } ClassGeneralPage::~ClassGeneralPage() { // // Always make sure we free the IADs object. // if ( pIADsObject ) { pIADsObject->Release(); pIADsObject = NULL; } // // And release the cache! // if ( pObject ) { pScopeControl->g_SchemaCache.ReleaseRef( pObject ); } } BOOL ClassGeneralPage::OnInitDialog() { CPropertyPage::OnInitDialog(); CWnd* wnd = GetDlgItem(IDC_CLASS_GENERAL_DESCRIPTION_EDIT); ASSERT(wnd); if (wnd) { wnd->SendMessage(EM_SETLIMITTEXT, (WPARAM) 1024, 0); } return TRUE; } BOOL ClassGeneralPage::OnSetActive() { // If pIADsObject is NULL, close dialog box if( CPropertyPage::OnSetActive() ) { if ( !pIADsObject ) { return FALSE; } else { // always enable the Apply button SetModified(TRUE); return TRUE; } } else return FALSE; } void ClassGeneralPage::Load( Cookie& CookieRef ) { // // Store the cookie object pointer. Everything // else gets loaded when the page is displayed. // pCookie = &CookieRef; return; } void ClassGeneralPage::DoDataExchange( CDataExchange *pDX ) /*** This routine picks up the object name out of the cookie and then looks up the ADSI path name out of the schema object cache. It then drives the dialog box directly from the ADS object. ***/ { HRESULT hr; CString szAdsPath; VARIANT AdsResult; DWORD dwClassType; CPropertyPage::DoDataExchange( pDX ); VariantInit( &AdsResult ); if ( !pDX->m_bSaveAndValidate ) { // // If this is not the initial load and is not // the save, just use the data that we've loaded. // if ( !fDataLoaded ) { CWaitCursor wait; // // Get the schema cache object and the actual ADS object. // Keep both around while the page is loaded. // pObject = pScopeControl->g_SchemaCache.LookupSchemaObjectByCN( pCookie->strSchemaObject, SCHMMGMT_CLASS ); if ( pObject ) { pScopeControl->GetSchemaObjectPath( pObject->commonName, szAdsPath ); if ( !szAdsPath.IsEmpty() ) { hr = ADsGetObject( (LPWSTR)(LPCWSTR)szAdsPath, IID_IADs, (void **)&pIADsObject ); } } // // If we have no ADS object, we should error out! // if ( !pIADsObject ) { DoErrMsgBox( ::GetActiveWindow(), TRUE, IDS_ERR_NO_SCHEMA_OBJECT ); // Because there is no pIADsObject, OnSetActive() will close dialog box return; } // // ObjectName - Use the ldapDisplayName to be consistent with // the other admin components. // hr = pIADsObject->Get( const_cast((LPCTSTR)g_DisplayName), &AdsResult ); if ( SUCCEEDED( hr ) ) { ASSERT( AdsResult.vt == VT_BSTR ); ObjectName = AdsResult.bstrVal; VariantClear( &AdsResult ); } // // // CommonName // hr = pIADsObject->Get( const_cast((LPCTSTR)g_CN), &AdsResult ); if ( SUCCEEDED( hr ) ) { ASSERT( AdsResult.vt == VT_BSTR ); DisplayName = AdsResult.bstrVal; VariantClear( &AdsResult ); } // // Description // hr = pIADsObject->Get( const_cast((LPCTSTR)g_Description), &AdsResult ); if ( SUCCEEDED( hr ) ) { ASSERT( AdsResult.vt == VT_BSTR ); Description = AdsResult.bstrVal; DDXDescription = AdsResult.bstrVal; VariantClear( &AdsResult ); } // // OID // hr = pIADsObject->Get( const_cast((LPCTSTR)g_GlobalClassID), &AdsResult ); if ( SUCCEEDED( hr ) ) { ASSERT( AdsResult.vt == VT_BSTR ); OidString = AdsResult.bstrVal; VariantClear( &AdsResult ); } // // Displayable // Displayable = TRUE; DDXDisplayable = TRUE; hr = pIADsObject->Get(g_ShowInAdvViewOnly, &AdsResult); if ( SUCCEEDED( hr ) ) { ASSERT( AdsResult.vt == VT_BOOL ); if ( AdsResult.boolVal == -1 ) { Displayable = FALSE; DDXDisplayable = FALSE; } VariantClear( &AdsResult ); } // // Defunct // Defunct = FALSE; DDXDefunct = FALSE; hr = pIADsObject->Get( const_cast((LPCTSTR)g_isDefunct), &AdsResult ); if ( SUCCEEDED( hr ) ) { ASSERT( AdsResult.vt == VT_BOOL ); if ( AdsResult.boolVal == -1 ) { Defunct = TRUE; DDXDefunct = TRUE; } VariantClear( &AdsResult ); } // // SysClass // hr = pIADsObject->Get( const_cast((LPCTSTR)g_SystemOnly), &AdsResult ); if ( SUCCEEDED( hr ) ) { ASSERT( AdsResult.vt == VT_BOOL ); if ( AdsResult.boolVal ) { SysClassString = g_SysClassString; } else { SysClassString = L""; } VariantClear( &AdsResult ); } else { SysClassString = L""; } // // ClassType // hr = pIADsObject->Get( const_cast((LPCTSTR)g_ObjectClassCategory), &AdsResult ); if ( SUCCEEDED( hr ) ) { ASSERT( AdsResult.vt == VT_I4 ); dwClassType = V_I4( &AdsResult ); VariantClear( &AdsResult ); switch ( dwClassType ) { case 0: ClassType = g_88Class; break; case 1: ClassType = g_StructuralClass; break; case 2: ClassType = g_AbstractClass; break; case 3: ClassType = g_AuxClass; break; default: ClassType = g_Unknown; break; } } // // Category // hr = pIADsObject->Get( const_cast((LPCTSTR)g_DefaultCategory), &AdsResult ); if ( SUCCEEDED( hr ) ) { ASSERT( V_VT(&AdsResult) == VT_BSTR ); CString strCN; if( SUCCEEDED( pScopeControl->GetLeafObjectFromDN( V_BSTR(&AdsResult), strCN ) )) { // // Look up the ldapDisplayName. // SchemaObject * pCategory = pScopeControl->g_SchemaCache.LookupSchemaObjectByCN( strCN, SCHMMGMT_CLASS ); if ( pCategory ) { Category = DDXCategory = pCategory->ldapDisplayName; pScopeControl->g_SchemaCache.ReleaseRef( pCategory ); } else { Category = DDXCategory = strCN; } } VariantClear( &AdsResult ); } // Determine if this is a category 1 object & disable read-only fields BOOL fIsSystemObject = FALSE; hr = IsCategory1Object( pIADsObject, fIsSystemObject ); if( SUCCEEDED(hr) && fIsSystemObject ) { ASSERT( GetDlgItem(IDC_CATEGORY_CHANGE) ); ASSERT( GetDlgItem(IDC_CLASS_DEACTIVATE) ); GetDlgItem(IDC_CATEGORY_CHANGE)->EnableWindow( FALSE ); GetDlgItem(IDC_CLASS_DEACTIVATE)->EnableWindow( FALSE ); } hr = DissableReadOnlyAttributes( this, pIADsObject, ctrls, sizeof(ctrls)/sizeof(ctrls[0]) ); ASSERT( SUCCEEDED(hr) ); // shouldn't fail, but unimportant, so ignore error // warn the user if this is a read/write defunct object ASSERT( GetDlgItem(IDC_CLASS_DEACTIVATE) ); if( DDXDefunct && GetDlgItem(IDC_CLASS_DEACTIVATE)->IsWindowEnabled() ) { AfxMessageBox( IDS_WARNING_DEFUNCT, MB_OK | MB_ICONINFORMATION ); } // // Remember that the data is loaded. // fDataLoaded = TRUE; } } // // Set up the dialog data exchange. // DDX_Text( pDX, IDC_CLASS_GENERAL_NAME_STATIC, ObjectName ); DDX_Text( pDX, IDC_CLASS_GENERAL_CATEGORY_COMBO, ClassType ); DDX_Text( pDX, IDC_CLASS_GENERAL_SYSCLASS_STATIC, SysClassString ); DDX_Text( pDX, IDC_CLASS_GENERAL_DESCRIPTION_EDIT, DDXDescription ); DDX_Text( pDX, IDC_CLASS_GENERAL_LDN, DisplayName ); DDX_Text( pDX, IDC_CLASS_GENERAL_OID_EDIT, OidString ); DDX_Text( pDX, IDC_CATEGORY_EDIT, DDXCategory ); DDX_Check( pDX, IDC_CLASS_GENERAL_DISPLAYABLE_CHECK, DDXDisplayable ); // Since we want the checkbox label to be positive // the value is actually the opposite of defunct int checkValue = !Defunct; DDX_Check( pDX, IDC_CLASS_DEACTIVATE, checkValue ); DDXDefunct = !checkValue; return; } BOOL ClassGeneralPage::OnApply( VOID ) { HRESULT hr; VARIANT AdsValue; BOOL fChangesMade = FALSE; BOOL fApplyAbort = FALSE; // stop later saves BOOL fApplyFailed = FALSE; // should not close the box if ( !UpdateData(TRUE) ) { return FALSE; } // // We have to flush the IADS property cache if we // have a failure so later operations won't fail because // of a bad cached attribute. // IADsPropertyList *pPropertyList; hr = pIADsObject->QueryInterface( IID_IADsPropertyList, reinterpret_cast(&pPropertyList) ); if ( FAILED( hr ) ) { pPropertyList = NULL; fApplyAbort = TRUE; } // // We only care if the description, class type, or // displayable attributes changed. // VariantInit( &AdsValue ); // // Defunct -- in case it was deactivated, activate the object first // if( !fApplyAbort && !DDXDefunct && DDXDefunct != Defunct ) { hr = ChangeDefunctState( DDXDefunct, Defunct, pPropertyList, fApplyAbort, fApplyFailed ); } if ( !fApplyAbort && DDXDescription != Description ) { V_VT(&AdsValue) = VT_BSTR; V_BSTR(&AdsValue) = const_cast((LPCTSTR)DDXDescription); if ( DDXDescription.IsEmpty() ) { hr = pIADsObject->PutEx( ADS_PROPERTY_CLEAR, const_cast((LPCTSTR)g_Description), AdsValue ); } else { hr = pIADsObject->Put( const_cast((LPCTSTR)g_Description), AdsValue ); } ASSERT( SUCCEEDED( hr ) ); hr = pIADsObject->SetInfo(); if ( SUCCEEDED( hr ) ) { pObject->description = DDXDescription; fChangesMade = TRUE; Description = DDXDescription; } else { pPropertyList->PurgePropertyList(); if( ERROR_DS_UNWILLING_TO_PERFORM == HRESULT_CODE(hr) ) { fApplyFailed = TRUE; DoErrMsgBox( ::GetActiveWindow(), TRUE, IDS_ERR_EDIT_DESC ); } else { fApplyAbort = TRUE; DoErrMsgBox( ::GetActiveWindow(), TRUE, GetErrorMessage(hr,TRUE) ); } } VariantInit( &AdsValue ); } if ( !fApplyAbort && DDXDisplayable != Displayable ) { V_VT(&AdsValue) = VT_BOOL; if ( DDXDisplayable ) { V_BOOL(&AdsValue) = 0; } else { V_BOOL(&AdsValue) = -1; } hr = pIADsObject->Put(g_ShowInAdvViewOnly, AdsValue); ASSERT( SUCCEEDED( hr ) ); hr = pIADsObject->SetInfo(); if ( FAILED( hr ) ) { pPropertyList->PurgePropertyList(); if( ERROR_DS_UNWILLING_TO_PERFORM == HRESULT_CODE(hr) ) { fApplyFailed = TRUE; DoErrMsgBox( ::GetActiveWindow(), TRUE, IDS_ERR_EDIT_DISPLAYABLE ); } else { fApplyAbort = TRUE; DoErrMsgBox( ::GetActiveWindow(), TRUE, GetErrorMessage(hr,TRUE) ); } } else { Displayable = DDXDisplayable; } VariantInit( &AdsValue ); } if ( !fApplyAbort && DDXCategory != Category ) { SchemaObject *pCategoryObject; CString DistName; hr = E_FAIL; V_VT(&AdsValue) = VT_BSTR; // // Map the commonName to the distinguished name. // pCategoryObject = pScopeControl->g_SchemaCache.LookupSchemaObjectByCN( DisplayName, SCHMMGMT_CLASS ); if ( pCategoryObject ) { pScopeControl->GetSchemaObjectPath( pCategoryObject->commonName, DistName, ADS_FORMAT_X500_DN ); V_BSTR(&AdsValue) = const_cast((LPCTSTR)DistName); hr = pIADsObject->Put( const_cast((LPCTSTR)g_DefaultCategory), AdsValue ); ASSERT( SUCCEEDED( hr ) ); hr = pIADsObject->SetInfo(); } if ( FAILED( hr ) ) { pPropertyList->PurgePropertyList(); if( ERROR_DS_UNWILLING_TO_PERFORM == HRESULT_CODE(hr) ) { fApplyFailed = TRUE; DoErrMsgBox( ::GetActiveWindow(), TRUE, IDS_ERR_EDIT_CATEGORY ); } else { fApplyAbort = TRUE; DoErrMsgBox( ::GetActiveWindow(), TRUE, GetErrorMessage(hr,TRUE) ); } } else { Category = DDXCategory; } VariantInit( &AdsValue ); } // // Defunct -- in case it was active, deactivate the object after we are done update // if( !fApplyAbort && DDXDefunct && DDXDefunct != Defunct ) { hr = ChangeDefunctState( DDXDefunct, Defunct, pPropertyList, fApplyAbort, fApplyFailed ); } if ( !fApplyAbort && fChangesMade ) { // // Call SetItem() so this gets refreshed. // SCOPEDATAITEM ScopeItem; CCookieListEntry *pEntry; BOOLEAN fFoundId = FALSE; if ( pScopeControl->g_ClassCookieList.pHead ) { pEntry = pScopeControl->g_ClassCookieList.pHead; if ( (pScopeControl->g_ClassCookieList.pHead)->pCookie == pCookie ) { fFoundId = TRUE; } else { while ( pEntry->pNext != pScopeControl->g_ClassCookieList.pHead ) { if ( pEntry->pCookie == pCookie ) { fFoundId = TRUE; break; } pEntry = pEntry->pNext; } } if ( fFoundId ) { ::ZeroMemory( &ScopeItem, sizeof(ScopeItem) ); ScopeItem.mask = SDI_STR | SDI_IMAGE | SDI_OPENIMAGE | SDI_PARAM | SDI_PARENT; ScopeItem.displayname = MMC_CALLBACK; ScopeItem.relativeID = pScopeControl->g_ClassCookieList.hParentScopeItem; ScopeItem.nState = 0; ScopeItem.lParam = reinterpret_cast((CCookie*)pCookie); ScopeItem.nImage = pScopeControl->QueryImage( *pCookie, FALSE ); ScopeItem.nOpenImage = pScopeControl->QueryImage( *pCookie, TRUE ); ScopeItem.ID = pEntry->hScopeItem; hr = pScopeControl->m_pConsoleNameSpace->SetItem( &ScopeItem ); ASSERT( SUCCEEDED( hr )); } } } if ( pPropertyList ) { pPropertyList->Release(); } return !fApplyAbort && !fApplyFailed ; // return TRUE if nothing happened } VOID ClassGeneralPage::OnButtonCategoryChange( ) { SchemaObject *pClass = NULL; INT_PTR DlgResult; AFX_MANAGE_STATE(AfxGetStaticModuleState()); // // Update any changes the user has made. // UpdateData( TRUE ); // // Start the common select dialog box. // CSchmMgmtSelect dlgSelect( pScopeControl, SELECT_CLASSES, &pClass ); DlgResult = dlgSelect.DoModal(); // // When this returns, the class schema object // pointer will be filled into pClass. // if ( ( DlgResult == IDOK ) && ( pClass != NULL ) ) { DDXCategory = pClass->ldapDisplayName; // // Push this back out to the UI. // UpdateData( FALSE ); } return; } void ClassGeneralPage::OnDeactivateClick() { if( !IsDlgButtonChecked(IDC_CLASS_DEACTIVATE) ) { if( IDOK != AfxMessageBox( IDS_WARNING_DEFUNCT_SET, MB_OKCANCEL | MB_ICONWARNING ) ) { CheckDlgButton( IDC_CLASS_DEACTIVATE, BST_UNCHECKED ); } } } HRESULT ClassGeneralPage::ChangeDefunctState( BOOL DDXDefunct, BOOL & Defunct, IADsPropertyList * pPropertyList, BOOL & fApplyAbort, BOOL & fApplyFailed ) { ASSERT( !fApplyAbort && DDXDefunct != Defunct ); VARIANT AdsValue; HRESULT hr = S_OK; VariantInit( &AdsValue ); V_VT(&AdsValue) = VT_BOOL; if ( DDXDefunct ) { V_BOOL(&AdsValue) = -1; } else { V_BOOL(&AdsValue) = 0; } hr = pIADsObject->Put( const_cast((LPCTSTR)g_isDefunct), AdsValue ); ASSERT( SUCCEEDED( hr ) ); hr = pIADsObject->SetInfo(); if ( FAILED( hr ) ) { pPropertyList->PurgePropertyList(); if( ERROR_DS_UNWILLING_TO_PERFORM == HRESULT_CODE(hr) ) { fApplyFailed = TRUE; DoErrMsgBox( ::GetActiveWindow(), TRUE, DDXDefunct ? IDS_ERR_EDIT_DEFUNCT_SET : IDS_ERR_EDIT_DEFUNCT_REMOVE ); } else { fApplyAbort = TRUE; DoErrMsgBox( ::GetActiveWindow(), TRUE, GetErrorMessage(hr,TRUE) ); } } else { pObject->isDefunct = DDXDefunct; Defunct = DDXDefunct; } return hr; }