|
|
//
// compdata.cpp : Implementation of ComponentData
//
// This COM object is primarily concerned with
// the scope pane items.
//
// Cory West <[email protected]>
// 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<Component>* pObject; CComObject<Component>::CreateInstance(&pObject); ASSERT(pObject != NULL);
pObject->SetComponentDataPtr( (ComponentData*)this );
return pObject->QueryInterface( IID_IComponent, reinterpret_cast<void**>(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<PBYTE>(&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<PBYTE>(&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<BSTR> 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<BSTR>(((LPCTSTR)g_strSchmMgmt)); break;
case SCHMMGMT_CLASSES:
if ( COLNUM_SCHEMA_NAME == nCol ) strDisplayText = const_cast<BSTR>(((LPCTSTR)g_strClasses)); break;
case SCHMMGMT_ATTRIBUTES:
if ( COLNUM_SCHEMA_NAME == nCol ) strDisplayText = const_cast<BSTR>(((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<BSTR>( (LPCTSTR)g_Unknown ); break; }
//
// Otherwise, return the appropriate text for the column.
//
if ( COLNUM_CLASS_NAME == nCol ) {
strDisplayText = const_cast<BSTR>((LPCTSTR)pSchemaObject->ldapDisplayName);
} else if ( COLNUM_CLASS_TYPE == nCol ) {
switch ( pSchemaObject->dwClassType ) {
case 0: strDisplayText = const_cast<BSTR>(((LPCTSTR)g_88Class)); break; case 1: strDisplayText = const_cast<BSTR>(((LPCTSTR)g_StructuralClass)); break; case 2: strDisplayText = const_cast<BSTR>(((LPCTSTR)g_AbstractClass)); break; case 3: strDisplayText = const_cast<BSTR>(((LPCTSTR)g_AuxClass)); break; default: strDisplayText = const_cast<BSTR>(((LPCTSTR)g_Unknown)); break; }
} else if ( COLNUM_CLASS_STATUS == nCol ) { if ( pSchemaObject->isDefunct ) { strDisplayText = const_cast<BSTR>( (LPCTSTR)g_Defunct ); } else { strDisplayText = const_cast<BSTR>( (LPCTSTR)g_Active ); } } else if ( COLNUM_CLASS_DESCRIPTION == nCol ) {
strDisplayText = const_cast<BSTR>((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<BSTR>( (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<BSTR>((LPCTSTR)pSchemaObject->ldapDisplayName);
} else if ( COLNUM_ATTRIBUTE_TYPE == nCol ) {
strDisplayText = const_cast<BSTR>( (LPCTSTR)g_Syntax[pSchemaObject->SyntaxOrdinal].m_strSyntaxName );
} else if ( COLNUM_ATTRIBUTE_STATUS == nCol) { if ( pSchemaObject->isDefunct ) { strDisplayText = const_cast<BSTR>( (LPCTSTR)g_Defunct ); } else { strDisplayText = const_cast<BSTR>( (LPCTSTR)g_Active ); } } else if ( COLNUM_ATTRIBUTE_SYSTEM == nCol ) {
strDisplayText = const_cast<BSTR>((LPCTSTR)pSchemaObject->description);
} else if ( COLNUM_ATTRIBUTE_DESCRIPTION == nCol ) {
strDisplayText = const_cast<BSTR>((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<BSTR>( (LPCTSTR)g_Unknown ); break; }
//
// Otherwise, return the appropriate text for the column.
//
strDisplayText = const_cast<BSTR>((LPCTSTR)pSrcSchemaObject->ldapDisplayName); } } else { if ( COLNUM_CLASS_ATTRIBUTE_NAME == nCol ) {
strDisplayText = const_cast<BSTR>((LPCTSTR)pSchemaObject->ldapDisplayName);
} else if ( COLNUM_CLASS_ATTRIBUTE_TYPE == nCol ) {
if ( cookieref.Mandatory ) { strDisplayText = const_cast<BSTR>(((LPCTSTR)g_MandatoryAttribute)); } else { strDisplayText = const_cast<BSTR>(((LPCTSTR)g_OptionalAttribute)); }
} else if ( COLNUM_CLASS_ATTRIBUTE_SYSTEM == nCol ) {
if ( cookieref.System ) { strDisplayText = const_cast<BSTR>(((LPCTSTR)g_Yes)); } else { strDisplayText = const_cast<BSTR>(((LPCTSTR)g_No)); }
} else if ( COLNUM_CLASS_ATTRIBUTE_DESCRIPTION == nCol ) {
strDisplayText = const_cast<BSTR>((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<BSTR>( (LPCTSTR)g_Unknown ); break; }
//
// Otherwise, return the appropriate text for the column.
//
strDisplayText = const_cast<BSTR>((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<PBYTE>(&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<PBYTE>(&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<PBYTE>(&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<LPARAM>((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<PWSTR>((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<IDisplayHelp> 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<IADs> 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<IADs> 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<PWSTR>((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<LPARAM>((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<LPARAM>((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(); }
|