mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1265 lines
34 KiB
1265 lines
34 KiB
#include "stdafx.h"
|
|
#include "compdata.h"
|
|
#include "cmponent.h"
|
|
#include "attrgen.hpp"
|
|
#include "resource.h"
|
|
#include "dataobj.h"
|
|
|
|
|
|
|
|
|
|
const TCHAR szUserClass[] = USER_CLASS_NAME ;
|
|
|
|
// disable User Copy for the following list of attributes
|
|
const TCHAR * rgszExclClass[] = { _T("cn"), _T("displayName"),
|
|
_T("sAMAccountName"), _T("userAccountControl"),
|
|
_T("userParameters"), _T("userPrincipalName"),
|
|
NULL };
|
|
|
|
//
|
|
// The following table is copied from dirsync\ldifds\ldifldap\samrestrict.h
|
|
//
|
|
// CLASS_USER, SampUserObjectType (ldapdisplayname: user)
|
|
//
|
|
PCWSTR rgszExclClass2[] = { // user[] = {
|
|
L"memberOf", // SAMP_USER_GROUPS, ATT_MEMBER
|
|
L"dBCSPwd", // SAMP_USER_DBCS_PWD, ATT_DBCS_PWD
|
|
L"ntPwdHistory", // SAMP_USER_NT_PWD_HISTORY, ATT_NT_PWD_HISTORY
|
|
L"lmPwdHistory", // SAMP_USER_LM_PWD_HISTORY, ATT_LM_PWD_HISTORY
|
|
L"lastLogon", // SAMP_FIXED_USER_LAST_LOGON, ATT_LAST_LOGON
|
|
L"lastLogoff", // SAMP_FIXED_USER_LAST_LOGOFF, ATT_LAST_LOGOFF
|
|
L"badPasswordTime", // SAMP_FIXED_USER_LAST_BAD_PASSWORD_TIME,
|
|
// ATT_BAD_PASSWORD_TIME
|
|
L"rid", // SAMP_FIXED_USER_USERID, ATT_RID
|
|
L"badPwdCount", // SAMP_FIXED_USER_BAD_PWD_COUNT,
|
|
// ATT_BAD_PWD_COUNT
|
|
L"logonCount", // SAMP_FIXED_USER_LOGON_COUNT, ATT_LOGON_COUNT
|
|
L"sAMAccountType", // SAMP_USER_ACCOUNT_TYPE, ATT_SAM_ACCOUNT_TYPE
|
|
L"supplementalCredentials", // SAMP_FIXED_USER_SUPPLEMENTAL_CREDENTIALS,
|
|
// ATT_SUPPLEMENTAL_CREDENTIALS
|
|
L"objectSid", // not in mappings.c, but still required!,
|
|
// ATT_OBJECT_SID
|
|
L"pwdLastSet",
|
|
NULL
|
|
};
|
|
|
|
|
|
|
|
const TCHAR szTopClass[] = _T("Top");
|
|
|
|
|
|
const CDialogControlsInfo ctrls[] =
|
|
{
|
|
{ IDC_ATTRIB_GENERAL_DESCRIPTION_EDIT, g_Description, TRUE },
|
|
{ IDC_ATTRIB_GENERAL_MIN_EDIT, g_RangeLower, TRUE },
|
|
{ IDC_ATTRIB_GENERAL_MAX_EDIT, g_RangeUpper, TRUE },
|
|
{ IDC_ATTRIB_GENERAL_DISPLAYABLE_CHECK, g_ShowInAdvViewOnly, FALSE },
|
|
{ IDC_ATTRIB_GENERAL_DEACTIVATE, g_isDefunct, FALSE },
|
|
{ IDC_ATTRIB_GENERAL_INDEX_CHECK, g_IndexFlag, FALSE },
|
|
{ IDC_ATTRIB_GENERAL_REPLICATED, g_GCReplicated, FALSE },
|
|
{ IDC_ATTRIB_GENERAL_CPYATTR_CHECK, g_IndexFlag, FALSE },
|
|
{ IDC_ATTRIB_GENERAL_ANR_CHECK, g_IndexFlag, FALSE },
|
|
{ IDC_ATTRIB_GENERAL_CONTAINERIZED_INDEX_CHECK, g_IndexFlag, FALSE},
|
|
} ;
|
|
|
|
|
|
const DWORD AttributeGeneralPage::help_map[] =
|
|
{
|
|
IDI_ATTRIBUTE, NO_HELP,
|
|
IDC_ATTRIB_GENERAL_NAME_STATIC, NO_HELP,
|
|
IDC_ATTRIB_GENERAL_DESCRIPTION_EDIT, IDH_ATTRIB_GENERAL_DESCRIPTION_EDIT,
|
|
IDC_ATTRIB_GENERAL_LDN, IDH_ATTRIB_GENERAL_LDN,
|
|
IDC_ATTRIB_GENERAL_OID_EDIT, IDH_ATTRIB_GENERAL_OID_EDIT,
|
|
IDC_ATTRIB_GENERAL_VALUE_STATIC, NO_HELP,
|
|
IDC_ATTRIB_GENERAL_SYNTAX_EDIT, IDH_ATTRIB_GENERAL_SYNTAX_EDIT,
|
|
IDC_ATTRIB_GENERAL_MIN_EDIT, IDH_ATTRIB_GENERAL_MIN_EDIT,
|
|
IDC_ATTRIB_GENERAL_MAX_EDIT, IDH_ATTRIB_GENERAL_MAX_EDIT,
|
|
IDC_ATTRIB_GENERAL_DISPLAYABLE_CHECK, IDH_ATTRIB_GENERAL_DISPLAYABLE_CHECK,
|
|
IDC_ATTRIB_GENERAL_DEACTIVATE, IDH_ATTRIB_DEACTIVATE,
|
|
IDC_ATTRIB_GENERAL_INDEX_CHECK, IDH_ATTRIB_GENERAL_INDEX_CHECK,
|
|
IDC_ATTRIB_GENERAL_CONTAINERIZED_INDEX_CHECK, IDH_ATTRIB_GENERAL_CONTAINERIZED_INDEX_CHECK,
|
|
IDC_ATTRIB_GENERAL_ANR_CHECK, IDH_ATTRIB_GENERAL_ANR_CHECK,
|
|
IDC_ATTRIB_GENERAL_REPLICATED, IDH_REPLICATED,
|
|
IDC_ATTRIB_GENERAL_CPYATTR_CHECK, IDH_ATTRIB_GENERAL_CPYATTR_CHECK,
|
|
IDC_ATTRIB_GENERAL_SYSCLASS_STATIC, NO_HELP,
|
|
0, 0
|
|
};
|
|
|
|
|
|
|
|
// returns state of bit n
|
|
|
|
inline
|
|
bool
|
|
getbit(const DWORD& bits, int n)
|
|
{
|
|
return (bits & (1 << n)) ? true : false;
|
|
}
|
|
|
|
|
|
// sets bit n to 1
|
|
|
|
inline
|
|
void
|
|
setbit(DWORD& bits, int n)
|
|
{
|
|
bits |= (1 << n);
|
|
}
|
|
|
|
|
|
|
|
// sets bit n to 0
|
|
|
|
inline
|
|
void
|
|
clearbit(DWORD& bits, int n)
|
|
{
|
|
bits &= ~(1 << n);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Attribute property sheet routines.
|
|
//
|
|
|
|
|
|
|
|
BEGIN_MESSAGE_MAP( AttributeGeneralPage, CDialog )
|
|
ON_MESSAGE(WM_HELP, OnHelp)
|
|
ON_MESSAGE(WM_CONTEXTMENU, OnContextHelp)
|
|
ON_BN_CLICKED(IDC_ATTRIB_GENERAL_INDEX_CHECK, OnIndexClick)
|
|
ON_BN_CLICKED(IDC_ATTRIB_GENERAL_DEACTIVATE, OnDeactivateClick)
|
|
END_MESSAGE_MAP()
|
|
|
|
|
|
|
|
AttributeGeneralPage::AttributeGeneralPage(
|
|
Component* pResultControl,
|
|
LPDATAOBJECT lpDataObject)
|
|
:
|
|
CPropertyPage( IDD_ATTRIB_GENERAL ),
|
|
pCookie( NULL ),
|
|
pIADsObject( NULL ),
|
|
pObject( NULL),
|
|
lpResultDataObject( lpDataObject ),
|
|
pComponent( pResultControl ),
|
|
fDataLoaded( FALSE ),
|
|
Displayable( TRUE ),
|
|
DDXDisplayable( TRUE ),
|
|
search_flags(0),
|
|
DDXIndexed( FALSE ),
|
|
DDXANR( FALSE ),
|
|
DDXCopyOnDuplicate( FALSE ),
|
|
Defunct( FALSE ),
|
|
DDXDefunct( FALSE ),
|
|
ReplicatedToGC( FALSE ),
|
|
DDXReplicatedToGC( FALSE ),
|
|
DDXContainerIndexed( FALSE ),
|
|
m_editLowerRange( CParsedEdit::EDIT_TYPE_UINT32 ),
|
|
m_editUpperRange( CParsedEdit::EDIT_TYPE_UINT32 )
|
|
{
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
AttributeGeneralPage::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;
|
|
}
|
|
|
|
|
|
AttributeGeneralPage::~AttributeGeneralPage(
|
|
)
|
|
{
|
|
|
|
ComponentData& Scope = pComponent->QueryComponentDataRef();
|
|
|
|
//
|
|
// Always make sure we free the IADs object.
|
|
//
|
|
|
|
if ( pIADsObject ) {
|
|
pIADsObject->Release();
|
|
pIADsObject = NULL;
|
|
}
|
|
|
|
//
|
|
// And release the cache.
|
|
//
|
|
|
|
if ( pObject ) {
|
|
Scope.g_SchemaCache.ReleaseRef( pObject );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
AttributeGeneralPage::OnInitDialog()
|
|
{
|
|
CPropertyPage::OnInitDialog();
|
|
|
|
ASSERT( GetDlgItem(IDC_ATTRIB_GENERAL_DESCRIPTION_EDIT) );
|
|
|
|
( static_cast<CEdit *>( GetDlgItem(IDC_ATTRIB_GENERAL_DESCRIPTION_EDIT) ) )
|
|
-> LimitText( 1024 ) ;
|
|
|
|
m_editLowerRange.SubclassEdit(IDC_ATTRIB_GENERAL_MIN_EDIT, this, cchMinMaxRange);
|
|
m_editUpperRange.SubclassEdit(IDC_ATTRIB_GENERAL_MAX_EDIT, this, cchMinMaxRange);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
void
|
|
AttributeGeneralPage::Load(
|
|
Cookie& CookieRef
|
|
) {
|
|
|
|
//
|
|
// Store the cookie object pointer. Everything
|
|
// else gets loaded when the page is displayed.
|
|
//
|
|
|
|
pCookie = &CookieRef;
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
AttributeGeneralPage::OnApply(
|
|
VOID
|
|
) {
|
|
|
|
HRESULT hr;
|
|
|
|
VARIANT AdsValue;
|
|
BOOL fChangesMade = FALSE;
|
|
BOOL fRangeChange = FALSE;
|
|
BOOL fApplyAbort = FALSE; // stop later saves
|
|
BOOL fApplyFailed = FALSE; // should not close the box
|
|
|
|
DWORD dwRange;
|
|
|
|
// Enable hourglass
|
|
CWaitCursor wait;
|
|
|
|
//
|
|
// 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;
|
|
}
|
|
|
|
//
|
|
// Check to see if something we cared about changed.
|
|
// We care about Description, Min, Max, Indexed,
|
|
// Defunct, ReplicatedToGC, and Displayable.
|
|
//
|
|
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
|
|
VariantInit( &AdsValue );
|
|
|
|
//
|
|
// Defunct -- in case it was deactivated, activate the object first
|
|
//
|
|
if( !fApplyAbort && !DDXDefunct && DDXDefunct != Defunct )
|
|
{
|
|
hr = ChangeDefunctState( DDXDefunct, Defunct, pPropertyList, fApplyAbort, fApplyFailed );
|
|
}
|
|
|
|
|
|
//
|
|
// Description
|
|
//
|
|
|
|
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 );
|
|
}
|
|
|
|
//
|
|
// Displayable
|
|
//
|
|
|
|
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 );
|
|
}
|
|
|
|
//
|
|
// ReplicatedToGC
|
|
//
|
|
|
|
if ( !fApplyAbort && DDXReplicatedToGC != ReplicatedToGC ) {
|
|
|
|
V_VT(&AdsValue) = VT_BOOL;
|
|
|
|
if ( DDXReplicatedToGC ) {
|
|
V_BOOL(&AdsValue) = -1;
|
|
} else {
|
|
V_BOOL(&AdsValue) = 0;
|
|
}
|
|
|
|
hr = pIADsObject->Put( const_cast<BSTR>((LPCTSTR)g_GCReplicated),
|
|
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_GC );
|
|
}
|
|
else
|
|
{
|
|
fApplyAbort = TRUE;
|
|
DoErrMsgBox( ::GetActiveWindow(), TRUE, GetErrorMessage(hr,TRUE) );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ReplicatedToGC = DDXReplicatedToGC;
|
|
}
|
|
|
|
VariantInit( &AdsValue );
|
|
}
|
|
|
|
//
|
|
// Indexed
|
|
//
|
|
|
|
// make sure ANR is not set when Indexed is unchecked
|
|
if( !DDXIndexed )
|
|
DDXANR = FALSE;
|
|
|
|
if( !fApplyAbort &&
|
|
(getbit(search_flags, INDEX_BIT_ATTINDEX) != (DDXIndexed ? 1 : 0)
|
|
|| getbit(search_flags, INDEX_BIT_ANR) != (DDXANR ? 1 : 0)
|
|
|| getbit(search_flags, INDEX_BIT_COPYONDUPLICATE) != (DDXCopyOnDuplicate ? 1 : 0)
|
|
|| getbit(search_flags, INDEX_BIT_PDNTATTINDEX) != (DDXContainerIndexed ? 1 : 0)) )
|
|
{
|
|
DWORD DDXsearch_flags = search_flags;
|
|
|
|
V_VT(&AdsValue) = VT_I4;
|
|
|
|
if (DDXIndexed)
|
|
setbit(DDXsearch_flags, INDEX_BIT_ATTINDEX);
|
|
else
|
|
clearbit(DDXsearch_flags, INDEX_BIT_ATTINDEX);
|
|
|
|
ASSERT( DDXIndexed || !DDXANR );
|
|
if (DDXANR)
|
|
setbit(DDXsearch_flags, INDEX_BIT_ANR);
|
|
else
|
|
clearbit(DDXsearch_flags, INDEX_BIT_ANR);
|
|
|
|
if (DDXCopyOnDuplicate)
|
|
setbit(DDXsearch_flags, INDEX_BIT_COPYONDUPLICATE);
|
|
else
|
|
clearbit(DDXsearch_flags, INDEX_BIT_COPYONDUPLICATE);
|
|
|
|
if (DDXContainerIndexed)
|
|
setbit(DDXsearch_flags, INDEX_BIT_PDNTATTINDEX);
|
|
else
|
|
clearbit(DDXsearch_flags, INDEX_BIT_PDNTATTINDEX);
|
|
|
|
V_I4(&AdsValue) = DDXsearch_flags;
|
|
hr = pIADsObject->Put( const_cast<BSTR>((LPCTSTR)g_IndexFlag),
|
|
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_INDEXED );
|
|
}
|
|
else
|
|
{
|
|
fApplyAbort = TRUE;
|
|
DoErrMsgBox( ::GetActiveWindow(), TRUE, GetErrorMessage(hr,TRUE) );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
search_flags = DDXsearch_flags;
|
|
}
|
|
|
|
VariantInit( &AdsValue );
|
|
}
|
|
|
|
//
|
|
// RangeUpper and RangeLower
|
|
// These have to be set together so the server
|
|
// range validation works correctly.
|
|
//
|
|
|
|
if ( !fApplyAbort && RangeUpper != DDXRangeUpper ) {
|
|
|
|
if ( DDXRangeUpper.IsEmpty() ) {
|
|
|
|
//
|
|
// Clear the value.
|
|
//
|
|
|
|
hr = pIADsObject->PutEx( ADS_PROPERTY_CLEAR,
|
|
const_cast<BSTR>((LPCTSTR)g_RangeUpper),
|
|
AdsValue );
|
|
ASSERT( SUCCEEDED( hr ) );
|
|
|
|
} else {
|
|
|
|
//
|
|
// Store the new value.
|
|
//
|
|
ASSERT(pObject);
|
|
|
|
hr = GetSafeSignedDWORDFromString( this, dwRange, DDXRangeUpper,
|
|
g_Syntax[ pObject->SyntaxOrdinal ].m_fIsSigned );
|
|
|
|
ASSERT( S_OK == hr ); // validation should have taken care of min/max stuff
|
|
|
|
V_VT( &AdsValue ) = VT_I4;
|
|
V_I4( &AdsValue ) = dwRange;
|
|
|
|
hr = pIADsObject->Put( const_cast<BSTR>((LPCTSTR)g_RangeUpper),
|
|
AdsValue );
|
|
ASSERT( SUCCEEDED( hr ) );
|
|
}
|
|
|
|
fRangeChange = TRUE;
|
|
VariantInit( &AdsValue );
|
|
}
|
|
|
|
if ( !fApplyAbort && RangeLower != DDXRangeLower ) {
|
|
|
|
if ( DDXRangeLower.IsEmpty() ) {
|
|
|
|
//
|
|
// Clear the value.
|
|
//
|
|
|
|
hr = pIADsObject->PutEx( ADS_PROPERTY_CLEAR,
|
|
const_cast<BSTR>((LPCTSTR)g_RangeLower),
|
|
AdsValue );
|
|
ASSERT( SUCCEEDED( hr ) );
|
|
|
|
} else {
|
|
|
|
//
|
|
// Store the new value.
|
|
//
|
|
|
|
ASSERT(pObject);
|
|
|
|
hr = GetSafeSignedDWORDFromString( this, dwRange, DDXRangeLower,
|
|
g_Syntax[ pObject->SyntaxOrdinal ].m_fIsSigned );
|
|
|
|
ASSERT( S_OK == hr ); // validation should have taken care of min/max stuff
|
|
|
|
V_VT( &AdsValue ) = VT_I4;
|
|
V_I4( &AdsValue ) = dwRange;
|
|
|
|
hr = pIADsObject->Put( const_cast<BSTR>((LPCTSTR)g_RangeLower),
|
|
AdsValue );
|
|
ASSERT( SUCCEEDED( hr ) );
|
|
}
|
|
|
|
fRangeChange = TRUE;
|
|
VariantInit( &AdsValue );
|
|
}
|
|
|
|
//
|
|
// Actually commit the changes.
|
|
//
|
|
|
|
if ( !fApplyAbort && fRangeChange ) {
|
|
|
|
hr = pIADsObject->SetInfo();
|
|
|
|
if ( FAILED( hr ) ) {
|
|
pPropertyList->PurgePropertyList();
|
|
if( ERROR_DS_UNWILLING_TO_PERFORM == HRESULT_CODE(hr) )
|
|
{
|
|
fApplyFailed = TRUE;
|
|
DoErrMsgBox( ::GetActiveWindow(), TRUE, IDS_ERR_CREATE_MINMAX );
|
|
}
|
|
else
|
|
{
|
|
fApplyAbort = TRUE;
|
|
DoErrMsgBox( ::GetActiveWindow(), TRUE, GetErrorMessage(hr,TRUE) );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RangeLower = DDXRangeLower;
|
|
RangeUpper = DDXRangeUpper;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// 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 there are visible changes, update the views.
|
|
//
|
|
|
|
if ( ( fChangesMade ) &&
|
|
( pComponent ) &&
|
|
( lpResultDataObject ) ) {
|
|
|
|
CCookie* pBaseCookie;
|
|
Cookie* pCookie;
|
|
|
|
hr = ExtractData( lpResultDataObject,
|
|
CSchmMgmtDataObject::m_CFRawCookie,
|
|
OUT reinterpret_cast<PBYTE>(&pBaseCookie),
|
|
sizeof(pBaseCookie) );
|
|
ASSERT( SUCCEEDED(hr) );
|
|
|
|
pCookie = pComponent->ActiveCookie(pBaseCookie);
|
|
ASSERT( NULL != pCookie );
|
|
|
|
hr = pComponent->m_pResultData->UpdateItem( pCookie->hResultId );
|
|
ASSERT( SUCCEEDED(hr) );
|
|
}
|
|
|
|
if ( pPropertyList ) {
|
|
pPropertyList->Release();
|
|
}
|
|
|
|
return !fApplyAbort && !fApplyFailed ; // return TRUE if nothing happened
|
|
}
|
|
|
|
|
|
|
|
void
|
|
AttributeGeneralPage::DoDataExchange(
|
|
CDataExchange *pDX
|
|
) {
|
|
|
|
HRESULT hr;
|
|
CString szAdsPath;
|
|
VARIANT AdsResult;
|
|
UINT SyntaxOrdinal = SCHEMA_SYNTAX_UNKNOWN;
|
|
|
|
ComponentData& Scope = pComponent->QueryComponentDataRef();
|
|
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
|
|
|
|
// Enable hourglass
|
|
CWaitCursor wait;
|
|
|
|
CPropertyPage::DoDataExchange( pDX );
|
|
|
|
VariantInit( &AdsResult );
|
|
|
|
// We still want to do the DDX exchange at the bottom
|
|
// even if the data is already loaded so make it part
|
|
// of this if statement instead of short circuiting
|
|
// from within
|
|
|
|
if ( !pDX->m_bSaveAndValidate &&
|
|
!fDataLoaded) {
|
|
|
|
//
|
|
// Get the schema cache object and the actual ADS object.
|
|
// Keep the ADS object around while the page is loaded.
|
|
//
|
|
|
|
ASSERT( !pObject ); // Must be NULL initially
|
|
|
|
pObject = Scope.g_SchemaCache.LookupSchemaObjectByCN(
|
|
pCookie->strSchemaObject,
|
|
SCHMMGMT_ATTRIBUTE );
|
|
|
|
if ( pObject ) {
|
|
|
|
Scope.GetSchemaObjectPath( pObject->commonName, szAdsPath );
|
|
|
|
if ( !szAdsPath.IsEmpty() ) {
|
|
|
|
hr = ADsGetObject( (LPWSTR)(LPCWSTR)szAdsPath,
|
|
IID_IADs,
|
|
(void **)&pIADsObject );
|
|
|
|
if( SUCCEEDED(hr) )
|
|
{
|
|
BOOL fIsConstructed = FALSE;
|
|
|
|
// Igrnore error code
|
|
IsConstructedObject( pIADsObject, fIsConstructed );
|
|
|
|
// Enable check box if ths attribute is not in the excluded
|
|
// list and available for the User Class
|
|
GetDlgItem(IDC_ATTRIB_GENERAL_CPYATTR_CHECK)->EnableWindow(
|
|
!fIsConstructed &&
|
|
!IsInList( rgszExclClass, pObject->ldapDisplayName ) &&
|
|
!IsInList( rgszExclClass2, pObject->ldapDisplayName ) &&
|
|
IsAttributeInUserClass( pObject->ldapDisplayName ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// 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 );
|
|
}
|
|
|
|
//
|
|
// 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 );
|
|
}
|
|
|
|
//
|
|
// CommonName
|
|
//
|
|
|
|
hr = pIADsObject->Get( const_cast<BSTR>((LPCTSTR)g_CN),
|
|
&AdsResult );
|
|
|
|
if ( SUCCEEDED( hr ) ) {
|
|
|
|
ASSERT( AdsResult.vt == VT_BSTR );
|
|
DisplayName = AdsResult.bstrVal;
|
|
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_SysAttrString;
|
|
} else {
|
|
SysClassString = L"";
|
|
}
|
|
|
|
VariantClear( &AdsResult );
|
|
|
|
} else {
|
|
|
|
SysClassString = L"";
|
|
}
|
|
|
|
//
|
|
// Syntax
|
|
//
|
|
// No need to reload from schema -- syntax never changes
|
|
//
|
|
ASSERT(pObject);
|
|
if( pObject )
|
|
SyntaxOrdinal = pObject->SyntaxOrdinal;
|
|
|
|
SyntaxString = g_Syntax[ SyntaxOrdinal ].m_strSyntaxName;
|
|
|
|
|
|
//
|
|
// Syntax min and max values.
|
|
//
|
|
|
|
hr = pIADsObject->Get( const_cast<BSTR>((LPCTSTR)g_RangeLower),
|
|
&AdsResult );
|
|
|
|
if ( SUCCEEDED( hr ) ) {
|
|
|
|
ASSERT( V_VT( &AdsResult ) == VT_I4 );
|
|
|
|
RangeLower.Format( g_Syntax[ SyntaxOrdinal ].m_fIsSigned ?
|
|
g_INT32_FORMAT : g_UINT32_FORMAT,
|
|
V_I4( &AdsResult ) );
|
|
|
|
ASSERT( RangeLower.GetLength() <= cchMinMaxRange );
|
|
DDXRangeLower = RangeLower;
|
|
|
|
VariantClear( &AdsResult );
|
|
}
|
|
|
|
hr = pIADsObject->Get( const_cast<BSTR>((LPCTSTR)g_RangeUpper),
|
|
&AdsResult );
|
|
|
|
if ( SUCCEEDED( hr ) ) {
|
|
|
|
ASSERT( V_VT( &AdsResult ) == VT_I4 );
|
|
|
|
RangeUpper.Format( g_Syntax[ SyntaxOrdinal ].m_fIsSigned ?
|
|
g_INT32_FORMAT : g_UINT32_FORMAT,
|
|
V_I4( &AdsResult ) );
|
|
|
|
ASSERT( RangeUpper.GetLength() <= cchMinMaxRange );
|
|
DDXRangeUpper = RangeUpper;
|
|
|
|
VariantClear( &AdsResult );
|
|
}
|
|
|
|
//
|
|
// Multi-Valued
|
|
//
|
|
|
|
|
|
MultiValued.LoadString( IDS_ATTRIBUTE_MULTI );
|
|
|
|
hr = pIADsObject->Get( const_cast<BSTR>((LPCTSTR)g_IsSingleValued),
|
|
&AdsResult );
|
|
|
|
if ( SUCCEEDED( hr ) ) {
|
|
|
|
ASSERT( AdsResult.vt == VT_BOOL );
|
|
|
|
if ( AdsResult.boolVal == -1 ) {
|
|
MultiValued.Empty();
|
|
MultiValued.LoadString( IDS_ATTRIBUTE_SINGLE );
|
|
}
|
|
|
|
VariantClear( &AdsResult );
|
|
|
|
}
|
|
|
|
//
|
|
// Displayable
|
|
//
|
|
|
|
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
|
|
//
|
|
|
|
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 );
|
|
|
|
}
|
|
|
|
//
|
|
// ReplicatedToGC
|
|
//
|
|
|
|
hr = pIADsObject->Get( const_cast<BSTR>((LPCTSTR)g_GCReplicated),
|
|
&AdsResult );
|
|
|
|
if ( SUCCEEDED( hr ) ) {
|
|
|
|
ASSERT( AdsResult.vt == VT_BOOL );
|
|
|
|
if ( AdsResult.boolVal == -1 ) {
|
|
ReplicatedToGC = TRUE;
|
|
DDXReplicatedToGC = TRUE;
|
|
}
|
|
|
|
VariantClear( &AdsResult );
|
|
|
|
}
|
|
|
|
//
|
|
// OID
|
|
//
|
|
|
|
hr = pIADsObject->Get( const_cast<BSTR>((LPCTSTR)g_GlobalAttributeID),
|
|
&AdsResult );
|
|
|
|
if ( SUCCEEDED( hr ) ) {
|
|
|
|
ASSERT( AdsResult.vt == VT_BSTR );
|
|
OidString = AdsResult.bstrVal;
|
|
VariantClear( &AdsResult );
|
|
}
|
|
|
|
//
|
|
// Indexed, ANR, & Copy on duplicate
|
|
//
|
|
|
|
hr = pIADsObject->Get( const_cast<BSTR>((LPCTSTR)g_IndexFlag),
|
|
&AdsResult );
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
ASSERT(AdsResult.vt == VT_I4);
|
|
|
|
search_flags = V_I4(&AdsResult);
|
|
|
|
// Index this attribute in the Active Directory
|
|
DDXIndexed = getbit( search_flags, INDEX_BIT_ATTINDEX );
|
|
|
|
// Ambiguous Name Resolution (ANR)
|
|
// checkbox must exist
|
|
ASSERT( GetDlgItem(IDC_ATTRIB_GENERAL_ANR_CHECK) );
|
|
|
|
// if not indexed, or not allowed, disable the checkbox
|
|
GetDlgItem(IDC_ATTRIB_GENERAL_ANR_CHECK)->EnableWindow(
|
|
g_Syntax[ SyntaxOrdinal ].m_fIsANRCapable ? DDXIndexed : FALSE );
|
|
|
|
if( DDXIndexed )
|
|
DDXANR = getbit( search_flags, INDEX_BIT_ANR );
|
|
else
|
|
{
|
|
DDXANR = FALSE;
|
|
|
|
// if not indexed, ANR in DS should not be set
|
|
ASSERT( !getbit( search_flags, INDEX_BIT_ANR ) );
|
|
}
|
|
|
|
// Attribute is copied when duplicating a user
|
|
DDXCopyOnDuplicate = getbit( search_flags, INDEX_BIT_COPYONDUPLICATE );
|
|
|
|
VariantClear( &AdsResult );
|
|
}
|
|
|
|
// Containerized index
|
|
DDXContainerIndexed = getbit( search_flags, INDEX_BIT_PDNTATTINDEX );
|
|
|
|
// 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_ATTRIB_GENERAL_MIN_EDIT) );
|
|
ASSERT( GetDlgItem(IDC_ATTRIB_GENERAL_MAX_EDIT) );
|
|
ASSERT( GetDlgItem(IDC_ATTRIB_GENERAL_DEACTIVATE) );
|
|
|
|
reinterpret_cast<CEdit *>( GetDlgItem(IDC_ATTRIB_GENERAL_MIN_EDIT) )->SetReadOnly();
|
|
reinterpret_cast<CEdit *>( GetDlgItem(IDC_ATTRIB_GENERAL_MAX_EDIT) )->SetReadOnly();
|
|
GetDlgItem(IDC_ATTRIB_GENERAL_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_ATTRIB_GENERAL_DEACTIVATE) );
|
|
|
|
if( DDXDefunct &&
|
|
GetDlgItem(IDC_ATTRIB_GENERAL_DEACTIVATE)->IsWindowEnabled() )
|
|
{
|
|
AfxMessageBox( IDS_WARNING_DEFUNCT, MB_OK | MB_ICONINFORMATION );
|
|
}
|
|
|
|
|
|
//
|
|
// Remember that the data is loaded.
|
|
//
|
|
|
|
fDataLoaded = TRUE;
|
|
|
|
m_editLowerRange.SetSigned( g_Syntax[ SyntaxOrdinal ].m_fIsSigned );
|
|
m_editUpperRange.SetSigned( g_Syntax[ SyntaxOrdinal ].m_fIsSigned );
|
|
}
|
|
|
|
|
|
//
|
|
// Set up the dialog data exchange.
|
|
//
|
|
|
|
DDX_Text( pDX, IDC_ATTRIB_GENERAL_NAME_STATIC, ObjectName );
|
|
DDX_Text( pDX, IDC_ATTRIB_GENERAL_SYSCLASS_STATIC, SysClassString );
|
|
DDX_Text( pDX, IDC_ATTRIB_GENERAL_SYNTAX_EDIT, SyntaxString );
|
|
DDX_Text( pDX, IDC_ATTRIB_GENERAL_OID_EDIT, OidString );
|
|
DDX_Text( pDX, IDC_ATTRIB_GENERAL_VALUE_STATIC, MultiValued );
|
|
DDX_Text( pDX, IDC_ATTRIB_GENERAL_LDN, DisplayName );
|
|
DDX_Text( pDX, IDC_ATTRIB_GENERAL_DESCRIPTION_EDIT, DDXDescription );
|
|
|
|
DDXV_VerifyAttribRange( pDX, g_Syntax[ pObject->SyntaxOrdinal ].m_fIsSigned,
|
|
IDC_ATTRIB_GENERAL_MIN_EDIT, DDXRangeLower,
|
|
IDC_ATTRIB_GENERAL_MAX_EDIT, DDXRangeUpper );
|
|
|
|
DDX_Check( pDX, IDC_ATTRIB_GENERAL_DISPLAYABLE_CHECK, DDXDisplayable );
|
|
DDX_Check( pDX, IDC_ATTRIB_GENERAL_INDEX_CHECK, DDXIndexed );
|
|
DDX_Check( pDX, IDC_ATTRIB_GENERAL_ANR_CHECK, DDXANR );
|
|
DDX_Check( pDX, IDC_ATTRIB_GENERAL_CPYATTR_CHECK, DDXCopyOnDuplicate );
|
|
DDX_Check( pDX, IDC_ATTRIB_GENERAL_REPLICATED, DDXReplicatedToGC );
|
|
DDX_Check( pDX, IDC_ATTRIB_GENERAL_CONTAINERIZED_INDEX_CHECK, DDXContainerIndexed );
|
|
|
|
// Since we want the checkbox label to be positive
|
|
// the value is actually the opposite of defunct
|
|
|
|
int checkValue = !Defunct;
|
|
DDX_Check( pDX, IDC_ATTRIB_GENERAL_DEACTIVATE, checkValue );
|
|
DDXDefunct = !checkValue;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void
|
|
AttributeGeneralPage::OnIndexClick()
|
|
{
|
|
ASSERT( pObject );
|
|
if( pObject && g_Syntax[ pObject->SyntaxOrdinal ].m_fIsANRCapable )
|
|
{
|
|
GetDlgItem(IDC_ATTRIB_GENERAL_ANR_CHECK)->
|
|
EnableWindow( IsDlgButtonChecked(IDC_ATTRIB_GENERAL_INDEX_CHECK) );
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
AttributeGeneralPage::OnDeactivateClick()
|
|
{
|
|
if( !IsDlgButtonChecked(IDC_ATTRIB_GENERAL_DEACTIVATE) )
|
|
{
|
|
if( IDOK != AfxMessageBox( IDS_WARNING_DEFUNCT_SET, MB_OKCANCEL | MB_ICONWARNING ) )
|
|
{
|
|
CheckDlgButton( IDC_ATTRIB_GENERAL_DEACTIVATE, BST_UNCHECKED );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Search User class & aux classes for the specified attribute
|
|
BOOL
|
|
AttributeGeneralPage::IsAttributeInUserClass( const CString & strAttribDN )
|
|
{
|
|
BOOL fFound = FALSE;
|
|
ComponentData & Scope = pComponent->QueryComponentDataRef();
|
|
|
|
SchemaObject * pObject = Scope.g_SchemaCache.LookupSchemaObject(
|
|
CString( szUserClass ),
|
|
SCHMMGMT_CLASS );
|
|
//
|
|
// Call the attribute check routine. This routine
|
|
// will call itself recursively to search the
|
|
// inheritance structure of the class User.
|
|
//
|
|
if ( pObject ) {
|
|
|
|
fFound = RecursiveIsAttributeInUserClass( strAttribDN, pObject );
|
|
Scope.g_SchemaCache.ReleaseRef( pObject );
|
|
}
|
|
|
|
return fFound ;
|
|
}
|
|
|
|
|
|
// Search the user class & subclasses
|
|
BOOL
|
|
AttributeGeneralPage::RecursiveIsAttributeInUserClass(
|
|
const CString & strAttribDN,
|
|
SchemaObject * pObject )
|
|
{
|
|
BOOL fFound = FALSE;
|
|
|
|
//
|
|
// Don't process "top" here since everyone inherits from it.
|
|
//
|
|
|
|
// i don't think we ever get "top" here?
|
|
ASSERT( pObject->ldapDisplayName.CompareNoCase( szTopClass ) );
|
|
|
|
if ( !pObject->ldapDisplayName.CompareNoCase(szTopClass) )
|
|
return fFound;
|
|
|
|
DebugTrace( L"RecursiveIsAttributeInUserClass: %ls\n",
|
|
const_cast<LPWSTR>((LPCTSTR)pObject->ldapDisplayName) );
|
|
|
|
// Check every list
|
|
if( !SearchResultList( strAttribDN, pObject->systemMayContain) &&
|
|
!SearchResultList( strAttribDN, pObject->mayContain) &&
|
|
!SearchResultList( strAttribDN, pObject->systemMustContain) &&
|
|
!SearchResultList( strAttribDN, pObject->mustContain) )
|
|
{
|
|
//
|
|
// The attribute was not found in the given class, diging deeper...
|
|
// Check each auxiliary class...
|
|
//
|
|
|
|
fFound = TraverseAuxiliaryClassList( strAttribDN,
|
|
pObject->systemAuxiliaryClass );
|
|
|
|
if( !fFound )
|
|
{
|
|
fFound = TraverseAuxiliaryClassList( strAttribDN,
|
|
pObject->auxiliaryClass );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fFound = TRUE;
|
|
}
|
|
|
|
return fFound ;
|
|
}
|
|
|
|
|
|
// Linear search of the linked list for the string strAttribDN
|
|
|
|
BOOL
|
|
AttributeGeneralPage::SearchResultList(
|
|
const CString & strAttribDN,
|
|
ListEntry * pList )
|
|
{
|
|
// Traverse the list
|
|
while ( pList )
|
|
{
|
|
// Searching for the existance of the attribute
|
|
if( !pList->Attribute.CompareNoCase( strAttribDN ) )
|
|
return TRUE;
|
|
|
|
pList = pList->pNext;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// Traverse each auxiliary class by recursivly
|
|
// calling RecursiveIsAttributeInUserClass()
|
|
BOOL
|
|
AttributeGeneralPage::TraverseAuxiliaryClassList(
|
|
const CString & strAttribDN,
|
|
ListEntry * pList )
|
|
{
|
|
SchemaObject * pInheritFrom = NULL;
|
|
ComponentData & Scope = pComponent->QueryComponentDataRef();
|
|
BOOL fFound = FALSE;
|
|
|
|
while ( !fFound && pList ) {
|
|
|
|
pInheritFrom = Scope.g_SchemaCache.LookupSchemaObject( pList->Attribute,
|
|
SCHMMGMT_CLASS );
|
|
if ( pInheritFrom )
|
|
{
|
|
// recursive call
|
|
fFound = RecursiveIsAttributeInUserClass( strAttribDN, pInheritFrom );
|
|
|
|
Scope.g_SchemaCache.ReleaseRef( pInheritFrom );
|
|
}
|
|
|
|
pList = pList->pNext;
|
|
}
|
|
|
|
return fFound ;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
AttributeGeneralPage::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;
|
|
}
|