Source code of Windows XP (NT5)
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.

830 lines
21 KiB

  1. #include "stdafx.h"
  2. #include "compdata.h"
  3. #include "select.h"
  4. #include "classgen.hpp"
  5. /////////////////////////////////////////////////////////////////
  6. // ClassGeneralPage
  7. const CDialogControlsInfo ctrls[] =
  8. {
  9. { IDC_CLASS_GENERAL_DESCRIPTION_EDIT, g_Description, TRUE },
  10. { IDC_CATEGORY_CHANGE, g_DefaultCategory, FALSE },
  11. { IDC_CLASS_GENERAL_DISPLAYABLE_CHECK, g_ShowInAdvViewOnly, FALSE },
  12. { IDC_CLASS_DEACTIVATE, g_isDefunct, FALSE }
  13. };
  14. const DWORD ClassGeneralPage::help_map[] =
  15. {
  16. IDI_CLASS, NO_HELP,
  17. IDC_CLASS_GENERAL_NAME_STATIC, NO_HELP,
  18. IDC_CLASS_GENERAL_DESCRIPTION_EDIT, IDH_CLASS_GENERAL_DESCRIPTION_EDIT,
  19. IDC_CLASS_GENERAL_LDN, IDH_CLASS_GENERAL_LDN,
  20. IDC_CLASS_GENERAL_OID_EDIT, IDH_CLASS_GENERAL_OID_EDIT,
  21. IDC_CLASS_GENERAL_CATEGORY_COMBO, IDH_CLASS_GENERAL_CATEGORY_COMBO,
  22. IDC_CATEGORY_EDIT, IDH_CATEGORY_EDIT,
  23. IDC_CATEGORY_CHANGE, IDH_CATEGORY_CHANGE,
  24. IDC_CLASS_GENERAL_DISPLAYABLE_CHECK, IDH_CLASS_GENERAL_DISPLAYABLE_CHECK,
  25. IDC_CLASS_DEACTIVATE, IDH_CLASS_DEACTIVATE,
  26. IDC_CLASS_GENERAL_SYSCLASS_STATIC, NO_HELP,
  27. 0, 0
  28. };
  29. //
  30. // The MFC Message Map.
  31. //
  32. BEGIN_MESSAGE_MAP( ClassGeneralPage, CDialog )
  33. ON_BN_CLICKED( IDC_CATEGORY_CHANGE, OnButtonCategoryChange )
  34. ON_MESSAGE(WM_HELP, OnHelp)
  35. ON_MESSAGE(WM_CONTEXTMENU, OnContextHelp)
  36. ON_BN_CLICKED(IDC_CLASS_DEACTIVATE, OnDeactivateClick)
  37. END_MESSAGE_MAP()
  38. //
  39. // Class dialog box routines.
  40. //
  41. ClassGeneralPage::ClassGeneralPage( ComponentData *pScope ) :
  42. CPropertyPage( IDD_CLASS_GENERAL ),
  43. fDataLoaded( FALSE ),
  44. pIADsObject( NULL ),
  45. pObject( NULL ),
  46. pScopeControl( pScope )
  47. { ; }
  48. ClassGeneralPage::~ClassGeneralPage() {
  49. //
  50. // Always make sure we free the IADs object.
  51. //
  52. if ( pIADsObject ) {
  53. pIADsObject->Release();
  54. pIADsObject = NULL;
  55. }
  56. //
  57. // And release the cache!
  58. //
  59. if ( pObject ) {
  60. pScopeControl->g_SchemaCache.ReleaseRef( pObject );
  61. }
  62. }
  63. BOOL
  64. ClassGeneralPage::OnInitDialog()
  65. {
  66. CPropertyPage::OnInitDialog();
  67. CWnd* wnd = GetDlgItem(IDC_CLASS_GENERAL_DESCRIPTION_EDIT);
  68. ASSERT(wnd);
  69. if (wnd)
  70. {
  71. wnd->SendMessage(EM_SETLIMITTEXT, (WPARAM) 1024, 0);
  72. }
  73. return TRUE;
  74. }
  75. BOOL
  76. ClassGeneralPage::OnSetActive()
  77. {
  78. // If pIADsObject is NULL, close dialog box
  79. if( CPropertyPage::OnSetActive() )
  80. {
  81. if ( !pIADsObject )
  82. {
  83. return FALSE;
  84. }
  85. else
  86. {
  87. // always enable the Apply button
  88. SetModified(TRUE);
  89. return TRUE;
  90. }
  91. }
  92. else
  93. return FALSE;
  94. }
  95. void
  96. ClassGeneralPage::Load(
  97. Cookie& CookieRef
  98. ) {
  99. //
  100. // Store the cookie object pointer. Everything
  101. // else gets loaded when the page is displayed.
  102. //
  103. pCookie = &CookieRef;
  104. return;
  105. }
  106. void
  107. ClassGeneralPage::DoDataExchange(
  108. CDataExchange *pDX
  109. )
  110. /***
  111. This routine picks up the object name out of the
  112. cookie and then looks up the ADSI path name out of
  113. the schema object cache. It then drives the dialog
  114. box directly from the ADS object.
  115. ***/
  116. {
  117. HRESULT hr;
  118. CString szAdsPath;
  119. VARIANT AdsResult;
  120. DWORD dwClassType;
  121. CPropertyPage::DoDataExchange( pDX );
  122. VariantInit( &AdsResult );
  123. if ( !pDX->m_bSaveAndValidate ) {
  124. //
  125. // If this is not the initial load and is not
  126. // the save, just use the data that we've loaded.
  127. //
  128. if ( !fDataLoaded ) {
  129. CWaitCursor wait;
  130. //
  131. // Get the schema cache object and the actual ADS object.
  132. // Keep both around while the page is loaded.
  133. //
  134. pObject = pScopeControl->g_SchemaCache.LookupSchemaObjectByCN(
  135. pCookie->strSchemaObject,
  136. SCHMMGMT_CLASS );
  137. if ( pObject ) {
  138. pScopeControl->GetSchemaObjectPath( pObject->commonName, szAdsPath );
  139. if ( !szAdsPath.IsEmpty() ) {
  140. hr = ADsGetObject( (LPWSTR)(LPCWSTR)szAdsPath,
  141. IID_IADs,
  142. (void **)&pIADsObject );
  143. }
  144. }
  145. //
  146. // If we have no ADS object, we should error out!
  147. //
  148. if ( !pIADsObject ) {
  149. DoErrMsgBox( ::GetActiveWindow(), TRUE, IDS_ERR_NO_SCHEMA_OBJECT );
  150. // Because there is no pIADsObject, OnSetActive() will close dialog box
  151. return;
  152. }
  153. //
  154. // ObjectName - Use the ldapDisplayName to be consistent with
  155. // the other admin components.
  156. //
  157. hr = pIADsObject->Get( const_cast<BSTR>((LPCTSTR)g_DisplayName),
  158. &AdsResult );
  159. if ( SUCCEEDED( hr ) ) {
  160. ASSERT( AdsResult.vt == VT_BSTR );
  161. ObjectName = AdsResult.bstrVal;
  162. VariantClear( &AdsResult );
  163. }
  164. //
  165. //
  166. // CommonName
  167. //
  168. hr = pIADsObject->Get( const_cast<BSTR>((LPCTSTR)g_CN),
  169. &AdsResult );
  170. if ( SUCCEEDED( hr ) ) {
  171. ASSERT( AdsResult.vt == VT_BSTR );
  172. DisplayName = AdsResult.bstrVal;
  173. VariantClear( &AdsResult );
  174. }
  175. //
  176. // Description
  177. //
  178. hr = pIADsObject->Get( const_cast<BSTR>((LPCTSTR)g_Description),
  179. &AdsResult );
  180. if ( SUCCEEDED( hr ) ) {
  181. ASSERT( AdsResult.vt == VT_BSTR );
  182. Description = AdsResult.bstrVal;
  183. DDXDescription = AdsResult.bstrVal;
  184. VariantClear( &AdsResult );
  185. }
  186. //
  187. // OID
  188. //
  189. hr = pIADsObject->Get( const_cast<BSTR>((LPCTSTR)g_GlobalClassID),
  190. &AdsResult );
  191. if ( SUCCEEDED( hr ) ) {
  192. ASSERT( AdsResult.vt == VT_BSTR );
  193. OidString = AdsResult.bstrVal;
  194. VariantClear( &AdsResult );
  195. }
  196. //
  197. // Displayable
  198. //
  199. Displayable = TRUE;
  200. DDXDisplayable = TRUE;
  201. hr = pIADsObject->Get(g_ShowInAdvViewOnly, &AdsResult);
  202. if ( SUCCEEDED( hr ) ) {
  203. ASSERT( AdsResult.vt == VT_BOOL );
  204. if ( AdsResult.boolVal == -1 ) {
  205. Displayable = FALSE;
  206. DDXDisplayable = FALSE;
  207. }
  208. VariantClear( &AdsResult );
  209. }
  210. //
  211. // Defunct
  212. //
  213. Defunct = FALSE;
  214. DDXDefunct = FALSE;
  215. hr = pIADsObject->Get( const_cast<BSTR>((LPCTSTR)g_isDefunct),
  216. &AdsResult );
  217. if ( SUCCEEDED( hr ) ) {
  218. ASSERT( AdsResult.vt == VT_BOOL );
  219. if ( AdsResult.boolVal == -1 ) {
  220. Defunct = TRUE;
  221. DDXDefunct = TRUE;
  222. }
  223. VariantClear( &AdsResult );
  224. }
  225. //
  226. // SysClass
  227. //
  228. hr = pIADsObject->Get( const_cast<BSTR>((LPCTSTR)g_SystemOnly),
  229. &AdsResult );
  230. if ( SUCCEEDED( hr ) ) {
  231. ASSERT( AdsResult.vt == VT_BOOL );
  232. if ( AdsResult.boolVal ) {
  233. SysClassString = g_SysClassString;
  234. } else {
  235. SysClassString = L"";
  236. }
  237. VariantClear( &AdsResult );
  238. } else {
  239. SysClassString = L"";
  240. }
  241. //
  242. // ClassType
  243. //
  244. hr = pIADsObject->Get( const_cast<BSTR>((LPCTSTR)g_ObjectClassCategory),
  245. &AdsResult );
  246. if ( SUCCEEDED( hr ) ) {
  247. ASSERT( AdsResult.vt == VT_I4 );
  248. dwClassType = V_I4( &AdsResult );
  249. VariantClear( &AdsResult );
  250. switch ( dwClassType ) {
  251. case 0:
  252. ClassType = g_88Class;
  253. break;
  254. case 1:
  255. ClassType = g_StructuralClass;
  256. break;
  257. case 2:
  258. ClassType = g_AbstractClass;
  259. break;
  260. case 3:
  261. ClassType = g_AuxClass;
  262. break;
  263. default:
  264. ClassType = g_Unknown;
  265. break;
  266. }
  267. }
  268. //
  269. // Category
  270. //
  271. hr = pIADsObject->Get( const_cast<BSTR>((LPCTSTR)g_DefaultCategory),
  272. &AdsResult );
  273. if ( SUCCEEDED( hr ) ) {
  274. ASSERT( V_VT(&AdsResult) == VT_BSTR );
  275. CString strCN;
  276. if( SUCCEEDED( pScopeControl->GetLeafObjectFromDN( V_BSTR(&AdsResult), strCN ) ))
  277. {
  278. //
  279. // Look up the ldapDisplayName.
  280. //
  281. SchemaObject * pCategory =
  282. pScopeControl->g_SchemaCache.LookupSchemaObjectByCN( strCN, SCHMMGMT_CLASS );
  283. if ( pCategory )
  284. {
  285. Category = DDXCategory = pCategory->ldapDisplayName;
  286. pScopeControl->g_SchemaCache.ReleaseRef( pCategory );
  287. }
  288. else
  289. {
  290. Category = DDXCategory = strCN;
  291. }
  292. }
  293. VariantClear( &AdsResult );
  294. }
  295. // Determine if this is a category 1 object & disable read-only fields
  296. BOOL fIsSystemObject = FALSE;
  297. hr = IsCategory1Object( pIADsObject, fIsSystemObject );
  298. if( SUCCEEDED(hr) && fIsSystemObject )
  299. {
  300. ASSERT( GetDlgItem(IDC_CATEGORY_CHANGE) );
  301. ASSERT( GetDlgItem(IDC_CLASS_DEACTIVATE) );
  302. GetDlgItem(IDC_CATEGORY_CHANGE)->EnableWindow( FALSE );
  303. GetDlgItem(IDC_CLASS_DEACTIVATE)->EnableWindow( FALSE );
  304. }
  305. hr = DissableReadOnlyAttributes( this, pIADsObject, ctrls, sizeof(ctrls)/sizeof(ctrls[0]) );
  306. ASSERT( SUCCEEDED(hr) ); // shouldn't fail, but unimportant, so ignore error
  307. // warn the user if this is a read/write defunct object
  308. ASSERT( GetDlgItem(IDC_CLASS_DEACTIVATE) );
  309. if( DDXDefunct &&
  310. GetDlgItem(IDC_CLASS_DEACTIVATE)->IsWindowEnabled() )
  311. {
  312. AfxMessageBox( IDS_WARNING_DEFUNCT, MB_OK | MB_ICONINFORMATION );
  313. }
  314. //
  315. // Remember that the data is loaded.
  316. //
  317. fDataLoaded = TRUE;
  318. }
  319. }
  320. //
  321. // Set up the dialog data exchange.
  322. //
  323. DDX_Text( pDX, IDC_CLASS_GENERAL_NAME_STATIC, ObjectName );
  324. DDX_Text( pDX, IDC_CLASS_GENERAL_CATEGORY_COMBO, ClassType );
  325. DDX_Text( pDX, IDC_CLASS_GENERAL_SYSCLASS_STATIC, SysClassString );
  326. DDX_Text( pDX, IDC_CLASS_GENERAL_DESCRIPTION_EDIT, DDXDescription );
  327. DDX_Text( pDX, IDC_CLASS_GENERAL_LDN, DisplayName );
  328. DDX_Text( pDX, IDC_CLASS_GENERAL_OID_EDIT, OidString );
  329. DDX_Text( pDX, IDC_CATEGORY_EDIT, DDXCategory );
  330. DDX_Check( pDX, IDC_CLASS_GENERAL_DISPLAYABLE_CHECK, DDXDisplayable );
  331. // Since we want the checkbox label to be positive
  332. // the value is actually the opposite of defunct
  333. int checkValue = !Defunct;
  334. DDX_Check( pDX, IDC_CLASS_DEACTIVATE, checkValue );
  335. DDXDefunct = !checkValue;
  336. return;
  337. }
  338. BOOL
  339. ClassGeneralPage::OnApply(
  340. VOID
  341. ) {
  342. HRESULT hr;
  343. VARIANT AdsValue;
  344. BOOL fChangesMade = FALSE;
  345. BOOL fApplyAbort = FALSE; // stop later saves
  346. BOOL fApplyFailed = FALSE; // should not close the box
  347. if ( !UpdateData(TRUE) ) {
  348. return FALSE;
  349. }
  350. //
  351. // We have to flush the IADS property cache if we
  352. // have a failure so later operations won't fail because
  353. // of a bad cached attribute.
  354. //
  355. IADsPropertyList *pPropertyList;
  356. hr = pIADsObject->QueryInterface( IID_IADsPropertyList,
  357. reinterpret_cast<void**>(&pPropertyList) );
  358. if ( FAILED( hr ) ) {
  359. pPropertyList = NULL;
  360. fApplyAbort = TRUE;
  361. }
  362. //
  363. // We only care if the description, class type, or
  364. // displayable attributes changed.
  365. //
  366. VariantInit( &AdsValue );
  367. //
  368. // Defunct -- in case it was deactivated, activate the object first
  369. //
  370. if( !fApplyAbort && !DDXDefunct && DDXDefunct != Defunct )
  371. {
  372. hr = ChangeDefunctState( DDXDefunct, Defunct, pPropertyList, fApplyAbort, fApplyFailed );
  373. }
  374. if ( !fApplyAbort && DDXDescription != Description ) {
  375. V_VT(&AdsValue) = VT_BSTR;
  376. V_BSTR(&AdsValue) = const_cast<BSTR>((LPCTSTR)DDXDescription);
  377. if ( DDXDescription.IsEmpty() ) {
  378. hr = pIADsObject->PutEx( ADS_PROPERTY_CLEAR,
  379. const_cast<BSTR>((LPCTSTR)g_Description),
  380. AdsValue );
  381. } else {
  382. hr = pIADsObject->Put( const_cast<BSTR>((LPCTSTR)g_Description),
  383. AdsValue );
  384. }
  385. ASSERT( SUCCEEDED( hr ) );
  386. hr = pIADsObject->SetInfo();
  387. if ( SUCCEEDED( hr ) ) {
  388. pObject->description = DDXDescription;
  389. fChangesMade = TRUE;
  390. Description = DDXDescription;
  391. } else {
  392. pPropertyList->PurgePropertyList();
  393. if( ERROR_DS_UNWILLING_TO_PERFORM == HRESULT_CODE(hr) )
  394. {
  395. fApplyFailed = TRUE;
  396. DoErrMsgBox( ::GetActiveWindow(), TRUE, IDS_ERR_EDIT_DESC );
  397. }
  398. else
  399. {
  400. fApplyAbort = TRUE;
  401. DoErrMsgBox( ::GetActiveWindow(), TRUE, GetErrorMessage(hr,TRUE) );
  402. }
  403. }
  404. VariantInit( &AdsValue );
  405. }
  406. if ( !fApplyAbort && DDXDisplayable != Displayable ) {
  407. V_VT(&AdsValue) = VT_BOOL;
  408. if ( DDXDisplayable ) {
  409. V_BOOL(&AdsValue) = 0;
  410. } else {
  411. V_BOOL(&AdsValue) = -1;
  412. }
  413. hr = pIADsObject->Put(g_ShowInAdvViewOnly, AdsValue);
  414. ASSERT( SUCCEEDED( hr ) );
  415. hr = pIADsObject->SetInfo();
  416. if ( FAILED( hr ) ) {
  417. pPropertyList->PurgePropertyList();
  418. if( ERROR_DS_UNWILLING_TO_PERFORM == HRESULT_CODE(hr) )
  419. {
  420. fApplyFailed = TRUE;
  421. DoErrMsgBox( ::GetActiveWindow(), TRUE, IDS_ERR_EDIT_DISPLAYABLE );
  422. }
  423. else
  424. {
  425. fApplyAbort = TRUE;
  426. DoErrMsgBox( ::GetActiveWindow(), TRUE, GetErrorMessage(hr,TRUE) );
  427. }
  428. }
  429. else
  430. {
  431. Displayable = DDXDisplayable;
  432. }
  433. VariantInit( &AdsValue );
  434. }
  435. if ( !fApplyAbort && DDXCategory != Category ) {
  436. SchemaObject *pCategoryObject;
  437. CString DistName;
  438. hr = E_FAIL;
  439. V_VT(&AdsValue) = VT_BSTR;
  440. //
  441. // Map the commonName to the distinguished name.
  442. //
  443. pCategoryObject = pScopeControl->g_SchemaCache.LookupSchemaObjectByCN(
  444. DisplayName,
  445. SCHMMGMT_CLASS );
  446. if ( pCategoryObject ) {
  447. pScopeControl->GetSchemaObjectPath( pCategoryObject->commonName, DistName, ADS_FORMAT_X500_DN );
  448. V_BSTR(&AdsValue) = const_cast<BSTR>((LPCTSTR)DistName);
  449. hr = pIADsObject->Put( const_cast<BSTR>((LPCTSTR)g_DefaultCategory),
  450. AdsValue );
  451. ASSERT( SUCCEEDED( hr ) );
  452. hr = pIADsObject->SetInfo();
  453. }
  454. if ( FAILED( hr ) ) {
  455. pPropertyList->PurgePropertyList();
  456. if( ERROR_DS_UNWILLING_TO_PERFORM == HRESULT_CODE(hr) )
  457. {
  458. fApplyFailed = TRUE;
  459. DoErrMsgBox( ::GetActiveWindow(), TRUE, IDS_ERR_EDIT_CATEGORY );
  460. }
  461. else
  462. {
  463. fApplyAbort = TRUE;
  464. DoErrMsgBox( ::GetActiveWindow(), TRUE, GetErrorMessage(hr,TRUE) );
  465. }
  466. }
  467. else
  468. {
  469. Category = DDXCategory;
  470. }
  471. VariantInit( &AdsValue );
  472. }
  473. //
  474. // Defunct -- in case it was active, deactivate the object after we are done update
  475. //
  476. if( !fApplyAbort && DDXDefunct && DDXDefunct != Defunct )
  477. {
  478. hr = ChangeDefunctState( DDXDefunct, Defunct, pPropertyList, fApplyAbort, fApplyFailed );
  479. }
  480. if ( !fApplyAbort && fChangesMade ) {
  481. //
  482. // Call SetItem() so this gets refreshed.
  483. //
  484. SCOPEDATAITEM ScopeItem;
  485. CCookieListEntry *pEntry;
  486. BOOLEAN fFoundId = FALSE;
  487. if ( pScopeControl->g_ClassCookieList.pHead ) {
  488. pEntry = pScopeControl->g_ClassCookieList.pHead;
  489. if ( (pScopeControl->g_ClassCookieList.pHead)->pCookie == pCookie ) {
  490. fFoundId = TRUE;
  491. } else {
  492. while ( pEntry->pNext != pScopeControl->g_ClassCookieList.pHead ) {
  493. if ( pEntry->pCookie == pCookie ) {
  494. fFoundId = TRUE;
  495. break;
  496. }
  497. pEntry = pEntry->pNext;
  498. }
  499. }
  500. if ( fFoundId ) {
  501. ::ZeroMemory( &ScopeItem, sizeof(ScopeItem) );
  502. ScopeItem.mask = SDI_STR | SDI_IMAGE | SDI_OPENIMAGE | SDI_PARAM | SDI_PARENT;
  503. ScopeItem.displayname = MMC_CALLBACK;
  504. ScopeItem.relativeID = pScopeControl->g_ClassCookieList.hParentScopeItem;
  505. ScopeItem.nState = 0;
  506. ScopeItem.lParam = reinterpret_cast<LPARAM>((CCookie*)pCookie);
  507. ScopeItem.nImage = pScopeControl->QueryImage( *pCookie, FALSE );
  508. ScopeItem.nOpenImage = pScopeControl->QueryImage( *pCookie, TRUE );
  509. ScopeItem.ID = pEntry->hScopeItem;
  510. hr = pScopeControl->m_pConsoleNameSpace->SetItem( &ScopeItem );
  511. ASSERT( SUCCEEDED( hr ));
  512. }
  513. }
  514. }
  515. if ( pPropertyList ) {
  516. pPropertyList->Release();
  517. }
  518. return !fApplyAbort && !fApplyFailed ; // return TRUE if nothing happened
  519. }
  520. VOID
  521. ClassGeneralPage::OnButtonCategoryChange(
  522. ) {
  523. SchemaObject *pClass = NULL;
  524. INT_PTR DlgResult;
  525. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  526. //
  527. // Update any changes the user has made.
  528. //
  529. UpdateData( TRUE );
  530. //
  531. // Start the common select dialog box.
  532. //
  533. CSchmMgmtSelect dlgSelect( pScopeControl,
  534. SELECT_CLASSES,
  535. &pClass );
  536. DlgResult = dlgSelect.DoModal();
  537. //
  538. // When this returns, the class schema object
  539. // pointer will be filled into pClass.
  540. //
  541. if ( ( DlgResult == IDOK ) &&
  542. ( pClass != NULL ) ) {
  543. DDXCategory = pClass->ldapDisplayName;
  544. //
  545. // Push this back out to the UI.
  546. //
  547. UpdateData( FALSE );
  548. }
  549. return;
  550. }
  551. void
  552. ClassGeneralPage::OnDeactivateClick()
  553. {
  554. if( !IsDlgButtonChecked(IDC_CLASS_DEACTIVATE) )
  555. {
  556. if( IDOK != AfxMessageBox( IDS_WARNING_DEFUNCT_SET, MB_OKCANCEL | MB_ICONWARNING ) )
  557. {
  558. CheckDlgButton( IDC_CLASS_DEACTIVATE, BST_UNCHECKED );
  559. }
  560. }
  561. }
  562. HRESULT
  563. ClassGeneralPage::ChangeDefunctState( BOOL DDXDefunct,
  564. BOOL & Defunct,
  565. IADsPropertyList * pPropertyList,
  566. BOOL & fApplyAbort,
  567. BOOL & fApplyFailed )
  568. {
  569. ASSERT( !fApplyAbort && DDXDefunct != Defunct );
  570. VARIANT AdsValue;
  571. HRESULT hr = S_OK;
  572. VariantInit( &AdsValue );
  573. V_VT(&AdsValue) = VT_BOOL;
  574. if ( DDXDefunct ) {
  575. V_BOOL(&AdsValue) = -1;
  576. } else {
  577. V_BOOL(&AdsValue) = 0;
  578. }
  579. hr = pIADsObject->Put( const_cast<BSTR>((LPCTSTR)g_isDefunct),
  580. AdsValue );
  581. ASSERT( SUCCEEDED( hr ) );
  582. hr = pIADsObject->SetInfo();
  583. if ( FAILED( hr ) ) {
  584. pPropertyList->PurgePropertyList();
  585. if( ERROR_DS_UNWILLING_TO_PERFORM == HRESULT_CODE(hr) )
  586. {
  587. fApplyFailed = TRUE;
  588. DoErrMsgBox( ::GetActiveWindow(),
  589. TRUE,
  590. DDXDefunct ? IDS_ERR_EDIT_DEFUNCT_SET : IDS_ERR_EDIT_DEFUNCT_REMOVE );
  591. }
  592. else
  593. {
  594. fApplyAbort = TRUE;
  595. DoErrMsgBox( ::GetActiveWindow(), TRUE, GetErrorMessage(hr,TRUE) );
  596. }
  597. } else {
  598. pObject->isDefunct = DDXDefunct;
  599. Defunct = DDXDefunct;
  600. }
  601. return hr;
  602. }