windows-nt/Source/XPSP1/NT/admin/snapin/schmmgmt/cmponent.cpp
2020-09-26 16:20:57 +08:00

1172 lines
28 KiB
C++

//
// cmponent.cpp : Declaration of Component.
//
// This COM object is primarily concerned with
// the result pane items.
//
// Cory West <corywest@microsoft.com>
// Copyright (c) Microsoft Corporation 1997
//
#include "stdafx.h"
#include "macros.h"
USE_HANDLE_MACROS("SCHMMGMT(cmponent.cpp)")
#include "dataobj.h"
#include "cmponent.h" // Component
#include "compdata.h" // ComponentData
#include "schmutil.h"
#include "attrgen.hpp"
#include "stdcmpnt.cpp" // CComponent
//
// These arrays describe the result pane layout for when
// any particular object is selected.
//
UINT
g_aColumns0[5] = {
IDS_COLUMN_NAME,
IDS_COLUMN_TYPE,
IDS_COLUMN_STATUS,
IDS_COLUMN_DESCRIPTION,
0
};
UINT
g_aColumns1[5] = {
IDS_COLUMN_NAME,
IDS_COLUMN_SYNTAX,
IDS_COLUMN_STATUS,
IDS_COLUMN_DESCRIPTION,
0
};
UINT
g_aColumns2[6] = {
IDS_COLUMN_NAME,
IDS_COLUMN_TYPE,
IDS_COLUMN_SYSTEM,
IDS_COLUMN_DESCRIPTION,
IDS_COLUMN_PARENT,
0
};
UINT
g_aColumns3[2] =
{
IDS_COLUMN_NAME,
0
};
UINT*
g_Columns[SCHMMGMT_NUMTYPES] = {
g_aColumns3, // SCHMMGMT_SCHMMGMT
g_aColumns0, // SCHMMGMT_CLASSES
g_aColumns1, // SCHMMGMT_ATTRIBUTES
g_aColumns2, // SCHMMGMT_CLASS
g_aColumns0, // SCHMMGMT_ATTRIBUTE // @@ Is this used?
};
UINT** g_aColumns = g_Columns;
//
// These control the column widths, which I will not change.
//
int g_aColumnWidths0[4] = {150,150,75,150};
int g_aColumnWidths1[5] = {150,75,75,150,150};
int g_aColumnWidths2[1] = {150};
int* g_ColumnWidths[SCHMMGMT_NUMTYPES] = {
g_aColumnWidths2, // SCHMMGMT_SCHMMGMT
g_aColumnWidths0, // SCHMMGMT_CLASSES
g_aColumnWidths0, // SCHMMGMT_ATTRIBUTES
g_aColumnWidths1, // SCHMMGMT_CLASS
g_aColumnWidths0, // SCHMMGMT_ATTRIBUTE
};
int** g_aColumnWidths = g_ColumnWidths;
//
// Constructors and destructors.
//
Component::Component()
: m_pSvcMgmtToolbar( NULL ),
m_pSchmMgmtToolbar( NULL ),
m_pControlbar( NULL )
{
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
m_pViewedCookie = NULL;
}
Component::~Component()
{
TRACE_METHOD(Component,Destructor);
VERIFY( SUCCEEDED(ReleaseAll()) );
}
HRESULT Component::ReleaseAll()
{
MFC_TRY;
TRACE_METHOD(Component,ReleaseAll);
SAFE_RELEASE(m_pSvcMgmtToolbar);
SAFE_RELEASE(m_pSchmMgmtToolbar);
SAFE_RELEASE(m_pControlbar);
return CComponent::ReleaseAll();
MFC_CATCH;
}
//
// Support routines in ISchmMgmtComponent.
//
HRESULT
Component::LoadColumns(
Cookie* pcookie
) {
TEST_NONNULL_PTR_PARAM(pcookie);
return LoadColumnsFromArrays( (INT)(pcookie->m_objecttype) );
}
HRESULT
Component::OnViewChange(
LPDATAOBJECT,
LPARAM data,
LPARAM function
)
/***
This is called when IConsole->UpdateAllViews() is called.
The data is a schema object type as follows:
if function == 0 (SCHMMGMT_UPDATEVIEW_REFRESH)
SCHMMGMT_ATTIBUTES - We need to refresh the attributes
folder displays.
SCHMMGMT_CLASS - We need to refresh _ALL_ class attribute
displays. We don't try and trace the inheritance
graphs and do a selective refresh, that's too complicated.
SCHMMGMT_SCHMMGMT - Refresh EVERYTHING because we reloaded
the schema cache.
else if function == 1 (SCHMMGMT_UPDATEVIEW_DELETE_RESULT_ITEM)
data is the Cookie pointer
***/
{
//
// Refresh this result view.
//
if ( function == SCHMMGMT_UPDATEVIEW_REFRESH )
{
if ( m_pViewedCookie ) {
if ( ( data == m_pViewedCookie->m_objecttype ) ||
( data == SCHMMGMT_SCHMMGMT ) ) {
m_pResultData->DeleteAllRsltItems();
PopulateListbox( m_pViewedCookie );
}
}
}
else if ( function == SCHMMGMT_UPDATEVIEW_DELETE_RESULT_ITEM )
{
HRESULTITEM item;
ZeroMemory( &item, sizeof(HRESULTITEM) );
HRESULT hr = m_pResultData->FindItemByLParam( data, &item );
if ( SUCCEEDED(hr) )
{
hr = m_pResultData->DeleteItem( item, 0 );
ASSERT( SUCCEEDED(hr) );
}
}
return S_OK;
}
HRESULT
Component::OnNotifySelect( LPDATAOBJECT lpDataObject, BOOL )
/***
This called in response to MMCN_SELECT.
This routine will set the default verb and enable the toolbar buttons.
***/
{
CCookie* pBaseParentCookie = NULL;
HRESULT hr = ExtractData( lpDataObject,
CSchmMgmtDataObject::m_CFRawCookie,
OUT reinterpret_cast<PBYTE>(&pBaseParentCookie),
sizeof(pBaseParentCookie) );
ASSERT( SUCCEEDED(hr) );
Cookie* pParentCookie = ActiveCookie(pBaseParentCookie);
ASSERT( NULL != pParentCookie );
switch ( pParentCookie->m_objecttype ) {
case SCHMMGMT_CLASSES:
case SCHMMGMT_ATTRIBUTES:
break;
case SCHMMGMT_CLASS:
{
//
// Set the default verb to display the properties of the selected object.
//
m_pConsoleVerb->SetVerbState(MMC_VERB_PROPERTIES, ENABLED, TRUE);
m_pConsoleVerb->SetDefaultVerb(MMC_VERB_PROPERTIES);
// if the schema class is defunct and the forest version is Whistler or higher
// then allow delete
/* Feature was removed for Whistler
ComponentData& Scope = QueryComponentDataRef();
if ( Scope.GetBasePathsInfo()->GetForestBehaviorVersion() >= 2)
{
SchemaObject *pSchemaObject = Scope.g_SchemaCache.LookupSchemaObjectByCN(
pParentCookie->strSchemaObject,
SCHMMGMT_CLASS );
if ( pSchemaObject &&
pSchemaObject->isDefunct )
{
m_pConsoleVerb->SetVerbState(MMC_VERB_DELETE, ENABLED, TRUE);
}
}
*/
}
break;
case SCHMMGMT_ATTRIBUTE:
if ( ( pParentCookie->m_objecttype == SCHMMGMT_ATTRIBUTE ) &&
( pParentCookie->pParentCookie ) &&
( pParentCookie->pParentCookie->m_objecttype == SCHMMGMT_ATTRIBUTES ) ) {
//
// Set the default verb to display the properties of the selected object.
//
m_pConsoleVerb->SetVerbState(MMC_VERB_PROPERTIES, ENABLED, TRUE);
m_pConsoleVerb->SetDefaultVerb(MMC_VERB_PROPERTIES);
// if the schema class is defunct and the forest version is Whistler or higher
// then allow delete
/* Feature was removed for Whistler
ComponentData& Scope = QueryComponentDataRef();
if ( Scope.GetBasePathsInfo()->GetForestBehaviorVersion() >= 2)
{
SchemaObject *pSchemaObject = Scope.g_SchemaCache.LookupSchemaObjectByCN(
pParentCookie->strSchemaObject,
SCHMMGMT_ATTRIBUTE );
if ( pSchemaObject &&
pSchemaObject->isDefunct )
{
m_pConsoleVerb->SetVerbState(MMC_VERB_DELETE, ENABLED, TRUE);
}
}
*/
} else {
m_pConsoleVerb->SetVerbState(MMC_VERB_PROPERTIES, HIDDEN, TRUE);
}
break;
default:
//
// Otherwise set the default verb to open/expand the folder.
//
m_pConsoleVerb->SetDefaultVerb(MMC_VERB_OPEN);
break;
}
return S_OK;
}
HRESULT
Component::Show(
CCookie* pcookie,
LPARAM arg,
HSCOPEITEM hScopeItem
)
/***
This is called in response to MMCN_SHOW.
***/
{
TEST_NONNULL_PTR_PARAM(pcookie);
HRESULT hr = S_OK;
do
{
if ( TRUE == arg ) // showing...
{
if( QueryComponentDataRef().IsSetDelayedRefreshOnShow() )
{
HSCOPEITEM hItem = QueryComponentDataRef().GetDelayedRefreshOnShowItem();
ASSERT( hItem == hScopeItem );
QueryComponentDataRef().SetDelayedRefreshOnShow( NULL );
hr = m_pConsole->SelectScopeItem( hItem ); // will call GetResultViewType & Show
ASSERT_BREAK_ON_FAILED_HRESULT(hr);
}
else if( QueryComponentDataRef().IsErrorSet() )
{
CComPtr<IUnknown> pUnknown;
CComPtr<IMessageView> pMessageView;
hr = m_pConsole->QueryResultView(&pUnknown);
ASSERT_BREAK_ON_FAILED_HRESULT(hr);
hr = pUnknown->QueryInterface(IID_IMessageView, (PVOID*)&pMessageView);
ASSERT_BREAK_ON_FAILED_HRESULT(hr);
pMessageView->SetTitleText( CComBSTR( QueryComponentDataRef().GetErrorTitle() ) );
pMessageView->SetBodyText( CComBSTR( QueryComponentDataRef().GetErrorText() ) );
pMessageView->SetIcon(Icon_Error);
}
else
{
m_pViewedCookie = (Cookie*)pcookie;
LoadColumns( m_pViewedCookie );
hr = PopulateListbox( m_pViewedCookie );
}
}
else // hiding...
{
if( !QueryComponentDataRef().IsErrorSet() )
{
if ( NULL == m_pResultData )
{
ASSERT( FALSE );
hr = E_UNEXPECTED;
break;
}
m_pViewedCookie = NULL;
}
}
} while( FALSE );
return hr;
}
HRESULT
Component::OnNotifyAddImages(
LPDATAOBJECT,
LPIMAGELIST lpImageList,
HSCOPEITEM
)
/***
This routine is called in response to MMCN_ADD_IMAGES. Here's
what mmc.idl says about this:
Sent to IComponent to add images for the result pane. The
primary snapin should add images for both folders and leaf items.
arg = ptr to result panes IImageList.
param = HSCOPEITEM of selected/deselected item
***/
{
return QueryComponentDataRef().LoadIcons(lpImageList,TRUE);
}
HRESULT
Component::OnNotifyDelete(
LPDATAOBJECT lpDataObject)
{
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 = DeleteAttribute(pParentCookie);
if ( SUCCEEDED(hr) )
{
// Remove the node from the UI
hr = m_pConsole->UpdateAllViews( lpDataObject,
(LPARAM)pParentCookie,
SCHMMGMT_UPDATEVIEW_DELETE_RESULT_ITEM );
ASSERT( SUCCEEDED(hr) );
}
else
{
CString szDeleteError;
szDeleteError.Format(IDS_ERRMSG_DELETE_FAILED_ATTRIBUTE, GetErrorMessage(hr, TRUE));
DoErrMsgBox( ::GetActiveWindow(), TRUE, szDeleteError );
}
}
return hr;
}
HRESULT
Component::DeleteAttribute(
Cookie* pcookie
)
/***
This deletes an attribute from the schema
***/
{
HRESULT hr = S_OK;
do
{
if ( !pcookie )
{
hr = E_INVALIDARG;
break;
}
ComponentData& Scope = QueryComponentDataRef();
SchemaObject* pObject = Scope.g_SchemaCache.LookupSchemaObjectByCN(
pcookie->strSchemaObject,
SCHMMGMT_ATTRIBUTE );
if ( !pObject )
{
hr = E_FAIL;
break;
}
CString szAdsPath;
Scope.GetSchemaObjectPath( pObject->commonName, szAdsPath );
hr = DeleteObject( szAdsPath, pcookie, g_AttributeFilter );
} while (false);
return hr;
}
HRESULT
Component::PopulateListbox(
Cookie* pcookie
)
/***
This populates the result pane when the result pane
contains data that is not directly derived from the
data in the scope pane.
***/
{
switch ( pcookie->m_objecttype ) {
case SCHMMGMT_SCHMMGMT:
case SCHMMGMT_CLASSES:
//
// We don't care about these - the result
// pane contains only scope items.
//
break;
case SCHMMGMT_ATTRIBUTES:
//
// List the specified items in the result pane
// with some informational data.
//
return FastInsertAttributeResultCookies(
pcookie );
break;
case SCHMMGMT_CLASS:
//
// This results in the attributes used in this
// class and other class data being displayed.
//
return FastInsertClassAttributesResults( pcookie );
break;
case SCHMMGMT_ATTRIBUTE:
//
// This is not a scope pane item and can have no
// corresponding result pane data!!
//
ASSERT(FALSE);
break;
}
return S_OK;
}
HRESULT
Component::FastInsertAttributeResultCookies(
Cookie* pParentCookie
)
/***
When the "Attributes" folder is selected, this puts
the attributes in the result pane.
pParentCookie is the cookie for the parent object.
This routine is similar to
ComponentData::FastInsertClassScopeCookies.
****/
{
HRESULT hr;
SchemaObject *pObject, *pHead;
Cookie *pNewCookie;
RESULTDATAITEM ResultItem;
LPCWSTR lpcszMachineName = pParentCookie->QueryNonNULLMachineName();
ComponentData& Scope = QueryComponentDataRef();
//
// Initialize the result item.
//
::ZeroMemory( &ResultItem, sizeof( ResultItem ) );
ResultItem.nCol = 0;
ResultItem.mask = RDI_STR | RDI_IMAGE | RDI_PARAM;
ResultItem.str = MMC_CALLBACK;
ResultItem.nImage = iIconAttribute;
//
// 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.
//
Scope.g_SchemaCache.LoadCache();
pObject = Scope.g_SchemaCache.pSortedAttribs;
//
// If there's no sorted list, we can't insert anything!!!!
//
if ( !pObject ) {
ASSERT( FALSE );
DoErrMsgBox( ::GetActiveWindow(), TRUE, IDS_ERR_NO_SCHEMA_PATH );
return S_OK;
}
//
// Delete whatever was in the view before
// and do the insert.
//
pHead = pObject;
do {
//
// Insert this result.
//
pNewCookie= new Cookie( SCHMMGMT_ATTRIBUTE,
lpcszMachineName );
if ( pNewCookie ) {
pNewCookie->pParentCookie = pParentCookie;
pNewCookie->strSchemaObject = pObject->commonName;
pParentCookie->m_listScopeCookieBlocks.AddHead(
(CBaseCookieBlock*)pNewCookie
);
ResultItem.lParam = reinterpret_cast<LPARAM>((CCookie*)pNewCookie);
hr = m_pResultData->InsertItem( &ResultItem );
if ( SUCCEEDED(hr) ) {
pNewCookie->SetResultHandle( ResultItem.itemID );
} else {
delete pNewCookie;
}
}
pObject = pObject->pSortedListFlink;
} while ( pObject != pHead );
return S_OK;
}
HRESULT
Component::FastInsertClassAttributesResults(
Cookie* pClassCookie
)
/***
This routine displays all the attributes for a class.
***/
{
HRESULT hr = S_OK;
SchemaObject *pObject, *pTop;
CString top = L"top";
ComponentData& Scope = QueryComponentDataRef();
//
// Call the attribute display routine. This routine
// will call itself recursively to display the
// inheritance structure of the class.
//
pObject = Scope.g_SchemaCache.LookupSchemaObjectByCN(
pClassCookie->strSchemaObject,
SCHMMGMT_CLASS );
if ( pObject ) {
CStringList szProcessedList;
hr = RecursiveDisplayClassAttributesResults(
pClassCookie,
pObject,
szProcessedList);
Scope.g_SchemaCache.ReleaseRef( pObject );
}
//
// Process "top" just once.
//
pTop = Scope.g_SchemaCache.LookupSchemaObject( top, SCHMMGMT_CLASS );
if ( pTop ) {
ProcessResultList( pClassCookie, pTop->systemMayContain, TRUE, TRUE, pTop );
ProcessResultList( pClassCookie, pTop->mayContain, TRUE, FALSE, pTop );
ProcessResultList( pClassCookie, pTop->systemMustContain, FALSE, TRUE, pTop );
ProcessResultList( pClassCookie, pTop->mustContain, FALSE, FALSE, pTop );
Scope.g_SchemaCache.ReleaseRef( pTop );
}
return hr;
}
HRESULT
Component::RecursiveDisplayClassAttributesResults(
Cookie *pParentCookie,
SchemaObject* pObject,
CStringList& szProcessedList
)
/***
Display all the attributes for this class.
***/
{
ListEntry *pList;
SchemaObject *pInheritFrom;
ComponentData& Scope = QueryComponentDataRef();
//
// Don't process "top" here since everyone inherits from it.
//
if ( pObject->ldapDisplayName == L"top" ) {
return S_OK;
}
DebugTrace( L"RecursiveDisplayClassAttributesResults: %ls\n",
const_cast<LPWSTR>((LPCTSTR)pObject->ldapDisplayName) );
//
// Insert all the attributes for this class.
// The second parameter dictates whether these
// are optional or not. The third parameter
// is the source of the attribute.
//
ProcessResultList( pParentCookie, pObject->systemMayContain, TRUE, TRUE, pObject );
ProcessResultList( pParentCookie, pObject->mayContain, TRUE, FALSE, pObject );
ProcessResultList( pParentCookie, pObject->systemMustContain, FALSE, TRUE, pObject );
ProcessResultList( pParentCookie, pObject->mustContain, FALSE, FALSE, pObject );
//
// For each auxiliary class, insert those attributes.
//
pList = pObject->systemAuxiliaryClass;
while ( pList ) {
pInheritFrom = Scope.g_SchemaCache.LookupSchemaObject( pList->Attribute,
SCHMMGMT_CLASS );
//
// Don't recursively process the item if we already processed it
//
if ( pInheritFrom && szProcessedList.Find(pList->Attribute) == NULL) {
RecursiveDisplayClassAttributesResults( pParentCookie, pInheritFrom, szProcessedList );
szProcessedList.AddTail(pList->Attribute);
Scope.g_SchemaCache.ReleaseRef( pInheritFrom );
}
pList = pList->pNext;
}
pList = pObject->auxiliaryClass;
while ( pList ) {
pInheritFrom = Scope.g_SchemaCache.LookupSchemaObject( pList->Attribute,
SCHMMGMT_CLASS );
//
// Don't recursively process the item if we already processed it
//
if ( pInheritFrom && szProcessedList.Find(pList->Attribute) == NULL ) {
RecursiveDisplayClassAttributesResults( pParentCookie, pInheritFrom, szProcessedList );
szProcessedList.AddTail(pList->Attribute);
Scope.g_SchemaCache.ReleaseRef( pInheritFrom );
}
pList = pList->pNext;
}
//
// If this is an inherited class, insert those attributes.
//
pInheritFrom = Scope.g_SchemaCache.LookupSchemaObject( pObject->subClassOf,
SCHMMGMT_CLASS );
if ( pInheritFrom ) {
RecursiveDisplayClassAttributesResults( pParentCookie, pInheritFrom, szProcessedList );
Scope.g_SchemaCache.ReleaseRef( pInheritFrom );
}
return S_OK;
}
HRESULT
Component::ProcessResultList(
Cookie *pParentCookie,
ListEntry *pList,
BOOLEAN fOptional,
BOOLEAN fSystem,
SchemaObject* pSrcObject
) {
HRESULT hr;
Cookie *pNewCookie;
RESULTDATAITEM ResultItem;
LPCWSTR lpcszMachineName = pParentCookie->QueryNonNULLMachineName();
ListEntry *pCurrent = pList;
SchemaObject *pAttribute;
ComponentData& Scope = QueryComponentDataRef();
//
// Initialize the result item.
//
::ZeroMemory( &ResultItem, sizeof( ResultItem ) );
ResultItem.nCol = 0;
ResultItem.mask = RDI_STR | RDI_IMAGE | RDI_PARAM;
ResultItem.str = MMC_CALLBACK;
ResultItem.nImage = iIconAttribute;
while ( pCurrent ) {
//
// Make a new cookie.
//
pNewCookie = new Cookie( SCHMMGMT_ATTRIBUTE,
lpcszMachineName );
if ( pNewCookie ) {
//
// Record the optional status and the source.
//
if ( fOptional ) {
pNewCookie->Mandatory = FALSE;
} else {
pNewCookie->Mandatory = TRUE;
}
if ( fSystem ) {
pNewCookie->System = TRUE;
} else {
pNewCookie->System = FALSE;
}
pNewCookie->strSrcSchemaObject = pSrcObject->commonName;
pNewCookie->pParentCookie = pParentCookie;
//
// Point to the actual attribute.
//
pAttribute = Scope.g_SchemaCache.LookupSchemaObject(
pCurrent->Attribute,
SCHMMGMT_ATTRIBUTE );
if ( pAttribute ) {
pNewCookie->strSchemaObject = pAttribute->commonName;
Scope.g_SchemaCache.ReleaseRef( pAttribute );
}
//
// Insert the result pane item.
//
pParentCookie->m_listScopeCookieBlocks.AddHead(
(CBaseCookieBlock*)pNewCookie
);
ResultItem.lParam = reinterpret_cast<LPARAM>((CCookie*)pNewCookie);
hr = m_pResultData->InsertItem( &ResultItem );
if ( SUCCEEDED(hr) ) {
pNewCookie->SetResultHandle( ResultItem.itemID );
} else {
delete pNewCookie;
}
}
pCurrent = pCurrent->pNext;
}
return S_OK;
}
STDMETHODIMP
Component::AddMenuItems(
LPDATAOBJECT,
LPCONTEXTMENUCALLBACK,
long*
) {
return S_OK;
}
STDMETHODIMP
Component::Command(
long,
LPDATAOBJECT
) {
return S_OK;
}
HRESULT Component::OnNotifySnapinHelp (LPDATAOBJECT)
{
// return ShowHelpTopic( L"sag_adschema.htm" );
CComQIPtr<IDisplayHelp,&IID_IDisplayHelp> spDisplayHelp = m_pConsole;
if ( !spDisplayHelp )
{
ASSERT(FALSE);
return E_UNEXPECTED;
}
CString strHelpTopic = L"ADConcepts.chm::/sag_adschema.htm";
HRESULT hr = spDisplayHelp->ShowTopic (T2OLE ((LPWSTR)(LPCWSTR) strHelpTopic));
ASSERT (SUCCEEDED (hr));
return hr;
}
HRESULT Component::OnNotifyContextHelp (LPDATAOBJECT)
{
// return ShowHelpTopic( L"schmmgmt_top.htm" );
CComQIPtr<IDisplayHelp,&IID_IDisplayHelp> spDisplayHelp = m_pConsole;
if ( !spDisplayHelp )
{
ASSERT(FALSE);
return E_UNEXPECTED;
}
CString strHelpTopic = L"ADConcepts.chm::/schmmgmt_top.htm";
HRESULT hr = spDisplayHelp->ShowTopic (T2OLE ((LPWSTR)(LPCWSTR) strHelpTopic));
ASSERT (SUCCEEDED (hr));
return hr;
}
STDMETHODIMP
Component::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_ATTRIBUTE ) &&
( pParentCookie->pParentCookie ) &&
( pParentCookie->pParentCookie->m_objecttype == SCHMMGMT_ATTRIBUTES ) ) {
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
Component::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) );
Cookie* pParentCookie = ActiveCookie(pBaseParentCookie);
ASSERT( NULL != pParentCookie );
ASSERT( pParentCookie->m_objecttype == SCHMMGMT_ATTRIBUTE );
//
// Create the page.
//
HPROPSHEETPAGE hPage;
AttributeGeneralPage *pGeneralPage =
new AttributeGeneralPage( this, pDataObject );
if ( pGeneralPage )
{
pGeneralPage->Load( *pParentCookie );
MMCPropPageCallback( &pGeneralPage->m_psp );
hPage= CreatePropertySheetPage( &pGeneralPage->m_psp );
hr = pCallBack->AddPage( hPage );
}
return S_OK;
MFC_CATCH;
}
HRESULT __stdcall
Component::Compare(
LPARAM,
MMC_COOKIE cookieA,
MMC_COOKIE cookieB,
int* result)
{
if (!result)
{
return E_INVALIDARG;
}
if (!m_pViewedCookie)
{
ASSERT(false);
*result = 0;
return S_OK;
}
Cookie* c1 =
(Cookie*) ActiveBaseCookie(reinterpret_cast<CCookie*>(cookieA));
Cookie* c2 =
(Cookie*) ActiveBaseCookie(reinterpret_cast<CCookie*>(cookieB));
PWSTR t1 = QueryBaseComponentDataRef().QueryResultColumnText(*c1, *result);
PWSTR t2 = QueryBaseComponentDataRef().QueryResultColumnText(*c2, *result);
// All columns use a case-insensitive comparison, as many columns contain
// display names from the directory (which are case-insensitive). That we
// also use a case insensitive compare for the other columns is harmless.
// another trick: we are inverting the results from the compare. This is
// because we initially insert the items in the list in sorted order. So
// the first sort request from the user really is intended to reverse-sort
// the list.
*result = -(_wcsicmp(t1, t2));
return S_OK;
}
STDMETHODIMP Component::GetResultViewType(MMC_COOKIE cookie,
BSTR* ppViewType,
long* pViewOptions)
{
MFC_TRY;
if( QueryComponentDataRef().IsErrorSet() )
{
*pViewOptions = MMC_VIEW_OPTIONS_NOLISTVIEWS;
LPOLESTR psz = NULL;
StringFromCLSID(CLSID_MessageView, &psz);
USES_CONVERSION;
if (psz != NULL)
{
*ppViewType = psz;
return S_OK;
}
else
{
return S_FALSE;
}
}
else
{
return CComponent::GetResultViewType( cookie, ppViewType, pViewOptions );
}
MFC_CATCH;
}