WindowsXP-SP1/admin/snapin/schmmgmt/classgen.cpp
2020-09-30 16:53:49 +02:00

831 lines
22 KiB
C++

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