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.

686 lines
17 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1998 - 1999
  6. //
  7. // File: editorui.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. #include "pch.h"
  11. #include <SnapBase.h>
  12. #include "resource.h"
  13. #include "attredit.h"
  14. #include "adsiedit.h"
  15. #include "editor.h"
  16. #include "editorui.h"
  17. #include "snapdata.h"
  18. #include "common.h"
  19. #include <aclpage.h>
  20. #include <dssec.h> // For AclEditor flags
  21. #include "connection.h"
  22. #ifdef DEBUG_ALLOCATOR
  23. #ifdef _DEBUG
  24. #define new DEBUG_NEW
  25. #undef THIS_FILE
  26. static char THIS_FILE[] = __FILE__;
  27. #endif
  28. #endif
  29. ////////////////////////////////////////////////////////////////////////////
  30. // this is used to fill in the attributes for RootDSE
  31. //
  32. typedef struct tagRootDSEAttr
  33. {
  34. LPCWSTR lpszAttr;
  35. LPCWSTR lpszSyntax;
  36. BOOL bMulti;
  37. } SYNTAXMAP;
  38. SYNTAXMAP g_ldapRootDSESyntax[] =
  39. {
  40. _T("currentTime"), _T("UTCTime"), FALSE,
  41. _T("subschemaSubentry"), _T("String"), FALSE,
  42. _T("serverName"), _T("String"), FALSE,
  43. _T("namingContexts"), _T("String"), TRUE,
  44. _T("defaultNamingContext"), _T("String"), FALSE,
  45. _T("schemaNamingContext"), _T("String"), FALSE,
  46. _T("configurationNamingContext"), _T("String"), FALSE,
  47. _T("rootDomainNamingContext"), _T("String"), FALSE,
  48. _T("supportedControl"), _T("String"), TRUE,
  49. _T("supportedLDAPVersion"), _T("Integer"), TRUE,
  50. _T("supportedLDAPPolicies"), _T("String"), TRUE,
  51. _T("supportedSASLMechanisms"), _T("String"), TRUE,
  52. _T("dsServiceName"), _T("String"), FALSE,
  53. _T("dnsHostName"), _T("String"), FALSE,
  54. _T("supportedCapabilities"), _T("String"), TRUE,
  55. _T("ldapServiceName"), _T("String"), FALSE,
  56. _T("highestCommittedUsn"), _T("String"), FALSE, // this should be an integer but after investigation I found it was a string
  57. NULL, 0,
  58. };
  59. extern LPCWSTR g_lpszGC;
  60. /////////////////////////////////////////////////////////////////////////
  61. BEGIN_MESSAGE_MAP(CADSIEditPropertyPage, CPropertyPageBase)
  62. //{{AFX_MSG_MAP(CADsObjectDialog)
  63. ON_CBN_SELCHANGE(IDC_PROP_BOX, OnSelChangeAttrList)
  64. ON_CBN_SELCHANGE(IDC_PROPTYPES_BOX, OnSelChangePropList)
  65. //}}AFX_MSG_MAP
  66. END_MESSAGE_MAP()
  67. CADSIEditPropertyPage::CADSIEditPropertyPage()
  68. : CPropertyPageBase(IDD_PROPERTY_PAGE)
  69. {
  70. m_bExisting = TRUE;
  71. }
  72. CADSIEditPropertyPage::CADSIEditPropertyPage(CAttrList* pAttrs)
  73. : CPropertyPageBase(IDD_PROPERTY_PAGE)
  74. {
  75. ASSERT(pAttrs != NULL);
  76. m_pOldAttrList = pAttrs;
  77. m_bExisting = FALSE;
  78. CopyAttrList(pAttrs);
  79. }
  80. void CADSIEditPropertyPage::CopyAttrList(CAttrList* pAttrList)
  81. {
  82. m_AttrList.RemoveAll();
  83. POSITION pos = pAttrList->GetHeadPosition();
  84. while (pos != NULL)
  85. {
  86. m_AttrList.AddHead(pAttrList->GetNext(pos));
  87. }
  88. }
  89. BOOL CADSIEditPropertyPage::OnInitDialog()
  90. {
  91. CPropertyPageBase::OnInitDialog();
  92. // Get the dialog items
  93. //
  94. CEdit* pPathBox = (CEdit*)GetDlgItem(IDC_PATH_BOX);
  95. CEdit* pClassBox = (CEdit*)GetDlgItem(IDC_CLASS_BOX);
  96. CComboBox* pPropSelectBox = (CComboBox*)GetDlgItem(IDC_PROPTYPES_BOX);
  97. CComboBox* pPropertyBox = (CComboBox*)GetDlgItem(IDC_PROP_BOX);
  98. CStatic* pPathLabel = (CStatic*)GetDlgItem(IDC_PATH_LABEL);
  99. CStatic* pClassLabel = (CStatic*)GetDlgItem(IDC_CLASS_LABEL);
  100. CStatic* pFilterLabel = (CStatic*)GetDlgItem(IDC_FILTER_LABEL);
  101. CStatic* pPropertyLabel = (CStatic*)GetDlgItem(IDC_PROPERTY_LABEL);
  102. CStatic* pSyntaxLabel = (CStatic*)GetDlgItem(IDC_SYNTAX_LABEL);
  103. CStatic* pEditLabel = (CStatic*)GetDlgItem(IDC_EDIT_LABEL);
  104. CStatic* pValueLabel = (CStatic*)GetDlgItem(IDC_VALUE_LABEL);
  105. CButton* pAttrGroup = (CButton*)GetDlgItem(IDC_ATTR_GROUP);
  106. CStatic* pNoInfoLabel = (CStatic*)GetDlgItem(IDC_NO_INFO);
  107. if (m_bExisting)
  108. {
  109. // This determines whether the node is complete with data or not. If not we won't enable
  110. // the UI
  111. //
  112. BOOL bComplete = TRUE;
  113. CADsObject* pADsObject = NULL;
  114. CTreeNode* pTreeNode = GetHolder()->GetTreeNode();
  115. CADSIEditContainerNode* pContNode = dynamic_cast<CADSIEditContainerNode*>(pTreeNode);
  116. if (pContNode == NULL)
  117. {
  118. CADSIEditLeafNode* pLeafNode = dynamic_cast<CADSIEditLeafNode*>(pTreeNode);
  119. ASSERT(pLeafNode != NULL);
  120. pADsObject = pLeafNode->GetADsObject();
  121. m_pConnectData = pADsObject->GetConnectionNode()->GetConnectionData();
  122. bComplete = pADsObject->IsComplete();
  123. }
  124. else
  125. {
  126. pADsObject = pContNode->GetADsObject();
  127. m_pConnectData = pADsObject->GetConnectionNode()->GetConnectionData();
  128. bComplete = pADsObject->IsComplete();
  129. }
  130. // Initialize the attribute editor
  131. //
  132. m_attrEditor.Initialize(this, pTreeNode, m_sServer,
  133. IDC_EDITVALUE_BOX, IDC_SYNTAX_BOX,
  134. IDC_VALUE_EDITBOX, IDC_VALUE_LISTBOX,
  135. IDC_ADD_BUTTON, IDC_REMOVE_BUTTON,
  136. bComplete);
  137. // Get the UI to reflect the data
  138. //
  139. if ( bComplete)
  140. {
  141. pPathBox->SetWindowText(m_sPath);
  142. GetProperties();
  143. pClassBox->SetWindowText(m_sClass);
  144. CString sMand, sOpt, sBoth;
  145. if (!sMand.LoadString(IDS_MANDATORY) ||
  146. !sOpt.LoadString(IDS_OPTIONAL) ||
  147. !sBoth.LoadString(IDS_BOTH))
  148. {
  149. ADSIEditMessageBox(IDS_MSG_FAIL_TO_LOAD, MB_OK);
  150. }
  151. if (m_pConnectData->IsRootDSE())
  152. {
  153. pPropSelectBox->AddString(sMand);
  154. pPropSelectBox->SetCurSel(0);
  155. }
  156. else
  157. {
  158. pPropSelectBox->AddString(sMand);
  159. pPropSelectBox->AddString(sOpt);
  160. pPropSelectBox->AddString(sBoth);
  161. pPropSelectBox->SetCurSel(1);
  162. }
  163. OnSelChangePropList();
  164. pPropertyBox->SetCurSel(0);
  165. }
  166. else
  167. {
  168. pClassBox->ShowWindow(SW_HIDE);
  169. pPropSelectBox->ShowWindow(SW_HIDE);
  170. pPropertyBox->ShowWindow(SW_HIDE);
  171. pPathLabel->ShowWindow(SW_HIDE);
  172. pClassLabel->ShowWindow(SW_HIDE);
  173. pFilterLabel->ShowWindow(SW_HIDE);
  174. pPropertyLabel->ShowWindow(SW_HIDE);
  175. pSyntaxLabel->ShowWindow(SW_HIDE);
  176. pEditLabel->ShowWindow(SW_HIDE);
  177. pValueLabel->ShowWindow(SW_HIDE);
  178. pAttrGroup->ShowWindow(SW_HIDE);
  179. pNoInfoLabel->ShowWindow(SW_SHOW);
  180. }
  181. }
  182. else
  183. {
  184. // Initialize the attribute editor
  185. //
  186. m_attrEditor.Initialize(this, m_pConnectData, m_sServer,
  187. IDC_EDITVALUE_BOX, IDC_SYNTAX_BOX,
  188. IDC_VALUE_EDITBOX, IDC_VALUE_LISTBOX,
  189. IDC_ADD_BUTTON, IDC_REMOVE_BUTTON,
  190. TRUE, &m_AttrList);
  191. pPathBox->SetWindowText(m_sPath);
  192. GetProperties();
  193. pClassBox->SetWindowText(m_sClass);
  194. CString sMand, sOpt, sBoth;
  195. if (!sMand.LoadString(IDS_MANDATORY) ||
  196. !sOpt.LoadString(IDS_OPTIONAL) ||
  197. !sBoth.LoadString(IDS_BOTH))
  198. {
  199. ADSIEditMessageBox(IDS_MSG_FAIL_TO_LOAD, MB_OK);
  200. }
  201. if (m_pConnectData->IsRootDSE())
  202. {
  203. pPropSelectBox->AddString(sMand);
  204. pPropSelectBox->SetCurSel(0);
  205. }
  206. else
  207. {
  208. pPropSelectBox->AddString(sMand);
  209. pPropSelectBox->AddString(sOpt);
  210. pPropSelectBox->AddString(sBoth);
  211. pPropSelectBox->SetCurSel(1);
  212. }
  213. OnSelChangePropList();
  214. pPropertyBox->SetCurSel(0);
  215. }
  216. return TRUE;
  217. }
  218. BOOL CADSIEditPropertyPage::OnApply()
  219. {
  220. if( m_attrEditor.OnApply())
  221. {
  222. if (!m_bExisting)
  223. {
  224. m_pOldAttrList->RemoveAll();
  225. while (!m_AttrList.IsEmpty())
  226. {
  227. m_pOldAttrList->AddTail(m_AttrList.RemoveTail());
  228. }
  229. }
  230. }
  231. else
  232. {
  233. return FALSE;
  234. }
  235. return TRUE;
  236. }
  237. void CADSIEditPropertyPage::OnCancel()
  238. {
  239. if (!m_bExisting)
  240. {
  241. while (!m_AttrList.IsEmpty())
  242. {
  243. CADSIAttr* pAttr = m_AttrList.RemoveTail();
  244. ASSERT(pAttr != NULL);
  245. CString szProp;
  246. pAttr->GetProperty(szProp);
  247. if (!m_pOldAttrList->HasProperty(szProp))
  248. {
  249. delete pAttr;
  250. }
  251. }
  252. }
  253. }
  254. void CADSIEditPropertyPage::SetAttrList(CAttrList* pAttrList)
  255. {
  256. ASSERT(pAttrList != NULL);
  257. m_pOldAttrList = pAttrList;
  258. }
  259. void CADSIEditPropertyPage::OnSelChangePropList()
  260. {
  261. // Filter the properties list
  262. //
  263. FillAttrList();
  264. OnSelChangeAttrList();
  265. }
  266. void CADSIEditPropertyPage::OnSelChangeAttrList()
  267. {
  268. CComboBox* pPropertyBox = (CComboBox*)GetDlgItem(IDC_PROP_BOX);
  269. int idx, iCount;
  270. CString s;
  271. HRESULT hr;
  272. idx = pPropertyBox->GetCurSel();
  273. // Make sure a property was selected
  274. //
  275. if ( idx == LB_ERR )
  276. {
  277. return;
  278. }
  279. pPropertyBox->GetLBText( idx, s );
  280. // Have the attribute editor display the values for the new property
  281. //
  282. m_attrEditor.SetAttribute(s, m_sPath);
  283. }
  284. BOOL CADSIEditPropertyPage::GetProperties()
  285. {
  286. CString schema;
  287. //Get the class object so that we can get the properties
  288. //
  289. if (!m_pConnectData->IsRootDSE()) // Not RootDSE
  290. {
  291. m_pConnectData->GetAbstractSchemaPath(schema);
  292. schema += m_sClass;
  293. // bind to object with authentication
  294. //
  295. CComPtr<IADsClass> pClass;
  296. HRESULT hr, hCredResult;
  297. hr = OpenObjectWithCredentials(
  298. m_pConnectData,
  299. m_pConnectData->GetCredentialObject()->UseCredentials(),
  300. (LPWSTR)(LPCWSTR)schema,
  301. IID_IADsClass,
  302. (LPVOID*) &pClass,
  303. GetSafeHwnd(),
  304. hCredResult
  305. );
  306. if ( FAILED(hr) )
  307. {
  308. if (SUCCEEDED(hCredResult))
  309. {
  310. ADSIEditErrorMessage(hr);
  311. }
  312. return FALSE;
  313. }
  314. // Get the Mandatory Properties
  315. //
  316. VARIANT var;
  317. VariantInit(&var);
  318. hr = pClass->get_MandatoryProperties(&var);
  319. if ( FAILED(hr) )
  320. {
  321. ADSIEditErrorMessage(hr);
  322. return FALSE;
  323. }
  324. VariantToStringList( var, m_sMandatoryAttrList );
  325. VariantClear(&var);
  326. // Remove the nTSecurityDescriptor from the list because the aclEditor replaces it for ui purposes
  327. //
  328. m_sMandatoryAttrList.RemoveAt(m_sMandatoryAttrList.Find(_T("nTSecurityDescriptor")));
  329. // Get the Optional Properties
  330. //
  331. VariantInit(&var);
  332. hr = pClass->get_OptionalProperties(&var);
  333. if ( FAILED(hr) )
  334. {
  335. ADSIEditErrorMessage(hr);
  336. return FALSE;
  337. }
  338. VariantToStringList( var, m_sOptionalAttrList );
  339. VariantClear(&var);
  340. }
  341. else // RootDSE
  342. {
  343. int idx=0;
  344. // Add in the predefined attributes for the RootDSE
  345. //
  346. while( g_ldapRootDSESyntax[idx].lpszAttr )
  347. {
  348. m_sMandatoryAttrList.AddTail(g_ldapRootDSESyntax[idx].lpszAttr);
  349. idx++;
  350. }
  351. }
  352. return TRUE;
  353. }
  354. void CADSIEditPropertyPage::FillAttrList()
  355. {
  356. CComboBox* pPropSelectBox = (CComboBox*)GetDlgItem(IDC_PROPTYPES_BOX);
  357. CComboBox* pPropertyBox = (CComboBox*)GetDlgItem(IDC_PROP_BOX);
  358. POSITION pos;
  359. CString s;
  360. // Clean out the property box
  361. //
  362. int iCount = pPropertyBox->GetCount();
  363. while (iCount > 0)
  364. {
  365. pPropertyBox->DeleteString(0);
  366. iCount--;
  367. }
  368. // Get the filter to use
  369. //
  370. int idx = pPropSelectBox->GetCurSel();
  371. if ( idx == LB_ERR )
  372. {
  373. return;
  374. }
  375. // Fill in the property box using the filter
  376. //
  377. if (idx == IDS_BOTH - IDS_MANDATORY)
  378. {
  379. AddPropertiesToBox(TRUE, TRUE);
  380. }
  381. else if (idx == IDS_MANDATORY - IDS_MANDATORY)
  382. {
  383. AddPropertiesToBox(TRUE, FALSE);
  384. }
  385. else
  386. {
  387. AddPropertiesToBox(FALSE, TRUE);
  388. }
  389. pPropertyBox->SetCurSel(0);
  390. }
  391. void CADSIEditPropertyPage::AddPropertiesToBox(BOOL bMand, BOOL bOpt)
  392. {
  393. CComboBox* pPropertyBox = (CComboBox*)GetDlgItem(IDC_PROP_BOX);
  394. POSITION pos;
  395. if (bMand)
  396. {
  397. // Add Mandatory Properties
  398. //
  399. pos = m_sMandatoryAttrList.GetHeadPosition();
  400. while( pos != NULL )
  401. {
  402. CString s = m_sMandatoryAttrList.GetNext(pos);
  403. if ( !s.IsEmpty())
  404. {
  405. pPropertyBox->AddString( s );
  406. }
  407. }
  408. }
  409. if (bOpt)
  410. {
  411. // Add Optional Properties
  412. //
  413. pos = m_sOptionalAttrList.GetHeadPosition();
  414. while( pos != NULL )
  415. {
  416. CString s = m_sOptionalAttrList.GetNext(pos);
  417. if ( !s.IsEmpty())
  418. {
  419. pPropertyBox->AddString( s );
  420. }
  421. }
  422. }
  423. }
  424. ///////////////////////////////////////////////////////////////////////////////////////////////////
  425. CADSIEditPropertyPageHolder::CADSIEditPropertyPageHolder(CADSIEditContainerNode* pContainerNode,
  426. CTreeNode* pThisNode, CComponentDataObject* pComponentData,
  427. LPCWSTR lpszClass, LPCWSTR lpszServer, LPCWSTR lpszPath)
  428. : CPropertyPageHolderBase(pContainerNode, pThisNode, pComponentData)
  429. {
  430. ASSERT(pComponentData != NULL);
  431. ASSERT(pContainerNode != NULL);
  432. m_pContainer = pContainerNode;
  433. ASSERT(pContainerNode == GetContainerNode());
  434. ASSERT(pThisNode != NULL);
  435. m_pAclEditorPage = NULL;
  436. m_bAutoDeletePages = FALSE; // we have the page as embedded member
  437. m_sPath = lpszPath;
  438. m_pADs = NULL;
  439. //
  440. // This gets the CConnectionData from the ConnectionNode by finding a valid treenode and using its
  441. // CADsObject to get the ConnectionNode and then the CConnectionData
  442. //
  443. CADSIEditContainerNode* pNode = GetContainerNode();
  444. CADSIEditConnectionNode* pConnectNode = pNode->GetADsObject()->GetConnectionNode();
  445. CConnectionData* pConnectData = pConnectNode->GetConnectionData();
  446. CCredentialObject* pCredObject = pConnectData->GetCredentialObject();
  447. HRESULT hr, hCredResult;
  448. hr = OpenObjectWithCredentials(
  449. pConnectData,
  450. pConnectData->GetCredentialObject()->UseCredentials(),
  451. (LPWSTR)(LPCWSTR)m_sPath,
  452. IID_IADs,
  453. (LPVOID*) &m_pADs,
  454. NULL,
  455. hCredResult
  456. );
  457. if (SUCCEEDED(hr))
  458. {
  459. //
  460. // Create the advanced attribute editor
  461. //
  462. hr = ::CoCreateInstance(CLSID_DsAttributeEditor, NULL, CLSCTX_INPROC_SERVER,
  463. IID_IDsAttributeEditor, (void**)&m_spIDsAttributeEditor);
  464. if (SUCCEEDED(hr))
  465. {
  466. CString szLDAP;
  467. pConnectData->GetLDAP(szLDAP);
  468. CString szServer;
  469. pConnectData->GetDomainServer(szServer);
  470. CString szProviderServer = szLDAP + szServer + _T("/");
  471. DS_ATTREDITOR_BINDINGINFO attrInfo = {0};
  472. attrInfo.dwSize = sizeof(DS_ATTREDITOR_BINDINGINFO);
  473. attrInfo.lpfnBind = BindingCallbackFunction;
  474. attrInfo.lParam = (LPARAM)pCredObject;
  475. attrInfo.lpszProviderServer = const_cast<LPWSTR>((LPCWSTR)szProviderServer);
  476. if (pConnectData->IsRootDSE())
  477. {
  478. attrInfo.dwFlags = DSATTR_EDITOR_ROOTDSE;
  479. }
  480. hr = m_spIDsAttributeEditor->Initialize(m_pADs, &attrInfo, this);
  481. }
  482. if (!pConnectData->IsRootDSE() && !pConnectData->IsGC())
  483. {
  484. CString szUsername;
  485. WCHAR szPassword[MAX_PASSWORD_LENGTH + 1];
  486. pCredObject->GetUsername(szUsername);
  487. pCredObject->GetPassword(szPassword);
  488. if (pCredObject->UseCredentials())
  489. {
  490. m_pAclEditorPage = CAclEditorPage::CreateInstanceEx(m_sPath,
  491. lpszServer,
  492. szUsername,
  493. szPassword,
  494. DSSI_NO_FILTER,
  495. this);
  496. }
  497. else
  498. {
  499. m_pAclEditorPage = CAclEditorPage::CreateInstanceEx(m_sPath,
  500. NULL,
  501. NULL,
  502. NULL,
  503. DSSI_NO_FILTER,
  504. this);
  505. }
  506. }
  507. }
  508. else
  509. {
  510. if (!pConnectData->IsRootDSE() && !pConnectData->IsGC())
  511. {
  512. if (SUCCEEDED(hCredResult))
  513. {
  514. CString szUsername;
  515. WCHAR szPassword[MAX_PASSWORD_LENGTH + 1];
  516. pCredObject->GetUsername(szUsername);
  517. pCredObject->GetPassword(szPassword);
  518. ADSIEditErrorMessage(hr);
  519. // Create the acl editor even if we were not successful binding, because
  520. // the object may be deny read and we would still want the acl editor
  521. if (pCredObject->UseCredentials())
  522. {
  523. m_pAclEditorPage = CAclEditorPage::CreateInstanceEx(m_sPath,
  524. lpszServer,
  525. szUsername,
  526. szPassword,
  527. DSSI_NO_FILTER,
  528. this);
  529. }
  530. else
  531. {
  532. m_pAclEditorPage = CAclEditorPage::CreateInstanceEx(m_sPath,
  533. NULL,
  534. NULL,
  535. NULL,
  536. DSSI_NO_FILTER,
  537. this);
  538. }
  539. return;
  540. }
  541. }
  542. }
  543. }
  544. HRESULT CADSIEditPropertyPageHolder::OnAddPage(int nPage, CPropertyPageBase* pPage)
  545. {
  546. HRESULT hr = S_OK;
  547. if (nPage == 0)
  548. {
  549. //
  550. // Add the advanced editor page
  551. //
  552. HPROPSHEETPAGE hAttrPage = NULL;
  553. if (m_spIDsAttributeEditor != NULL)
  554. {
  555. hr = m_spIDsAttributeEditor->GetPage(&hAttrPage);
  556. if (SUCCEEDED(hr))
  557. {
  558. hr = AddPageToSheetRaw(hAttrPage);
  559. }
  560. }
  561. }
  562. else if ( nPage == -1)
  563. {
  564. if (m_pAclEditorPage != NULL)
  565. {
  566. //
  567. // add the ACL editor page after the last, if present
  568. //
  569. HPROPSHEETPAGE hPage = m_pAclEditorPage->CreatePage();
  570. if (hPage == NULL)
  571. {
  572. return E_FAIL;
  573. }
  574. //
  575. // add the raw HPROPSHEETPAGE to sheet, not in the list
  576. //
  577. hr = AddPageToSheetRaw(hPage);
  578. }
  579. }
  580. return hr;
  581. }
  582. ///////////////////////////////////////////////////////////////////////////////////////////////
  583. ///////////////////////////////////////////////////////////////////////////////////////////////////
  584. CCreateWizPropertyPageHolder::CCreateWizPropertyPageHolder(CADSIEditContainerNode* pContainerNode,
  585. CComponentDataObject* pComponentData, LPCWSTR lpszClass, LPCWSTR lpszServer, CAttrList* pAttrList)
  586. : CPropertyPageHolderBase(pContainerNode, NULL, pComponentData), m_propPage(pAttrList)
  587. {
  588. ASSERT(pComponentData != NULL);
  589. ASSERT(pContainerNode != NULL);
  590. m_pContainer = pContainerNode;
  591. ASSERT(pContainerNode == GetContainerNode());
  592. m_bAutoDeletePages = FALSE; // we have the page as embedded member
  593. m_propPage.SetClass(lpszClass);
  594. m_propPage.SetServer(lpszServer);
  595. m_propPage.SetConnectionData(pContainerNode->GetADsObject()->GetConnectionNode()->GetConnectionData());
  596. AddPageToList((CPropertyPageBase*)&m_propPage);
  597. }