// // compdata.cpp : Implementation of ComponentData // // This COM object is primarily concerned with // the scope pane items. // // Cory West // Copyright (c) Microsoft Corporation 1997 // #include "stdafx.h" #include "macros.h" USE_HANDLE_MACROS("SCHMMGMT(compdata.cpp)") #include "dataobj.h" #include "compdata.h" #include "cookie.h" #include "snapmgr.h" #include "schmutil.h" #include "cache.h" #include "relation.h" #include "attrpage.h" #include "advui.h" #include "aclpage.h" #include "select.h" #include "classgen.hpp" #include "newclass.hpp" #include "newattr.hpp" // // CComponentData implementation. // #include "stdcdata.cpp" // // ComponentData // ComponentData::ComponentData() : m_pRootCookie( NULL ), m_pPathname( NULL ), m_hItem( NULL ), m_fViewDefunct( false ) { // // We must refcount the root cookie, since a dataobject for it // might outlive the IComponentData. JonN 9/2/97 // m_pRootCookie = new Cookie( SCHMMGMT_SCHMMGMT ); ASSERT(NULL != m_pRootCookie); m_pRootCookie->AddRef(); g_SchemaCache.SetScopeControl( this ); SetHtmlHelpFileName (L"schmmgmt.chm"); SetCanChangeOperationsMaster( ); SetCanCreateClass( ); SetCanCreateAttribute( ); } ComponentData::~ComponentData() { SAFE_RELEASE(m_pRootCookie); SAFE_RELEASE(m_pPathname); } DEFINE_FORWARDS_MACHINE_NAME( ComponentData, m_pRootCookie ) CCookie& ComponentData::QueryBaseRootCookie() { ASSERT(NULL != m_pRootCookie); return (CCookie&)*m_pRootCookie; } STDMETHODIMP ComponentData::Initialize( LPUNKNOWN pUnknown ) { HRESULT hr = CComponentData::Initialize( pUnknown ); if( SUCCEEDED(hr) ) { ASSERT( !m_pPathname ); // create Pathname Object if( FAILED( CoCreateInstance(CLSID_Pathname, NULL, CLSCTX_INPROC_SERVER, IID_IADsPathname, (void**)&m_pPathname) ) ) { // in case of an error, ignore and later provide no escaping. ASSERT( FALSE ); SAFE_RELEASE( m_pPathname ); } } return hr; } STDMETHODIMP ComponentData::CreateComponent( LPCOMPONENT* ppComponent ) { MFC_TRY; ASSERT(ppComponent != NULL); CComObject* pObject; CComObject::CreateInstance(&pObject); ASSERT(pObject != NULL); pObject->SetComponentDataPtr( (ComponentData*)this ); return pObject->QueryInterface( IID_IComponent, reinterpret_cast(ppComponent) ); MFC_CATCH; } HRESULT ComponentData::LoadIcons( LPIMAGELIST pImageList, BOOL ) /*** This routine loads the icon resources that MMC will use. We use the image list member ImageListSetIcon to make these resources available to MMC. ***/ { AFX_MANAGE_STATE(AfxGetStaticModuleState()); HICON hIcon; HRESULT hr = S_OK; if( !IsErrorSet() ) { // // Set the generic and the last icon in case they are used. // hIcon = LoadIcon(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDI_GENERIC)); ASSERT(hIcon != NULL); hr = pImageList->ImageListSetIcon((PLONG_PTR)hIcon,iIconGeneric); ASSERT(SUCCEEDED(hr)); hr = pImageList->ImageListSetIcon((PLONG_PTR)hIcon,iIconLast); ASSERT(SUCCEEDED(hr)); // // Set the closed folder icon. // hIcon = LoadIcon(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDI_FOLDER_CLOSED)); ASSERT(hIcon != NULL); hr = pImageList->ImageListSetIcon((PLONG_PTR)hIcon,iIconFolder); ASSERT(SUCCEEDED(hr)); // // Set the class, attribute, and display specifier icon. // hIcon = LoadIcon(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDI_CLASS)); ASSERT(hIcon != NULL); hr = pImageList->ImageListSetIcon((PLONG_PTR)hIcon,iIconClass); ASSERT(SUCCEEDED(hr)); hIcon = LoadIcon(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDI_ATTRIBUTE)); ASSERT(hIcon != NULL); hr = pImageList->ImageListSetIcon((PLONG_PTR)hIcon,iIconAttribute); ASSERT(SUCCEEDED(hr)); } return S_OK; } HRESULT ComponentData::OnNotifyExpand( LPDATAOBJECT lpDataObject, BOOL bExpanding, HSCOPEITEM hParent ) /*** This routine is called in response to IComponentData:Notify with the MMCN_EXPAND notification. The argument bExpanding tells us whether the node is expanding or contracting. ***/ { ASSERT( NULL != lpDataObject && NULL != hParent && NULL != m_pConsoleNameSpace ); // // Do nothing on a contraction - we will get notifications to // destroy the disappearing nodes. // if ( !bExpanding ) return S_OK; // // This code will not work if SchmMgmt becomes an extension // since the RawCookie format will not be available. // CCookie* pBaseParentCookie = NULL; HRESULT hr = ExtractData( lpDataObject, CSchmMgmtDataObject::m_CFRawCookie, reinterpret_cast(&pBaseParentCookie), sizeof(pBaseParentCookie) ); ASSERT( SUCCEEDED(hr) ); Cookie* pParentCookie = ActiveCookie(pBaseParentCookie); ASSERT( NULL != pParentCookie ); // // If this node already has children then this expansion is a // re-expansion. We should complain, but not do anything. // if ( !((pParentCookie->m_listScopeCookieBlocks).IsEmpty()) ) { ASSERT(FALSE); return S_OK; } switch ( pParentCookie->m_objecttype ) { case SCHMMGMT_SCHMMGMT: // expanding the root, need to bind hr = _InitBasePaths(); if( SUCCEEDED(hr) ) { CheckSchemaPermissions( ); // ignoring errors } else { SetError( IDS_ERR_ERROR, IDS_ERR_NO_SCHEMA_PATH ); SetDelayedRefreshOnShow( hParent ); return S_OK; } InitializeRootTree( hParent, pParentCookie ); break; case SCHMMGMT_CLASSES: return FastInsertClassScopeCookies( pParentCookie, hParent ); break; // // These node types have no scope children. // case SCHMMGMT_CLASS: case SCHMMGMT_ATTRIBUTE: case SCHMMGMT_ATTRIBUTES: return S_OK; // // We received an unknown node type. // default: TRACE( "ComponentData::EnumerateScopeChildren bad parent type.\n" ); ASSERT( FALSE ); return S_OK; } return S_OK; } HRESULT ComponentData::OnNotifyRelease( LPDATAOBJECT, HSCOPEITEM ) { // // Since we are not a valid extension snap in, // we don't need to do anything here. // return S_OK; } HRESULT ComponentData::OnNotifyDelete( LPDATAOBJECT lpDataObject) { CThemeContextActivator activator; CCookie* pBaseParentCookie = NULL; HRESULT hr = ExtractData( lpDataObject, CSchmMgmtDataObject::m_CFRawCookie, reinterpret_cast(&pBaseParentCookie), sizeof(pBaseParentCookie) ); ASSERT( SUCCEEDED(hr) ); Cookie* pParentCookie = ActiveCookie(pBaseParentCookie); ASSERT( NULL != pParentCookie ); UINT promptID = 0; LPARAM updateType = SCHMMGMT_CLASS; if (pParentCookie->m_objecttype == SCHMMGMT_CLASS) { promptID = IDS_DELETE_CLASS_PROMPT; updateType = SCHMMGMT_CLASS; } else if (pParentCookie->m_objecttype == SCHMMGMT_ATTRIBUTE) { promptID = IDS_DELETE_ATTR_PROMPT; updateType = SCHMMGMT_ATTRIBUTES; } else { // We should never get called to delete anything but // class and attribute nodes ASSERT(FALSE); return E_FAIL; } if( IDYES == AfxMessageBox( promptID, MB_YESNO | MB_ICONWARNING )) { hr = DeleteClass( pParentCookie ); if ( SUCCEEDED(hr) ) { // Remove the node from the UI m_pConsoleNameSpace->DeleteItem( pParentCookie->m_hScopeItem, TRUE ); // Remove the node from the list bool result = g_ClassCookieList.DeleteCookie(pParentCookie); ASSERT(result); } else { CString szDeleteError; szDeleteError.Format(IDS_ERRMSG_DELETE_FAILED_CLASS, GetErrorMessage(hr, TRUE)); DoErrMsgBox( ::GetActiveWindow(), TRUE, szDeleteError ); } } return hr; } HRESULT ComponentData::DeleteClass( Cookie* pcookie ) /*** This deletes an attribute from the schema ***/ { HRESULT hr = S_OK; do { if ( !pcookie ) { hr = E_INVALIDARG; break; } SchemaObject* pObject = g_SchemaCache.LookupSchemaObjectByCN( pcookie->strSchemaObject, SCHMMGMT_CLASS ); if ( !pObject ) { hr = E_FAIL; break; } CString szAdsPath; GetSchemaObjectPath( pObject->commonName, szAdsPath ); hr = DeleteObject( szAdsPath, pcookie, g_ClassFilter ); } while (false); return hr; } // // This is where we store the string handed back to GetDisplayInfo(). // // FUTURE-2002/02/13-dantra-Schema Manager: Consider redefining the signature of QueryResultColumnText // to return LPCWSTR instead of BSTR since all callers of this method expect LPWSTR. e.g., all the calls // to const_cast are misleading and unnecessary. CString g_strResultColumnText; BSTR ComponentData::QueryResultColumnText( CCookie& basecookieref, int nCol ) { #ifndef UNICODE #error not ANSI-enabled #endif BSTR strDisplayText = NULL; Cookie& cookieref = (Cookie&)basecookieref; SchemaObject *pSchemaObject = NULL; SchemaObject *pSrcSchemaObject = NULL; switch ( cookieref.m_objecttype ) { // // These only have first column textual data. // case SCHMMGMT_SCHMMGMT: if ( COLNUM_SCHEMA_NAME == nCol ) strDisplayText = const_cast(((LPCTSTR)g_strSchmMgmt)); break; case SCHMMGMT_CLASSES: if ( COLNUM_SCHEMA_NAME == nCol ) strDisplayText = const_cast(((LPCTSTR)g_strClasses)); break; case SCHMMGMT_ATTRIBUTES: if ( COLNUM_SCHEMA_NAME == nCol ) strDisplayText = const_cast(((LPCTSTR)g_strAttributes)); break; case SCHMMGMT_CLASS: // // These display names come out of the schema cache objects. // pSchemaObject = g_SchemaCache.LookupSchemaObjectByCN( cookieref.strSchemaObject, SCHMMGMT_CLASS ); // // If there is no cache object, we just have to return UNKNOWN. // if ( !pSchemaObject ) { ASSERT(FALSE); strDisplayText = const_cast( (LPCTSTR)g_Unknown ); break; } // // Otherwise, return the appropriate text for the column. // if ( COLNUM_CLASS_NAME == nCol ) { strDisplayText = const_cast((LPCTSTR)pSchemaObject->ldapDisplayName); } else if ( COLNUM_CLASS_TYPE == nCol ) { switch ( pSchemaObject->dwClassType ) { case 0: strDisplayText = const_cast(((LPCTSTR)g_88Class)); break; case 1: strDisplayText = const_cast(((LPCTSTR)g_StructuralClass)); break; case 2: strDisplayText = const_cast(((LPCTSTR)g_AbstractClass)); break; case 3: strDisplayText = const_cast(((LPCTSTR)g_AuxClass)); break; default: strDisplayText = const_cast(((LPCTSTR)g_Unknown)); break; } } else if ( COLNUM_CLASS_STATUS == nCol ) { if ( pSchemaObject->isDefunct ) { strDisplayText = const_cast( (LPCTSTR)g_Defunct ); } else { strDisplayText = const_cast( (LPCTSTR)g_Active ); } } else if ( COLNUM_CLASS_DESCRIPTION == nCol ) { strDisplayText = const_cast((LPCTSTR)pSchemaObject->description); } break; case SCHMMGMT_ATTRIBUTE: pSchemaObject = g_SchemaCache.LookupSchemaObjectByCN( cookieref.strSchemaObject, SCHMMGMT_ATTRIBUTE ); // // If there is no cache object, we just have to return UNKNOWN. // if ( !pSchemaObject ) { ASSERT(FALSE); strDisplayText = const_cast( (LPCTSTR)g_Unknown ); break; } // // Otherwise, return the appropriate text for the column. // if ( (cookieref.pParentCookie)->m_objecttype == SCHMMGMT_ATTRIBUTES ) { if ( COLNUM_ATTRIBUTE_NAME == nCol ) { strDisplayText = const_cast((LPCTSTR)pSchemaObject->ldapDisplayName); } else if ( COLNUM_ATTRIBUTE_TYPE == nCol ) { strDisplayText = const_cast( (LPCTSTR)g_Syntax[pSchemaObject->SyntaxOrdinal].m_strSyntaxName ); } else if ( COLNUM_ATTRIBUTE_STATUS == nCol) { if ( pSchemaObject->isDefunct ) { strDisplayText = const_cast( (LPCTSTR)g_Defunct ); } else { strDisplayText = const_cast( (LPCTSTR)g_Active ); } } else if ( COLNUM_ATTRIBUTE_SYSTEM == nCol ) { strDisplayText = const_cast((LPCTSTR)pSchemaObject->description); } else if ( COLNUM_ATTRIBUTE_DESCRIPTION == nCol ) { strDisplayText = const_cast((LPCTSTR)pSchemaObject->description); } else if ( COLNUM_ATTRIBUTE_PARENT == nCol ) { pSrcSchemaObject = g_SchemaCache.LookupSchemaObjectByCN( cookieref.strSrcSchemaObject, SCHMMGMT_CLASS ); // // If there is no cache object, we just have to return UNKNOWN. // if ( !pSchemaObject ) { ASSERT(FALSE); strDisplayText = const_cast( (LPCTSTR)g_Unknown ); break; } // // Otherwise, return the appropriate text for the column. // strDisplayText = const_cast((LPCTSTR)pSrcSchemaObject->ldapDisplayName); } } else { if ( COLNUM_CLASS_ATTRIBUTE_NAME == nCol ) { strDisplayText = const_cast((LPCTSTR)pSchemaObject->ldapDisplayName); } else if ( COLNUM_CLASS_ATTRIBUTE_TYPE == nCol ) { if ( cookieref.Mandatory ) { strDisplayText = const_cast(((LPCTSTR)g_MandatoryAttribute)); } else { strDisplayText = const_cast(((LPCTSTR)g_OptionalAttribute)); } } else if ( COLNUM_CLASS_ATTRIBUTE_SYSTEM == nCol ) { if ( cookieref.System ) { strDisplayText = const_cast(((LPCTSTR)g_Yes)); } else { strDisplayText = const_cast(((LPCTSTR)g_No)); } } else if ( COLNUM_CLASS_ATTRIBUTE_DESCRIPTION == nCol ) { strDisplayText = const_cast((LPCTSTR)pSchemaObject->description); } else if ( COLNUM_CLASS_ATTRIBUTE_PARENT == nCol ) { pSrcSchemaObject = g_SchemaCache.LookupSchemaObjectByCN( cookieref.strSrcSchemaObject, SCHMMGMT_CLASS ); // // If there is no cache object, we just have to return UNKNOWN. // if ( !pSchemaObject ) { ASSERT(FALSE); strDisplayText = const_cast( (LPCTSTR)g_Unknown ); break; } // // Otherwise, return the appropriate text for the column. // strDisplayText = const_cast((LPCTSTR)pSrcSchemaObject->ldapDisplayName); } } break; default: TRACE( "ComponentData::QueryResultColumnText bad cookie.\n" ); ASSERT( FALSE ); break; } // // Release the schema cache references. // if ( pSchemaObject ) { g_SchemaCache.ReleaseRef( pSchemaObject ); } if ( pSrcSchemaObject ) { g_SchemaCache.ReleaseRef( pSrcSchemaObject ); } // // Return the appropriate display string. // if ( strDisplayText ) { return strDisplayText; } return L""; } // // Given a cookie, this returns the icon to display for that cookie. // int ComponentData::QueryImage( CCookie& basecookieref, BOOL ) { Cookie& cookieref = (Cookie&)basecookieref; switch ( cookieref.m_objecttype ) { case SCHMMGMT_SCHMMGMT: case SCHMMGMT_CLASSES: case SCHMMGMT_ATTRIBUTES: return iIconFolder; break; case SCHMMGMT_CLASS: return iIconClass; break; case SCHMMGMT_ATTRIBUTE: return iIconAttribute; break; default: TRACE( "ComponentData::QueryImage bad parent type.\n" ); ASSERT( FALSE ); break; } return iIconGeneric; } // // This routines tells MMC whether or not there are // property pages and menus for this item. // STDMETHODIMP ComponentData::AddMenuItems( LPDATAOBJECT piDataObject, LPCONTEXTMENUCALLBACK piCallback, long*) { CCookie* pBaseParentCookie = NULL; HRESULT hr = ExtractData( piDataObject, CSchmMgmtDataObject::m_CFRawCookie, reinterpret_cast(&pBaseParentCookie), sizeof(pBaseParentCookie) ); ASSERT( SUCCEEDED(hr) ); Cookie* pParentCookie = ActiveCookie(pBaseParentCookie); ASSERT( NULL != pParentCookie ); AFX_MANAGE_STATE(AfxGetStaticModuleState()); LoadGlobalCookieStrings(); switch (pParentCookie->m_objecttype) { case SCHMMGMT_SCHMMGMT: // Root Folder { VERIFY( SUCCEEDED( _InsertMenuHelper( piCallback, CCM_INSERTIONPOINTID_PRIMARY_TOP, SCHEMA_RETARGET))); VERIFY( SUCCEEDED( _InsertMenuHelper( piCallback, CCM_INSERTIONPOINTID_PRIMARY_TOP, SCHEMA_EDIT_FSMO, !IsErrorSet() && IsSchemaLoaded()))); VERIFY( SUCCEEDED( _InsertMenuHelper( piCallback, CCM_INSERTIONPOINTID_PRIMARY_TOP, SCHEMA_SECURITY, !IsErrorSet() && IsSchemaLoaded()))); VERIFY( SUCCEEDED( _InsertMenuHelper( piCallback, CCM_INSERTIONPOINTID_PRIMARY_TOP, SCHEMA_REFRESH, !IsErrorSet() && IsSchemaLoaded()))); break; } case SCHMMGMT_CLASSES: // classes folder { // 285448, 293449 VERIFY( SUCCEEDED( _InsertMenuHelper( piCallback, CCM_INSERTIONPOINTID_PRIMARY_TOP, NEW_CLASS, !IsErrorSet() && CanCreateClass()))); if( !IsErrorSet() && CanCreateClass() ) // add only if enabsed VERIFY( SUCCEEDED( _InsertMenuHelper( piCallback, CCM_INSERTIONPOINTID_PRIMARY_NEW, CLASSES_CREATE_CLASS))); break; } case SCHMMGMT_ATTRIBUTES: // attributes folder { VERIFY( SUCCEEDED( _InsertMenuHelper( piCallback, CCM_INSERTIONPOINTID_PRIMARY_TOP, NEW_ATTRIBUTE, !IsErrorSet() && CanCreateAttribute()))); if( !IsErrorSet() && CanCreateAttribute() ) // add only if enabsed VERIFY( SUCCEEDED( _InsertMenuHelper( piCallback, CCM_INSERTIONPOINTID_PRIMARY_NEW, ATTRIBUTES_CREATE_ATTRIBUTE))); break; } default: { // could be class or attribute item } } // switch return S_OK; } STDMETHODIMP ComponentData::Command(long lCommandID, LPDATAOBJECT piDataObject) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); CThemeContextActivator activator; switch ( lCommandID ) { case NEW_ATTRIBUTE: case ATTRIBUTES_CREATE_ATTRIBUTE: { CDialog warn(IDD_CREATE_WARN); if (IDOK == warn.DoModal()) { CreateAttributeDialog(this, piDataObject).DoModal(); } break; } case NEW_CLASS: case CLASSES_CREATE_CLASS: { CDialog warn(IDD_CREATE_WARN); if (IDOK == warn.DoModal()) { DoNewClassDialog(*this); } break; } case SCHEMA_RETARGET: _OnRetarget(piDataObject); break; case SCHEMA_EDIT_FSMO: _OnEditFSMO(); break; case SCHEMA_REFRESH: HRESULT hr; hr=_OnRefresh(piDataObject); if(FAILED(hr)) { if( E_FAIL == hr ) DoErrMsgBox( ::GetActiveWindow(), TRUE, IDS_ERR_NO_SCHEMA_PATH ); else DoErrMsgBox( ::GetActiveWindow(), TRUE, GetErrorMessage(hr,TRUE) ); } break; case SCHEMA_SECURITY: _OnSecurity(); break; default: break; } return S_OK; } STDMETHODIMP ComponentData::QueryPagesFor( LPDATAOBJECT pDataObject ) { MFC_TRY; if ( NULL == pDataObject ) { ASSERT(FALSE); return E_POINTER; } HRESULT hr; CCookie* pBaseParentCookie = NULL; hr = ExtractData( pDataObject, CSchmMgmtDataObject::m_CFRawCookie, reinterpret_cast(&pBaseParentCookie), sizeof(pBaseParentCookie) ); ASSERT( SUCCEEDED(hr) ); Cookie* pParentCookie = ActiveCookie(pBaseParentCookie); ASSERT( NULL != pParentCookie ); if ( pParentCookie->m_objecttype == SCHMMGMT_CLASS ) { return S_OK; } return S_FALSE; MFC_CATCH; } // // This adds pages to the property sheet if appropriate. // The handle parameter must be saved in the property page // object to notify the parent when modified. // STDMETHODIMP ComponentData::CreatePropertyPages( LPPROPERTYSHEETCALLBACK pCallBack, LONG_PTR, LPDATAOBJECT pDataObject ) { MFC_TRY; CWaitCursor wait; // // Validate the parameters. // if ( ( NULL == pCallBack ) || ( NULL == pDataObject ) ) { ASSERT(FALSE); return E_POINTER; } // // Make sure this is a class object that we are calling up. // CCookie* pBaseParentCookie = NULL; HRESULT hr = ExtractData( pDataObject, CSchmMgmtDataObject::m_CFRawCookie, reinterpret_cast(&pBaseParentCookie), sizeof(pBaseParentCookie) ); ASSERT( SUCCEEDED(hr) ); hr = S_OK; Cookie* pParentCookie = ActiveCookie(pBaseParentCookie); ASSERT( NULL != pParentCookie ); ASSERT( pParentCookie->m_objecttype == SCHMMGMT_CLASS ); // // Create the page. // HPROPSHEETPAGE hPage; ClassGeneralPage *pGeneralPage = new ClassGeneralPage( this ); ClassRelationshipPage *pRelationshipPage = new ClassRelationshipPage( this, pDataObject ); ClassAttributePage *pAttributesPage = new ClassAttributePage( this, pDataObject ); if ( pGeneralPage ) { pGeneralPage->Load( *pParentCookie ); MMCPropPageCallback( &pGeneralPage->m_psp ); hPage = MyCreatePropertySheetPage( &pGeneralPage->m_psp ); pCallBack->AddPage(hPage); } if ( pRelationshipPage ) { pRelationshipPage->Load( *pParentCookie ); MMCPropPageCallback( &pRelationshipPage->m_psp ); hPage = MyCreatePropertySheetPage( &pRelationshipPage->m_psp ); pCallBack->AddPage(hPage); } if ( pAttributesPage ) { pAttributesPage->Load( *pParentCookie ); MMCPropPageCallback( &pAttributesPage->m_psp ); hPage = MyCreatePropertySheetPage( &pAttributesPage->m_psp ); pCallBack->AddPage(hPage); } // // Add the ACL editor page. // SchemaObject * pObject = NULL; CAclEditorPage * pAclPage = NULL; CString szAdsPath; pObject = g_SchemaCache.LookupSchemaObjectByCN( pParentCookie->strSchemaObject, SCHMMGMT_CLASS ); if ( pObject ) { GetSchemaObjectPath( pObject->commonName, szAdsPath ); if ( !szAdsPath.IsEmpty() ) { hr = CAclEditorPage::CreateInstance( &pAclPage, szAdsPath, pParentCookie->strSchemaObject ); if ( SUCCEEDED(hr) ) { ASSERT( pAclPage ); pCallBack->AddPage( pAclPage->CreatePage() ); } else { DoErrMsgBox( ::GetActiveWindow(), TRUE, GetErrorMessage(hr) ); hr = S_FALSE; // tell mmc to cancel "show prop pages" } } } return hr; MFC_CATCH; } HRESULT ComponentData::FastInsertClassScopeCookies( Cookie* pParentCookie, HSCOPEITEM hParentScopeItem ) /*** On an expand for the "Classes" node, this inserts the class scope items from the cache. pParentCookie is the cookie for the parent object. hParentScopeItem is the HSCOPEITEM for the parent. ****/ { HRESULT hr; SCOPEDATAITEM ScopeItem; Cookie* pNewCookie; LPCWSTR lpcszMachineName = pParentCookie->QueryNonNULLMachineName(); SchemaObject *pObject, *pHead; // // Initialize the scope item. // // FUTURE-2002-03/94/2002-dantra-Although this is a safe usage of ZeroMemory, suggest changing // the definition SCOPEDATAITEM ScopeItem = {0} and removing the ZeroMemory call. ::ZeroMemory( &ScopeItem, sizeof(ScopeItem) ); ScopeItem.mask = SDI_STR | SDI_IMAGE | SDI_OPENIMAGE | SDI_STATE | SDI_PARAM | SDI_PARENT | SDI_CHILDREN; ScopeItem.displayname = MMC_CALLBACK; ScopeItem.relativeID = hParentScopeItem; ScopeItem.nState = TVIS_EXPANDED; ScopeItem.cChildren = 0; // // Remember the parent cookie and scope item; we // may need to insert later as a refresh. // g_ClassCookieList.pParentCookie = pParentCookie; g_ClassCookieList.hParentScopeItem = hParentScopeItem; // // Rather than having a clean class interface to the cache, we // walk the cache data structures ourselves. This isn't super // clean, but it's simple. // // Since we do this, we have to make sure that the cache is loaded. // // This is just like in // Component::FastInsertAttributeResultCookies // g_SchemaCache.LoadCache(); pObject = g_SchemaCache.pSortedClasses; // // If there's no sorted list, we can't insert anything!!!! // We must return an error or else the console will never // ask us again for scope items. // if ( !pObject ) { ASSERT( FALSE ); // @@ spb: bad message, this could occur if the schema // queries were empty... DoErrMsgBox( ::GetActiveWindow(), TRUE, IDS_ERR_NO_SCHEMA_PATH ); return E_FAIL; } // // Do the insert. // pHead = pObject; do { // // Insert this result. // if ( m_fViewDefunct || !pObject->isDefunct ) { pNewCookie= new Cookie( SCHMMGMT_CLASS, lpcszMachineName ); if ( pNewCookie ) { pNewCookie->pParentCookie = pParentCookie; pNewCookie->strSchemaObject = pObject->commonName; pParentCookie->m_listScopeCookieBlocks.AddHead( (CBaseCookieBlock*)pNewCookie ); ScopeItem.lParam = reinterpret_cast((CCookie*)pNewCookie); ScopeItem.nImage = QueryImage( *pNewCookie, FALSE ); ScopeItem.nOpenImage = QueryImage( *pNewCookie, TRUE ); hr = m_pConsoleNameSpace->InsertItem(&ScopeItem); if ( SUCCEEDED(hr) ) { pNewCookie->m_hScopeItem = ScopeItem.ID; g_ClassCookieList.AddCookie( pNewCookie, ScopeItem.ID ); } else { delete pNewCookie; } } } pObject = pObject->pSortedListFlink; } while ( pObject != pHead ); return S_OK; } // // Refreshing the scope pane view. // VOID ComponentData::RefreshScopeView( VOID ) /*** When we reload the schema cache and the "Classes" folder has been opened, this routine deletes all the scope items from view and re-inserts them. This makes new classes visible to the user. ***/ { HRESULT hr; CCookieListEntry *pHead = g_ClassCookieList.pHead; CCookieListEntry *pCurrent; if ( pHead != NULL ) { // // Remove all the scope pane items. // pCurrent = pHead; while ( pCurrent->pNext != pHead ) { hr = m_pConsoleNameSpace->DeleteItem( pCurrent->pNext->hScopeItem, TRUE ); ASSERT( SUCCEEDED( hr )); // // This should cause the cookie to be deleted. // pCurrent->pNext->pCookie->Release(); pCurrent = pCurrent->pNext; } // // Remove the head of the list. // hr = m_pConsoleNameSpace->DeleteItem( pHead->hScopeItem, TRUE ); ASSERT( SUCCEEDED( hr )); pHead->pCookie->Release(); // // Delete the class cookie list. // g_ClassCookieList.DeleteAll(); } // // Re-insert them from the cache if this node has // been expanded at some point. We have to do this // because the console doesn't ever seem to ask // again. // if ( g_ClassCookieList.pParentCookie ) { FastInsertClassScopeCookies( g_ClassCookieList.pParentCookie, g_ClassCookieList.hParentScopeItem ); } return; } void ComponentData::_OnRetarget(LPDATAOBJECT lpDataObject) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); CThemeContextActivator activator; MyBasePathsInfo oldBasePathsInfo; MyBasePathsInfo newBasePathsInfo; HRESULT hr = S_OK; HWND hWndParent = NULL; BOOL fWasErrorSet = IsErrorSet(); m_pConsole->GetMainWindow(&hWndParent); CChangeDCDialog dlg(GetBasePathsInfo(), hWndParent); do { if (IDOK != dlg.DoModal()) break; CWaitCursor wait; // save the old path just in case oldBasePathsInfo.InitFromInfo( GetBasePathsInfo() ); // attempt to bind hr = newBasePathsInfo.InitFromName(dlg.GetNewDCName()); BREAK_ON_FAILED_HRESULT(hr); // switch focus GetBasePathsInfo()->InitFromInfo(&newBasePathsInfo); // invalidate the whole tree hr = _OnRefresh(lpDataObject); BREAK_ON_FAILED_HRESULT(hr); SetError( 0, 0 ); // Reset the ResultViewType if( IsErrorSet() != fWasErrorSet ) { ASSERT( SCHMMGMT_SCHMMGMT == QueryRootCookie().m_objecttype ); hr = m_pConsole->SelectScopeItem( QueryRootCookie().m_hScopeItem ); ASSERT_BREAK_ON_FAILED_HRESULT(hr); // // Add children nodes if needed // if ( (QueryRootCookie().m_listScopeCookieBlocks).IsEmpty() ) { InitializeRootTree( QueryRootCookie().m_hScopeItem, &QueryRootCookie() ); } } // Update the root display name if (GetBasePathsInfo()->GetServerName()) { CString strDisplayName; strDisplayName.LoadString(IDS_SCOPE_SCHMMGMT); strDisplayName += L" ["; strDisplayName += GetBasePathsInfo()->GetServerName(); strDisplayName += L"]"; SCOPEDATAITEM RootItem; // FUTURE-2002-03/94/2002-dantra-Although this is a safe usage of ZeroMemory, suggest changing // the definition SCOPEDATAITEM RootItem = {0} and removing the ZeroMemory call. ::ZeroMemory( &RootItem, sizeof(RootItem)); RootItem.mask = SDI_STR | SDI_PARAM; RootItem.displayname = const_cast((PCWSTR)strDisplayName); RootItem.ID = QueryRootCookie().m_hScopeItem; hr = m_pConsoleNameSpace->SetItem(&RootItem); ASSERT(SUCCEEDED(hr)); } } while( FALSE ); if( FAILED(hr) ) { DoErrMsgBox(::GetActiveWindow(), TRUE, IDS_ERR_CANT_RETARGET, hr); // restoring... GetBasePathsInfo()->InitFromInfo(&oldBasePathsInfo); } } void ComponentData::_OnEditFSMO() { AFX_MANAGE_STATE(AfxGetStaticModuleState()); CThemeContextActivator activator; HWND hWndParent; // Enable hourglass CWaitCursor wait; m_pConsole->GetMainWindow(&hWndParent); CComPtr spIDisplayHelp; m_pConsole->QueryInterface (IID_IDisplayHelp, (void **)&spIDisplayHelp); ASSERT(spIDisplayHelp != NULL); CEditFsmoDialog dlg(GetBasePathsInfo(), hWndParent, spIDisplayHelp, CanChangeOperationsMaster() ); dlg.DoModal(); } HRESULT ComponentData::_OnRefresh(LPDATAOBJECT lpDataObject) { CWaitCursor wait; HRESULT hr = S_OK; do { // // Force the ds to update the schema cache. // hr = ForceDsSchemaCacheUpdate(); // S_FALSE here means Schema is read-only, cannot force refresh. Ignoring... if(hr==S_FALSE) hr = S_OK; BREAK_ON_FAILED_HRESULT(hr); // nothing shuld fail after this point g_SchemaCache.FreeAll(); g_SchemaCache.LoadCache(); RefreshScopeView(); m_pConsole->UpdateAllViews( lpDataObject, SCHMMGMT_SCHMMGMT, SCHMMGMT_UPDATEVIEW_REFRESH); } while( FALSE ); return hr; } void ComponentData::_OnSecurity() { HRESULT hr = S_OK; HWND hWndParent = NULL; CString szSchemaPath; do { // Enable hourglass CWaitCursor wait; CComPtr spSchemaContainer; GetBasePathsInfo()->GetSchemaPath(szSchemaPath); hr = SchemaOpenObject( (LPWSTR)(LPCWSTR)szSchemaPath, IID_IADs, (void**) &spSchemaContainer); BREAK_ON_FAILED_HRESULT(hr); CComBSTR path; hr = spSchemaContainer->get_ADsPath(&path); BREAK_ON_FAILED_HRESULT(hr); CComBSTR classname; hr = spSchemaContainer->get_Class(&classname); BREAK_ON_FAILED_HRESULT(hr); m_pConsole->GetMainWindow(&hWndParent); // Determine if the registry is accessible & schema modifications are allowed PWSTR pszFsmoOwnerServerName = 0; MyBasePathsInfo fsmoOwnerInfo; HRESULT hr2 = FindFsmoOwner(GetBasePathsInfo(), SCHEMA_FSMO, &fsmoOwnerInfo, &pszFsmoOwnerServerName); // If we have the server name, try to read the registry BOOL fMarkReadOnly = ( FAILED(hr2) || pszFsmoOwnerServerName == 0 || pszFsmoOwnerServerName[0] == 0); // Ignore hr code. hr2 = DSEditSecurity( hWndParent, path, classname, fMarkReadOnly ? DSSI_READ_ONLY : 0, NULL, NULL, NULL, 0); } while (0); if (FAILED(hr)) { m_pConsole->GetMainWindow(&hWndParent); if( szSchemaPath.IsEmpty() ) DoErrMsgBox( hWndParent, TRUE, IDS_ERR_NO_SCHEMA_PATH ); else DoErrMsgBox( hWndParent, TRUE, GetErrorMessage(hr,TRUE) ); } } HRESULT ComponentData::_InitBasePaths() { CWaitCursor wait; // try to get a bind to a generic DC HRESULT hr = GetBasePathsInfo()->InitFromName(NULL); if (FAILED(hr)) return hr; // ADSI failed, cannot get any server // from the current server, try to bind to the schema FSMO owner MyBasePathsInfo fsmoBasePathsInfo; PWSTR pszFsmoOwnerServerName = 0; hr = FindFsmoOwner(GetBasePathsInfo(), SCHEMA_FSMO, &fsmoBasePathsInfo, &pszFsmoOwnerServerName); delete[] pszFsmoOwnerServerName; pszFsmoOwnerServerName = 0; if (FAILED(hr)) return S_OK; // still good keep what we have (even though not the FSMO owner) // got it, we switch focus return GetBasePathsInfo()->InitFromInfo(&fsmoBasePathsInfo); } STDMETHODIMP ComponentData::GetLinkedTopics(LPOLESTR* lpCompiledHelpFile) { if (lpCompiledHelpFile == NULL) return E_INVALIDARG; CString szHelpFilePath; LPTSTR lpszBuffer = szHelpFilePath.GetBuffer(2*MAX_PATH); UINT nLen = ::GetSystemWindowsDirectory(lpszBuffer, 2*MAX_PATH); // NTRAID#NTBUG9-565360-2002/03/05-dantra-not checking the result of GetSystemWindowsDirectory() if (nLen == 0) return E_FAIL; szHelpFilePath.ReleaseBuffer(); szHelpFilePath += L"\\help\\ADconcepts.chm"; UINT nBytes = (szHelpFilePath.GetLength()+1) * sizeof(WCHAR); *lpCompiledHelpFile = (LPOLESTR)::CoTaskMemAlloc(nBytes); if (*lpCompiledHelpFile != NULL) { memcpy(*lpCompiledHelpFile, (LPCWSTR)szHelpFilePath, nBytes); } return S_OK; } const WCHAR CN_EQUALS[] = L"CN="; HRESULT ComponentData::GetSchemaObjectPath( const CString & strCN, CString & strPath, ADS_FORMAT_ENUM formatType /* = ADS_FORMAT_X500 */ ) { HRESULT hr = E_FAIL; do { if( !m_pPathname ) break; CComBSTR bstr; // Escape it hr = m_pPathname->GetEscapedElement( 0, CComBSTR( CString(CN_EQUALS) + strCN ), &bstr ); BREAK_ON_FAILED_HRESULT(hr); // set the dn without the leaf node. hr = m_pPathname->Set( CComBSTR( CString( GetBasePathsInfo()->GetProviderAndServerName()) + GetBasePathsInfo()->GetSchemaNamingContext() ), ADS_SETTYPE_FULL ); BREAK_ON_FAILED_HRESULT(hr); // add new leaf element hr = m_pPathname->AddLeafElement( bstr ); BREAK_ON_FAILED_HRESULT(hr); // the result should be property escaped hr = m_pPathname->put_EscapedMode( ADS_ESCAPEDMODE_DEFAULT ); BREAK_ON_FAILED_HRESULT(hr); // the full thing is needed hr = m_pPathname->SetDisplayType( ADS_DISPLAY_FULL ); BREAK_ON_FAILED_HRESULT(hr); // get the final result. hr = m_pPathname->Retrieve( formatType, &bstr ); BREAK_ON_FAILED_HRESULT(hr); strPath = bstr; } while( FALSE ); ASSERT( SUCCEEDED(hr) ); return hr; } HRESULT ComponentData::GetLeafObjectFromDN( const BSTR bstrDN, CString & strCN ) { HRESULT hr = E_FAIL; do { if( !m_pPathname ) break; // set the full DN. hr = m_pPathname->Set( bstrDN, ADS_SETTYPE_DN ); BREAK_ON_FAILED_HRESULT(hr); // the result should not be escaped hr = m_pPathname->put_EscapedMode( ADS_ESCAPEDMODE_OFF_EX ); BREAK_ON_FAILED_HRESULT(hr); // just the value please hr = m_pPathname->SetDisplayType( ADS_DISPLAY_VALUE_ONLY ); BREAK_ON_FAILED_HRESULT(hr); CComBSTR bstrCN; // extract the leaf node hr = m_pPathname->Retrieve( ADS_FORMAT_LEAF, &bstrCN ); BREAK_ON_FAILED_HRESULT(hr); strCN = bstrCN; } while( FALSE ); ASSERT( SUCCEEDED(hr) ); // this function should never fail (in theory) return hr; } // // Determine what operations are allowed. Optionally returns IADs * to Schema Container // if the path is not present, the returned value is E_FAIL // HRESULT ComponentData::CheckSchemaPermissions( IADs ** ppADs /* = NULL */ ) { HRESULT hr = S_OK; CComPtr ipADs; CString szSchemaContainerPath; CStringList strlist; ASSERT( !ppADs || !(*ppADs) ); // if present, must point to NULL do { // // Disable new attrib/class menu items // SetCanCreateClass( FALSE ); SetCanCreateAttribute( FALSE ); SetCanChangeOperationsMaster( FALSE ); // // Get the schema container path. // GetBasePathsInfo()->GetSchemaPath( szSchemaContainerPath ); if( szSchemaContainerPath.IsEmpty() ) { hr = E_FAIL; break; } // // Open the schema container. // hr = SchemaOpenObject( (LPWSTR)(LPCWSTR)szSchemaContainerPath, IID_IADs, (void **)&ipADs ); BREAK_ON_FAILED_HRESULT(hr); // extract the list of allowed attributes hr = GetStringListElement( ipADs, &g_allowedAttributesEffective, strlist ); if( SUCCEEDED(hr) ) { // search for needed attributes for( POSITION pos = strlist.GetHeadPosition(); pos != NULL; ) { CString * pstr = &strlist.GetNext( pos ); if( !pstr->CompareNoCase( g_fsmoRoleOwner ) ) { SetCanChangeOperationsMaster( TRUE ); break; } } } // extract the list of allowed classes hr = GetStringListElement( ipADs, &g_allowedChildClassesEffective, strlist ); if( SUCCEEDED(hr) ) { // search for needed attributes for( POSITION pos = strlist.GetHeadPosition(); pos != NULL; ) { CString * pstr = &strlist.GetNext( pos ); if( !pstr->CompareNoCase( g_AttributeFilter ) ) { SetCanCreateAttribute( TRUE ); if( CanCreateClass() ) break; } else if( !pstr->CompareNoCase( g_ClassFilter ) ) { SetCanCreateClass( TRUE ); if( CanCreateAttribute() ) break; } } } } while( FALSE ); if( ppADs ) { *ppADs = ipADs; if( *ppADs ) (*ppADs)->AddRef(); } return hr; } //////////////////////////////////////////////////////////////////// // // Error handling // // Set's error title & body text. Call it with 0, 0 to remove void ComponentData::SetError( UINT idsErrorTitle, UINT idsErrorText ) { if( idsErrorTitle ) m_sErrorTitle.LoadString( idsErrorTitle ); else m_sErrorTitle.Empty(); if( idsErrorText ) m_sErrorText.LoadString( idsErrorText ); else m_sErrorText.Empty(); } VOID ComponentData::InitializeRootTree( HSCOPEITEM hParent, Cookie * pParentCookie ) { // // This node has the two static nodes // for Classes and Attributes. // HRESULT hr = S_OK; LPCWSTR lpcszMachineName = pParentCookie->QueryNonNULLMachineName(); // Update the name of the root to contain the servername we are bound to if (GetBasePathsInfo()->GetServerName()) { CString strDisplayName; strDisplayName.LoadString(IDS_SCOPE_SCHMMGMT); strDisplayName += L" ["; strDisplayName += GetBasePathsInfo()->GetServerName(); strDisplayName += L"]"; SCOPEDATAITEM RootItem; // FUTURE-2002-03/94/2002-dantra-Although this is a safe usage of ZeroMemory, suggest changing // the definition SCOPEDATAITEM RootItem = {0} and removing the ZeroMemory call. ::ZeroMemory( &RootItem, sizeof(RootItem)); RootItem.mask = SDI_STR | SDI_PARAM; RootItem.displayname = const_cast((PCWSTR)strDisplayName); RootItem.ID = hParent; hr = m_pConsoleNameSpace->SetItem(&RootItem); ASSERT(SUCCEEDED(hr)); } // Set the HSCOPEITEMID for the root because it may not be set if the user // just hit the + sign instead of clicking on the root QueryRootCookie().m_hScopeItem = hParent; SCOPEDATAITEM ScopeItem; // FUTURE-2002-03/94/2002-dantra-Although this is a safe usage of ZeroMemory, suggest changing // the definition SCOPEDATAITEM ScopeItem = {0} and removing the ZeroMemory call. ::ZeroMemory( &ScopeItem, sizeof(ScopeItem) ); ScopeItem.mask = SDI_STR | SDI_IMAGE | SDI_OPENIMAGE | SDI_STATE | SDI_PARAM | SDI_PARENT; ScopeItem.displayname = MMC_CALLBACK; ScopeItem.relativeID = hParent; ScopeItem.nState = 0; LoadGlobalCookieStrings(); // // Create new cookies for the static scope items. // We're doing something funky with the cookie cast. // Cookie* pNewCookie; pNewCookie= new Cookie( SCHMMGMT_CLASSES, lpcszMachineName ); pParentCookie->m_listScopeCookieBlocks.AddHead( (CBaseCookieBlock*)pNewCookie ); ScopeItem.lParam = reinterpret_cast((CCookie*)pNewCookie); ScopeItem.nImage = QueryImage( *pNewCookie, FALSE ); ScopeItem.nOpenImage = QueryImage( *pNewCookie, TRUE ); hr = m_pConsoleNameSpace->InsertItem(&ScopeItem); ASSERT(SUCCEEDED(hr)); pNewCookie->m_hScopeItem = ScopeItem.ID; pNewCookie = new Cookie( SCHMMGMT_ATTRIBUTES, lpcszMachineName ); pParentCookie->m_listScopeCookieBlocks.AddHead( (CBaseCookieBlock*)pNewCookie ); ScopeItem.lParam = reinterpret_cast((CCookie*)pNewCookie); ScopeItem.nImage = QueryImage( *pNewCookie, FALSE ); ScopeItem.nOpenImage = QueryImage( *pNewCookie, TRUE ); // turn of the + on the Attributes node ScopeItem.mask |= SDI_CHILDREN; ScopeItem.cChildren = 0; hr = m_pConsoleNameSpace->InsertItem(&ScopeItem); ASSERT(SUCCEEDED(hr)); pNewCookie->m_hScopeItem = ScopeItem.ID; // // Force Cache load (if not done already) // g_SchemaCache.LoadCache(); }