Leaked source code of windows server 2003
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.

5118 lines
136 KiB

  1. #include "pch.h"
  2. #include <SnapBase.h>
  3. #include "resource.h"
  4. #include "query.h"
  5. #include "attrres.h"
  6. #include "editui.h"
  7. #include "common.h"
  8. #include "attrqry.h"
  9. #include "editorui.h"
  10. ////////////////////////////////////////////////////////////////////////////
  11. // this is used to fill in the attributes for RootDSE
  12. //
  13. typedef struct tagRootDSEAttr
  14. {
  15. LPCWSTR lpszAttr;
  16. LPCWSTR lpszSyntax;
  17. BOOL bMulti;
  18. } SYNTAXMAP;
  19. extern SYNTAXMAP g_ldapRootDSESyntax[];
  20. // Helper function to delete a set of ADSVALUEs
  21. void DeleteADsValues(PADSVALUE pADsValue, DWORD valueCount)
  22. {
  23. if (!pADsValue)
  24. {
  25. return;
  26. }
  27. for (DWORD idx = 0; idx < valueCount; ++idx)
  28. {
  29. switch (pADsValue[idx].dwType)
  30. {
  31. case ADSTYPE_DN_STRING:
  32. if (pADsValue[idx].DNString)
  33. {
  34. delete[] pADsValue[idx].DNString;
  35. }
  36. break;
  37. case ADSTYPE_CASE_EXACT_STRING:
  38. if (pADsValue[idx].CaseExactString)
  39. {
  40. delete[] pADsValue[idx].CaseExactString;
  41. }
  42. break;
  43. case ADSTYPE_CASE_IGNORE_STRING:
  44. if (pADsValue[idx].CaseIgnoreString)
  45. {
  46. delete[] pADsValue[idx].CaseIgnoreString;
  47. }
  48. break;
  49. case ADSTYPE_PRINTABLE_STRING:
  50. if (pADsValue[idx].PrintableString)
  51. {
  52. delete[] pADsValue[idx].PrintableString;
  53. }
  54. break;
  55. case ADSTYPE_NUMERIC_STRING:
  56. if (pADsValue[idx].NumericString)
  57. {
  58. delete[] pADsValue[idx].NumericString;
  59. }
  60. break;
  61. case ADSTYPE_OCTET_STRING:
  62. if (pADsValue[idx].OctetString.lpValue)
  63. {
  64. delete[] pADsValue[idx].OctetString.lpValue;
  65. }
  66. break;
  67. case ADSTYPE_DN_WITH_STRING:
  68. if (pADsValue[idx].pDNWithString)
  69. {
  70. if (pADsValue[idx].pDNWithString->pszStringValue)
  71. {
  72. delete[] pADsValue[idx].pDNWithString->pszStringValue;
  73. }
  74. if (pADsValue[idx].pDNWithString->pszDNString)
  75. {
  76. delete[] pADsValue[idx].pDNWithString->pszDNString;
  77. }
  78. delete pADsValue[idx].pDNWithString;
  79. }
  80. break;
  81. case ADSTYPE_BOOLEAN:
  82. case ADSTYPE_INTEGER:
  83. case ADSTYPE_UTC_TIME:
  84. case ADSTYPE_LARGE_INTEGER:
  85. case ADSTYPE_CASEIGNORE_LIST:
  86. case ADSTYPE_OCTET_LIST:
  87. case ADSTYPE_PATH:
  88. case ADSTYPE_POSTALADDRESS:
  89. case ADSTYPE_TIMESTAMP:
  90. case ADSTYPE_BACKLINK:
  91. case ADSTYPE_TYPEDNAME:
  92. case ADSTYPE_HOLD:
  93. case ADSTYPE_NETADDRESS:
  94. case ADSTYPE_REPLICAPOINTER:
  95. case ADSTYPE_FAXNUMBER:
  96. case ADSTYPE_EMAIL:
  97. case ADSTYPE_DN_WITH_BINARY:
  98. default:
  99. // Do nothing, we didn't allocate any memory for these other types
  100. break;
  101. }
  102. }
  103. if (valueCount < 2)
  104. {
  105. delete pADsValue;
  106. }
  107. else
  108. {
  109. delete[] pADsValue;
  110. }
  111. }
  112. ///////////////////////////////////////////////////////////////////////////////////////
  113. // CValueEditDialog
  114. BEGIN_MESSAGE_MAP(CValueEditDialog, CDialog)
  115. END_MESSAGE_MAP()
  116. HRESULT CValueEditDialog::Initialize(LPDS_ATTRIBUTE_EDITORINFO pAttributeEditorInfo)
  117. {
  118. HRESULT hr = S_OK;
  119. m_pOldADsValue = pAttributeEditorInfo->pADsValue;
  120. m_dwOldNumValues = pAttributeEditorInfo->dwNumValues;
  121. m_szClass = pAttributeEditorInfo->lpszClass;
  122. m_szAttribute = pAttributeEditorInfo->lpszAttribute;
  123. m_bMultivalued = pAttributeEditorInfo->bMultivalued;
  124. m_bReadOnly = pAttributeEditorInfo->bReadOnly;
  125. m_pfnBindingFunction = pAttributeEditorInfo->lpfnBind;
  126. m_lParam = pAttributeEditorInfo->lParam;
  127. return hr;
  128. }
  129. HRESULT CValueEditDialog::GetNewValue(PADSVALUE* ppADsValue, DWORD* pdwNumValues)
  130. {
  131. HRESULT hr = S_OK;
  132. if (ppADsValue == NULL ||
  133. pdwNumValues == NULL)
  134. {
  135. return E_OUTOFMEMORY;
  136. }
  137. *ppADsValue = NULL;
  138. *pdwNumValues = 0;
  139. return hr;
  140. }
  141. ///////////////////////////////////////////////////////////////////////////////////////
  142. // CSingleStringEditor
  143. CValueEditDialog* CreateSingleStringEditor(PCWSTR pszClass,
  144. PCWSTR pszAttribute,
  145. ADSTYPE adsType,
  146. BOOL bMultivalued)
  147. {
  148. return new CSingleStringEditor;
  149. }
  150. BEGIN_MESSAGE_MAP(CSingleStringEditor, CValueEditDialog)
  151. ON_BN_CLICKED(IDC_CLEAR_BUTTON, OnClear)
  152. END_MESSAGE_MAP()
  153. BOOL CSingleStringEditor::OnInitDialog()
  154. {
  155. //
  156. // Initialize the static control with the attribute name
  157. //
  158. SetDlgItemText(IDC_ATTRIBUTE_STATIC, m_szAttribute);
  159. //
  160. // Initialize the edit box with the value
  161. //
  162. if (m_szOldValue.IsEmpty())
  163. {
  164. CString szNotSet;
  165. VERIFY(szNotSet.LoadString(IDS_NOTSET));
  166. SetDlgItemText(IDC_VALUE_EDIT, szNotSet);
  167. }
  168. else
  169. {
  170. SetDlgItemText(IDC_VALUE_EDIT, m_szOldValue);
  171. }
  172. //
  173. // Select the text in the edit box
  174. //
  175. SendDlgItemMessage(IDC_VALUE_EDIT, EM_SETSEL, 0, -1);
  176. if (m_bReadOnly)
  177. {
  178. SendDlgItemMessage(IDC_VALUE_EDIT, EM_SETREADONLY, TRUE, 0);
  179. }
  180. return CDialog::OnInitDialog();
  181. }
  182. void CSingleStringEditor::OnOK()
  183. {
  184. GetDlgItemText(IDC_VALUE_EDIT, m_szNewValue);
  185. CDialog::OnOK();
  186. }
  187. HRESULT CSingleStringEditor::Initialize(LPDS_ATTRIBUTE_EDITORINFO pAttributeEditorInfo)
  188. {
  189. HRESULT hr = S_OK;
  190. if (SUCCEEDED(CValueEditDialog::Initialize(pAttributeEditorInfo)))
  191. {
  192. if (pAttributeEditorInfo->dwNumValues > 0 &&
  193. pAttributeEditorInfo->pADsValue != NULL)
  194. {
  195. switch (pAttributeEditorInfo->pADsValue->dwType)
  196. {
  197. case ADSTYPE_CASE_IGNORE_STRING:
  198. m_szOldValue = pAttributeEditorInfo->pADsValue->CaseIgnoreString;
  199. break;
  200. case ADSTYPE_CASE_EXACT_STRING:
  201. m_szOldValue = pAttributeEditorInfo->pADsValue->CaseExactString;
  202. break;
  203. case ADSTYPE_PRINTABLE_STRING:
  204. m_szOldValue = pAttributeEditorInfo->pADsValue->PrintableString;
  205. break;
  206. case ADSTYPE_DN_STRING:
  207. m_szOldValue = pAttributeEditorInfo->pADsValue->DNString;
  208. break;
  209. default:
  210. ASSERT(FALSE);
  211. break;
  212. }
  213. }
  214. }
  215. return hr;
  216. }
  217. void CSingleStringEditor::OnClear()
  218. {
  219. //
  220. // Change the text in the edit box to "<not set>"
  221. //
  222. CString szNotSet;
  223. VERIFY(szNotSet.LoadString(IDS_NOTSET));
  224. SetDlgItemText(IDC_VALUE_EDIT, szNotSet);
  225. //
  226. // Change the focus to the edit box
  227. //
  228. GetDlgItem(IDC_VALUE_EDIT)->SetFocus();
  229. //
  230. // Select the text in the edit box
  231. //
  232. SendDlgItemMessage(IDC_VALUE_EDIT, EM_SETSEL, 0, -1);
  233. }
  234. HRESULT CSingleStringEditor::GetNewValue(PADSVALUE* ppADsValue, DWORD* pdwNumValues)
  235. {
  236. HRESULT hr = S_OK;
  237. if (ppADsValue == NULL ||
  238. pdwNumValues == NULL)
  239. {
  240. return E_OUTOFMEMORY;
  241. }
  242. CString szNotSet;
  243. VERIFY(szNotSet.LoadString(IDS_NOTSET));
  244. if (m_szNewValue == szNotSet)
  245. {
  246. *ppADsValue = NULL;
  247. *pdwNumValues = 0;
  248. }
  249. else
  250. {
  251. *ppADsValue = new ADSVALUE;
  252. if (*ppADsValue != NULL)
  253. {
  254. *pdwNumValues = 1;
  255. (*ppADsValue)->dwType = m_pOldADsValue->dwType;
  256. switch (m_pOldADsValue->dwType)
  257. {
  258. case ADSTYPE_CASE_IGNORE_STRING:
  259. (*ppADsValue)->CaseIgnoreString = new WCHAR[wcslen(m_szNewValue) + 1];
  260. if ((*ppADsValue)->CaseIgnoreString != NULL)
  261. {
  262. // NOTICE-2002/03/05-artm wcscpy() OK.
  263. // Both args are allocated the same amount of memory.
  264. wcscpy((*ppADsValue)->CaseIgnoreString, m_szNewValue);
  265. }
  266. else
  267. {
  268. DeleteADsValues(*ppADsValue, *pdwNumValues);
  269. *ppADsValue = NULL;
  270. *pdwNumValues = 0;
  271. hr = E_OUTOFMEMORY;
  272. }
  273. break;
  274. case ADSTYPE_CASE_EXACT_STRING:
  275. (*ppADsValue)->CaseExactString = new WCHAR[wcslen(m_szNewValue) + 1];
  276. if ((*ppADsValue)->CaseExactString != NULL)
  277. {
  278. // NOTICE-2002/03/05-artm wcscpy() OK.
  279. // Both args are allocated the same amount of memory.
  280. wcscpy((*ppADsValue)->CaseExactString, m_szNewValue);
  281. }
  282. else
  283. {
  284. DeleteADsValues(*ppADsValue, *pdwNumValues);
  285. *ppADsValue = NULL;
  286. *pdwNumValues = 0;
  287. hr = E_OUTOFMEMORY;
  288. }
  289. break;
  290. case ADSTYPE_PRINTABLE_STRING:
  291. (*ppADsValue)->PrintableString = new WCHAR[wcslen(m_szNewValue) + 1];
  292. if ((*ppADsValue)->PrintableString != NULL)
  293. {
  294. // NOTICE-2002/03/05-artm wcscpy() OK.
  295. // Both args are allocated the same amount of memory.
  296. wcscpy((*ppADsValue)->PrintableString, m_szNewValue);
  297. }
  298. else
  299. {
  300. DeleteADsValues(*ppADsValue, *pdwNumValues);
  301. *ppADsValue = NULL;
  302. *pdwNumValues = 0;
  303. hr = E_OUTOFMEMORY;
  304. }
  305. break;
  306. case ADSTYPE_DN_STRING:
  307. (*ppADsValue)->DNString = new WCHAR[wcslen(m_szNewValue) + 1];
  308. if ((*ppADsValue)->DNString != NULL)
  309. {
  310. // NOTICE-2002/03/05-artm wcscpy() OK.
  311. // Both args are allocated the same amount of memory.
  312. wcscpy((*ppADsValue)->DNString, m_szNewValue);
  313. }
  314. else
  315. {
  316. DeleteADsValues(*ppADsValue, *pdwNumValues);
  317. *ppADsValue = NULL;
  318. *pdwNumValues = 0;
  319. hr = E_OUTOFMEMORY;
  320. }
  321. break;
  322. default:
  323. ASSERT(FALSE);
  324. DeleteADsValues(*ppADsValue, *pdwNumValues);
  325. *ppADsValue = NULL;
  326. *pdwNumValues = 0;
  327. hr = E_FAIL;
  328. break;
  329. }
  330. }
  331. else
  332. {
  333. *pdwNumValues = 0;
  334. hr = E_OUTOFMEMORY;
  335. }
  336. }
  337. return hr;
  338. }
  339. ///////////////////////////////////////////////////////////////////////////////////////
  340. // CMultiStringEditor
  341. CValueEditDialog* CreateMultiStringEditor(PCWSTR pszClass,
  342. PCWSTR pszAttribute,
  343. ADSTYPE adsType,
  344. BOOL bMultivalued)
  345. {
  346. return new CMultiStringEditor;
  347. }
  348. BEGIN_MESSAGE_MAP(CMultiStringEditor, CValueEditDialog)
  349. ON_BN_CLICKED(IDC_ATTR_ADD_BUTTON, OnAddButton)
  350. ON_BN_CLICKED(IDC_ATTR_REMOVE_BUTTON, OnRemoveButton)
  351. ON_LBN_SELCHANGE(IDC_VALUE_LIST, OnListSelChange)
  352. ON_EN_CHANGE(IDC_VALUE_EDIT, OnEditChange)
  353. END_MESSAGE_MAP()
  354. BOOL CMultiStringEditor::OnInitDialog()
  355. {
  356. CDialog::OnInitDialog();
  357. //
  358. // Set the attribute name static
  359. //
  360. SetDlgItemText(IDC_ATTRIBUTE_STATIC, m_szAttribute);
  361. //
  362. // Fill the list box with the current values
  363. //
  364. POSITION pos = m_szOldValueList.GetHeadPosition();
  365. while (pos != NULL)
  366. {
  367. CString szValue = m_szOldValueList.GetNext(pos);
  368. if (!szValue.IsEmpty())
  369. {
  370. SendDlgItemMessage(IDC_VALUE_LIST, LB_ADDSTRING, 0, (LPARAM)(LPCWSTR)szValue);
  371. }
  372. }
  373. //
  374. // The remove button should be disabled until something is selected in the listbox
  375. //
  376. GetDlgItem(IDC_ATTR_REMOVE_BUTTON)->EnableWindow(FALSE);
  377. GetDlgItem(IDC_VALUE_EDIT)->SetFocus();
  378. ManageButtonStates();
  379. //
  380. // Update the width of the list box
  381. //
  382. UpdateListboxHorizontalExtent();
  383. if (m_bReadOnly)
  384. {
  385. GetDlgItem(IDC_ATTR_REMOVE_BUTTON)->EnableWindow(FALSE);
  386. GetDlgItem(IDC_ATTR_ADD_BUTTON)->EnableWindow(FALSE);
  387. SendDlgItemMessage(IDC_VALUE_EDIT, EM_SETREADONLY, TRUE, 0);
  388. }
  389. //
  390. // NOTE: I have explicitly set the focus so return 0
  391. //
  392. return FALSE;
  393. }
  394. void CMultiStringEditor::OnOK()
  395. {
  396. if (!m_bReadOnly)
  397. {
  398. //
  399. // Get the values out of the list box
  400. //
  401. m_szNewValueList.RemoveAll();
  402. CListBox* pListBox = reinterpret_cast<CListBox*>(GetDlgItem(IDC_VALUE_LIST));
  403. if (pListBox != NULL)
  404. {
  405. int iCount = pListBox->GetCount();
  406. for (int idx = 0; idx < iCount; idx++)
  407. {
  408. CString szNewValue;
  409. pListBox->GetText(idx, szNewValue);
  410. m_szNewValueList.AddTail(szNewValue);
  411. }
  412. }
  413. }
  414. CDialog::OnOK();
  415. }
  416. void CMultiStringEditor::OnAddButton()
  417. {
  418. if (!m_bReadOnly)
  419. {
  420. //
  421. // Add the value to the list box and clear the edit field
  422. //
  423. CString szNewValue;
  424. GetDlgItemText(IDC_VALUE_EDIT, szNewValue);
  425. if (!szNewValue.IsEmpty())
  426. {
  427. LRESULT lFind = SendDlgItemMessage(IDC_VALUE_LIST,
  428. LB_FINDSTRING,
  429. (WPARAM)-1,
  430. (LPARAM)(PCWSTR)szNewValue);
  431. if (lFind != LB_ERR)
  432. {
  433. //
  434. // Ask them if they really want to add the duplicate value
  435. //
  436. UINT nResult = ADSIEditMessageBox(IDS_ATTREDIT_DUPLICATE_VALUE, MB_YESNO);
  437. lFind = (nResult == IDYES) ? LB_ERR : 1;
  438. }
  439. if (lFind == LB_ERR)
  440. {
  441. SendDlgItemMessage(IDC_VALUE_LIST, LB_ADDSTRING, 0, (LPARAM)(LPCWSTR)szNewValue);
  442. }
  443. }
  444. SetDlgItemText(IDC_VALUE_EDIT, L"");
  445. ManageButtonStates();
  446. //
  447. // Update the width of the list box
  448. //
  449. UpdateListboxHorizontalExtent();
  450. }
  451. }
  452. void CMultiStringEditor::OnRemoveButton()
  453. {
  454. if (!m_bReadOnly)
  455. {
  456. CListBox* pListBox = reinterpret_cast<CListBox*>(GetDlgItem(IDC_VALUE_LIST));
  457. if (pListBox != NULL)
  458. {
  459. int iCurSel = pListBox->GetCurSel();
  460. if (iCurSel != LB_ERR)
  461. {
  462. //
  463. // Put the old value into the edit box
  464. //
  465. CString szOldValue;
  466. pListBox->GetText(iCurSel, szOldValue);
  467. SetDlgItemText(IDC_VALUE_EDIT, szOldValue);
  468. //
  469. // Delete the item from the list box
  470. //
  471. pListBox->DeleteString(iCurSel);
  472. }
  473. }
  474. //
  475. // Manage Button States
  476. //
  477. ManageButtonStates();
  478. //
  479. // Update the width of the list box
  480. //
  481. UpdateListboxHorizontalExtent();
  482. }
  483. }
  484. void CMultiStringEditor::ManageButtonStates()
  485. {
  486. if (m_bReadOnly)
  487. {
  488. GetDlgItem(IDC_ATTR_REMOVE_BUTTON)->EnableWindow(FALSE);
  489. GetDlgItem(IDC_ATTR_ADD_BUTTON)->EnableWindow(FALSE);
  490. }
  491. else
  492. {
  493. //
  494. // Change the default button to the Add button
  495. //
  496. CString szValue;
  497. GetDlgItemText(IDC_VALUE_EDIT, szValue);
  498. if (szValue.IsEmpty())
  499. {
  500. //
  501. // Set the default button to OK
  502. //
  503. SendMessage(DM_SETDEFID, (WPARAM)IDOK, 0);
  504. SendDlgItemMessage(IDC_ATTR_ADD_BUTTON,
  505. BM_SETSTYLE,
  506. BS_PUSHBUTTON,
  507. MAKELPARAM(TRUE, 0));
  508. SendDlgItemMessage(IDOK,
  509. BM_SETSTYLE,
  510. BS_DEFPUSHBUTTON,
  511. MAKELPARAM(TRUE, 0));
  512. }
  513. else
  514. {
  515. //
  516. // Set the default button to the Add button
  517. //
  518. SendMessage(DM_SETDEFID, (WPARAM)IDC_ATTR_ADD_BUTTON, 0);
  519. SendDlgItemMessage(IDOK,
  520. BM_SETSTYLE,
  521. BS_PUSHBUTTON,
  522. MAKELPARAM(TRUE, 0));
  523. SendDlgItemMessage(IDC_ATTR_ADD_BUTTON,
  524. BM_SETSTYLE,
  525. BS_DEFPUSHBUTTON,
  526. MAKELPARAM(TRUE, 0));
  527. }
  528. LRESULT lSelection = SendDlgItemMessage(IDC_VALUE_LIST, LB_GETCURSEL, 0, 0);
  529. if (lSelection != LB_ERR)
  530. {
  531. GetDlgItem(IDC_ATTR_REMOVE_BUTTON)->EnableWindow(TRUE);
  532. }
  533. else
  534. {
  535. GetDlgItem(IDC_ATTR_REMOVE_BUTTON)->EnableWindow(FALSE);
  536. }
  537. }
  538. }
  539. void CMultiStringEditor::OnListSelChange()
  540. {
  541. ManageButtonStates();
  542. }
  543. void CMultiStringEditor::OnEditChange()
  544. {
  545. ManageButtonStates();
  546. }
  547. void CMultiStringEditor::UpdateListboxHorizontalExtent()
  548. {
  549. int nHorzExtent = 0;
  550. CListBox* pListBox = reinterpret_cast<CListBox*>(GetDlgItem(IDC_VALUE_LIST));
  551. if (pListBox != NULL)
  552. {
  553. CClientDC dc(pListBox);
  554. int nItems = pListBox->GetCount();
  555. for (int i=0; i < nItems; i++)
  556. {
  557. TEXTMETRIC tm;
  558. VERIFY(dc.GetTextMetrics(&tm));
  559. CString szBuffer;
  560. pListBox->GetText(i, szBuffer);
  561. CSize ext = dc.GetTextExtent(szBuffer,szBuffer.GetLength());
  562. nHorzExtent = max(ext.cx ,nHorzExtent);
  563. }
  564. pListBox->SetHorizontalExtent(nHorzExtent);
  565. }
  566. }
  567. HRESULT CMultiStringEditor::Initialize(LPDS_ATTRIBUTE_EDITORINFO pAttributeEditorInfo)
  568. {
  569. HRESULT hr = S_OK;
  570. if (SUCCEEDED(CValueEditDialog::Initialize(pAttributeEditorInfo)))
  571. {
  572. if (pAttributeEditorInfo->dwNumValues > 0 &&
  573. pAttributeEditorInfo->pADsValue != NULL)
  574. {
  575. for (int idx = 0; idx < pAttributeEditorInfo->dwNumValues; idx++)
  576. {
  577. switch (pAttributeEditorInfo->pADsValue[idx].dwType)
  578. {
  579. case ADSTYPE_CASE_IGNORE_STRING:
  580. m_szOldValueList.AddTail(pAttributeEditorInfo->pADsValue[idx].CaseIgnoreString);
  581. break;
  582. case ADSTYPE_CASE_EXACT_STRING:
  583. m_szOldValueList.AddTail(pAttributeEditorInfo->pADsValue[idx].CaseExactString);
  584. break;
  585. case ADSTYPE_PRINTABLE_STRING:
  586. m_szOldValueList.AddTail(pAttributeEditorInfo->pADsValue[idx].PrintableString);
  587. break;
  588. case ADSTYPE_DN_STRING:
  589. m_szOldValueList.AddTail(pAttributeEditorInfo->pADsValue[idx].DNString);
  590. break;
  591. default:
  592. ASSERT(FALSE);
  593. break;
  594. }
  595. }
  596. }
  597. }
  598. return hr;
  599. }
  600. // FUTURE-2002/03/05-artm Very similar functionality in CSingleStringEditor
  601. // and CMultiStringEditor classes. Perhaps there is a way to combine the
  602. // classes into a single class....or have one class inherit from the other.
  603. HRESULT CMultiStringEditor::GetNewValue(PADSVALUE* ppADsValue, DWORD* pdwNumValues)
  604. {
  605. HRESULT hr = S_OK;
  606. if (ppADsValue == NULL ||
  607. pdwNumValues == NULL)
  608. {
  609. return E_OUTOFMEMORY;
  610. }
  611. int iCount = m_szNewValueList.GetCount();
  612. if (iCount == 0)
  613. {
  614. *ppADsValue = NULL;
  615. *pdwNumValues = 0;
  616. }
  617. else
  618. {
  619. *ppADsValue = new ADSVALUE[iCount];
  620. if (*ppADsValue != NULL)
  621. {
  622. *pdwNumValues = iCount;
  623. int idx = 0;
  624. POSITION pos = m_szNewValueList.GetHeadPosition();
  625. while (pos != NULL)
  626. {
  627. CString szNewValue = m_szNewValueList.GetNext(pos);
  628. (*ppADsValue)[idx].dwType = m_pOldADsValue->dwType;
  629. switch (m_pOldADsValue->dwType)
  630. {
  631. case ADSTYPE_CASE_IGNORE_STRING:
  632. (*ppADsValue)[idx].CaseIgnoreString = new WCHAR[wcslen(szNewValue) + 1];
  633. if ((*ppADsValue)[idx].CaseIgnoreString != NULL)
  634. {
  635. // NOTICE-2002/03/05-artm wcscpy() OK.
  636. // Both args are allocated the same amount of memory.
  637. wcscpy((*ppADsValue)[idx].CaseIgnoreString, szNewValue);
  638. }
  639. else
  640. {
  641. DeleteADsValues(*ppADsValue, *pdwNumValues);
  642. *ppADsValue = NULL;
  643. *pdwNumValues = 0;
  644. hr = E_OUTOFMEMORY;
  645. }
  646. break;
  647. case ADSTYPE_CASE_EXACT_STRING:
  648. (*ppADsValue)[idx].CaseExactString = new WCHAR[wcslen(szNewValue) + 1];
  649. if ((*ppADsValue)[idx].CaseExactString != NULL)
  650. {
  651. // NOTICE-2002/03/05-artm wcscpy() OK.
  652. // Both args are allocated the same amount of memory.
  653. wcscpy((*ppADsValue)[idx].CaseExactString, szNewValue);
  654. }
  655. else
  656. {
  657. DeleteADsValues(*ppADsValue, *pdwNumValues);
  658. *ppADsValue = NULL;
  659. *pdwNumValues = 0;
  660. hr = E_OUTOFMEMORY;
  661. }
  662. break;
  663. case ADSTYPE_PRINTABLE_STRING:
  664. (*ppADsValue)[idx].PrintableString = new WCHAR[wcslen(szNewValue) + 1];
  665. if ((*ppADsValue)[idx].PrintableString != NULL)
  666. {
  667. // NOTICE-2002/03/05-artm wcscpy() OK.
  668. // Both args are allocated the same amount of memory.
  669. wcscpy((*ppADsValue)[idx].PrintableString, szNewValue);
  670. }
  671. else
  672. {
  673. DeleteADsValues(*ppADsValue, *pdwNumValues);
  674. *ppADsValue = NULL;
  675. *pdwNumValues = 0;
  676. hr = E_OUTOFMEMORY;
  677. }
  678. break;
  679. case ADSTYPE_DN_STRING:
  680. (*ppADsValue)[idx].DNString = new WCHAR[wcslen(szNewValue) + 1];
  681. if ((*ppADsValue)[idx].DNString != NULL)
  682. {
  683. // NOTICE-2002/03/05-artm wcscpy() OK.
  684. // Both args are allocated the same amount of memory.
  685. wcscpy((*ppADsValue)[idx].DNString, szNewValue);
  686. }
  687. else
  688. {
  689. DeleteADsValues(*ppADsValue, *pdwNumValues);
  690. *ppADsValue = NULL;
  691. *pdwNumValues = 0;
  692. hr = E_OUTOFMEMORY;
  693. }
  694. break;
  695. case ADSTYPE_NUMERIC_STRING:
  696. (*ppADsValue)[idx].NumericString = new WCHAR[wcslen(szNewValue) + 1];
  697. if ((*ppADsValue)[idx].NumericString != NULL)
  698. {
  699. // NOTICE-2002/03/05-artm wcscpy() OK.
  700. // Both args are allocated the same amount of memory.
  701. wcscpy((*ppADsValue)[idx].NumericString, szNewValue);
  702. }
  703. else
  704. {
  705. DeleteADsValues(*ppADsValue, *pdwNumValues);
  706. *ppADsValue = NULL;
  707. *pdwNumValues = 0;
  708. hr = E_OUTOFMEMORY;
  709. }
  710. break;
  711. default:
  712. ASSERT(FALSE);
  713. DeleteADsValues(*ppADsValue, *pdwNumValues);
  714. *ppADsValue = NULL;
  715. *pdwNumValues = 0;
  716. hr = E_FAIL;
  717. break;
  718. }
  719. idx++;
  720. }
  721. }
  722. else
  723. {
  724. *ppADsValue = NULL;
  725. *pdwNumValues = 0;
  726. hr = E_OUTOFMEMORY;
  727. }
  728. }
  729. return hr;
  730. }
  731. ///////////////////////////////////////////////////////////////////////////////////////
  732. // CSingleIntEditor
  733. CValueEditDialog* CreateSingleIntEditor(PCWSTR pszClass,
  734. PCWSTR pszAttribute,
  735. ADSTYPE adsType,
  736. BOOL bMultivalued)
  737. {
  738. return new CSingleIntEditor;
  739. }
  740. BEGIN_MESSAGE_MAP(CSingleIntEditor, CValueEditDialog)
  741. ON_BN_CLICKED(IDC_CLEAR_BUTTON, OnClear)
  742. END_MESSAGE_MAP()
  743. BOOL CSingleIntEditor::OnInitDialog()
  744. {
  745. //
  746. // Initialize the static control with the attribute name
  747. //
  748. SetDlgItemText(IDC_ATTRIBUTE_STATIC, m_szAttribute);
  749. //
  750. // Initialize the edit box with the value
  751. //
  752. if (!m_bValueSet)
  753. {
  754. CString szNotSet;
  755. VERIFY(szNotSet.LoadString(IDS_NOTSET));
  756. SetDlgItemText(IDC_VALUE_EDIT, szNotSet);
  757. }
  758. else
  759. {
  760. SetDlgItemInt(IDC_VALUE_EDIT, m_dwOldValue, TRUE);
  761. }
  762. //
  763. // Select the text in the edit box
  764. //
  765. SendDlgItemMessage(IDC_VALUE_EDIT, EM_SETSEL, 0, -1);
  766. //
  767. // Disable IME support on the edit box
  768. //
  769. ImmAssociateContext(::GetDlgItem(GetSafeHwnd(), IDC_VALUE_EDIT), NULL);
  770. if (m_bReadOnly)
  771. {
  772. SendDlgItemMessage(IDC_VALUE_EDIT, EM_SETREADONLY, TRUE, 0);
  773. GetDlgItem(IDC_CLEAR_BUTTON)->EnableWindow(FALSE);
  774. }
  775. return CDialog::OnInitDialog();
  776. }
  777. void CSingleIntEditor::OnOK()
  778. {
  779. if (!m_bReadOnly)
  780. {
  781. BOOL bTranslated = FALSE;
  782. m_dwNewValue = GetDlgItemInt(IDC_VALUE_EDIT, &bTranslated, TRUE);
  783. if (!bTranslated)
  784. {
  785. // The translation will always fail if we are in the <not set> state
  786. CString szNotSet;
  787. VERIFY(szNotSet.LoadString(IDS_NOTSET));
  788. CString value;
  789. GetDlgItemText(IDC_VALUE_EDIT, value);
  790. if (value.CompareNoCase(szNotSet) != 0)
  791. {
  792. // The user probably entered some non-numeric characters
  793. ADSIEditMessageBox(IDS_ERR_MUST_BE_NUMERIC, MB_OK | MB_ICONEXCLAMATION);
  794. }
  795. else
  796. {
  797. CDialog::OnOK();
  798. }
  799. }
  800. else
  801. {
  802. m_bValueSet = TRUE;
  803. CDialog::OnOK();
  804. }
  805. }
  806. else
  807. {
  808. CDialog::OnOK();
  809. }
  810. }
  811. HRESULT CSingleIntEditor::Initialize(LPDS_ATTRIBUTE_EDITORINFO pAttributeEditorInfo)
  812. {
  813. HRESULT hr = S_OK;
  814. if (SUCCEEDED(CValueEditDialog::Initialize(pAttributeEditorInfo)))
  815. {
  816. if (pAttributeEditorInfo->dwNumValues > 0 &&
  817. pAttributeEditorInfo->pADsValue != NULL)
  818. {
  819. switch (pAttributeEditorInfo->pADsValue->dwType)
  820. {
  821. case ADSTYPE_INTEGER:
  822. m_dwOldValue = pAttributeEditorInfo->pADsValue->Integer;
  823. m_bValueSet = TRUE;
  824. break;
  825. default:
  826. ASSERT(FALSE);
  827. break;
  828. }
  829. }
  830. }
  831. return hr;
  832. }
  833. // FUTURE-2002/03/05-artm Identical OnClear() functions...
  834. // The OnClear() method for all of the classes that extend CValueEditDialog
  835. // is implemented identically (or so it seems on first glance). Perhaps
  836. // the implementation should be placed in the base class to reduce
  837. // code size, complexity, and maintenance.
  838. void CSingleIntEditor::OnClear()
  839. {
  840. if (!m_bReadOnly)
  841. {
  842. //
  843. // Change the text in the edit box to "<not set>"
  844. //
  845. CString szNotSet;
  846. VERIFY(szNotSet.LoadString(IDS_NOTSET));
  847. SetDlgItemText(IDC_VALUE_EDIT, szNotSet);
  848. //
  849. // Change the focus to the edit box
  850. //
  851. GetDlgItem(IDC_VALUE_EDIT)->SetFocus();
  852. //
  853. // Select the text in the edit box
  854. //
  855. SendDlgItemMessage(IDC_VALUE_EDIT, EM_SETSEL, 0, -1);
  856. m_bValueSet = FALSE;
  857. }
  858. }
  859. HRESULT CSingleIntEditor::GetNewValue(PADSVALUE* ppADsValue, DWORD* pdwNumValues)
  860. {
  861. HRESULT hr = S_OK;
  862. if (ppADsValue == NULL ||
  863. pdwNumValues == NULL)
  864. {
  865. return E_OUTOFMEMORY;
  866. }
  867. CString szNotSet;
  868. VERIFY(szNotSet.LoadString(IDS_NOTSET));
  869. if (!m_bValueSet)
  870. {
  871. *ppADsValue = NULL;
  872. *pdwNumValues = 0;
  873. }
  874. else
  875. {
  876. *ppADsValue = new ADSVALUE;
  877. if (*ppADsValue != NULL)
  878. {
  879. *pdwNumValues = 1;
  880. (*ppADsValue)->dwType = m_pOldADsValue->dwType;
  881. switch (m_pOldADsValue->dwType)
  882. {
  883. case ADSTYPE_INTEGER:
  884. (*ppADsValue)->Integer = m_dwNewValue;
  885. break;
  886. default:
  887. ASSERT(FALSE);
  888. DeleteADsValues(*ppADsValue, *pdwNumValues);
  889. *ppADsValue = NULL;
  890. *pdwNumValues = 0;
  891. hr = E_FAIL;
  892. break;
  893. }
  894. }
  895. else
  896. {
  897. *pdwNumValues = 0;
  898. hr = E_OUTOFMEMORY;
  899. }
  900. }
  901. return hr;
  902. }
  903. ///////////////////////////////////////////////////////////////////////////////////////
  904. // CMultiIntEditor
  905. CValueEditDialog* CreateMultiIntEditor(PCWSTR pszClass,
  906. PCWSTR pszAttribute,
  907. ADSTYPE adsType,
  908. BOOL bMultivalued)
  909. {
  910. return new CMultiIntEditor;
  911. }
  912. BEGIN_MESSAGE_MAP(CMultiIntEditor, CValueEditDialog)
  913. ON_BN_CLICKED(IDC_ATTR_ADD_BUTTON, OnAddButton)
  914. ON_BN_CLICKED(IDC_ATTR_REMOVE_BUTTON, OnRemoveButton)
  915. ON_LBN_SELCHANGE(IDC_VALUE_LIST, OnListSelChange)
  916. ON_EN_CHANGE(IDC_VALUE_EDIT, OnEditChange)
  917. END_MESSAGE_MAP()
  918. BOOL CMultiIntEditor::OnInitDialog()
  919. {
  920. CDialog::OnInitDialog();
  921. //
  922. // Set the attribute name static
  923. //
  924. SetDlgItemText(IDC_ATTRIBUTE_STATIC, m_szAttribute);
  925. //
  926. // Disable IME support on the edit box
  927. //
  928. ImmAssociateContext(::GetDlgItem(GetSafeHwnd(), IDC_VALUE_EDIT), NULL);
  929. //
  930. // Fill the list box with the current values
  931. //
  932. POSITION pos = m_oldValueList.GetHeadPosition();
  933. while (pos != NULL)
  934. {
  935. int value = m_oldValueList.GetNext(pos);
  936. // Convert value to string
  937. CString stringValue;
  938. stringValue.Format(L"%d", value);
  939. // Add string to list box
  940. LRESULT index =
  941. SendDlgItemMessage(
  942. IDC_VALUE_LIST,
  943. LB_ADDSTRING,
  944. 0,
  945. (LPARAM)(LPCWSTR)stringValue);
  946. // Attach the int value to the list box item
  947. if (index != LB_ERR)
  948. {
  949. SendDlgItemMessage(
  950. IDC_VALUE_LIST,
  951. LB_SETITEMDATA,
  952. (WPARAM)index,
  953. (LPARAM)value);
  954. }
  955. }
  956. //
  957. // The remove button should be disabled until something is selected in the listbox
  958. //
  959. GetDlgItem(IDC_ATTR_REMOVE_BUTTON)->EnableWindow(FALSE);
  960. GetDlgItem(IDC_VALUE_EDIT)->SetFocus();
  961. ManageButtonStates();
  962. //
  963. // Update the width of the list box
  964. //
  965. UpdateListboxHorizontalExtent();
  966. if (m_bReadOnly)
  967. {
  968. GetDlgItem(IDC_ATTR_REMOVE_BUTTON)->EnableWindow(FALSE);
  969. GetDlgItem(IDC_ATTR_ADD_BUTTON)->EnableWindow(FALSE);
  970. SendDlgItemMessage(IDC_VALUE_EDIT, EM_SETREADONLY, TRUE, 0);
  971. }
  972. //
  973. // NOTE: I have explicitly set the focus so return 0
  974. //
  975. return FALSE;
  976. }
  977. void CMultiIntEditor::OnOK()
  978. {
  979. if (!m_bReadOnly)
  980. {
  981. //
  982. // Get the values out of the list box
  983. //
  984. m_newValueList.RemoveAll();
  985. CListBox* pListBox = reinterpret_cast<CListBox*>(GetDlgItem(IDC_VALUE_LIST));
  986. if (pListBox != NULL)
  987. {
  988. int iCount = pListBox->GetCount();
  989. for (int idx = 0; idx < iCount; idx++)
  990. {
  991. int newValue;
  992. newValue = static_cast<int>(pListBox->GetItemData(idx));
  993. m_newValueList.AddTail(newValue);
  994. }
  995. }
  996. }
  997. CDialog::OnOK();
  998. }
  999. void CMultiIntEditor::OnAddButton()
  1000. {
  1001. if (!m_bReadOnly)
  1002. {
  1003. //
  1004. // Add the value to the list box and clear the edit field
  1005. //
  1006. int newValue = 0;
  1007. BOOL trans = FALSE;
  1008. newValue = GetDlgItemInt(IDC_VALUE_EDIT, &trans, TRUE);
  1009. CString szNewValue;
  1010. GetDlgItemText(IDC_VALUE_EDIT, szNewValue);
  1011. if (trans && !szNewValue.IsEmpty())
  1012. {
  1013. LRESULT lFind = SendDlgItemMessage(IDC_VALUE_LIST,
  1014. LB_FINDSTRING,
  1015. (WPARAM)-1,
  1016. (LPARAM)(PCWSTR)szNewValue);
  1017. if (lFind != LB_ERR)
  1018. {
  1019. //
  1020. // Ask them if they really want to add the duplicate value
  1021. //
  1022. UINT nResult = ADSIEditMessageBox(IDS_ATTREDIT_DUPLICATE_VALUE, MB_YESNO);
  1023. lFind = (nResult == IDYES) ? LB_ERR : 1;
  1024. }
  1025. if (lFind == LB_ERR)
  1026. {
  1027. // Add the string to the list box
  1028. LRESULT index =
  1029. SendDlgItemMessage(
  1030. IDC_VALUE_LIST,
  1031. LB_ADDSTRING,
  1032. 0,
  1033. (LPARAM)(LPCWSTR)szNewValue);
  1034. if (index != LB_ERR)
  1035. {
  1036. // Set the item data to the integer value
  1037. SendDlgItemMessage(
  1038. IDC_VALUE_LIST,
  1039. LB_SETITEMDATA,
  1040. (WPARAM)index,
  1041. (LPARAM)newValue);
  1042. }
  1043. }
  1044. SetDlgItemText(IDC_VALUE_EDIT, L"");
  1045. }
  1046. else
  1047. {
  1048. //
  1049. // I was unable to convert the value to an integer so tell
  1050. // the user they can only enter digits from 0 to 9 and the
  1051. // - (negative) sign
  1052. //
  1053. ADSIEditMessageBox(IDS_ERR_MUST_BE_NUMERIC, MB_OK);
  1054. }
  1055. ManageButtonStates();
  1056. //
  1057. // Update the width of the list box
  1058. //
  1059. UpdateListboxHorizontalExtent();
  1060. }
  1061. }
  1062. void CMultiIntEditor::OnRemoveButton()
  1063. {
  1064. if (!m_bReadOnly)
  1065. {
  1066. CListBox* pListBox = reinterpret_cast<CListBox*>(GetDlgItem(IDC_VALUE_LIST));
  1067. if (pListBox != NULL)
  1068. {
  1069. int iCurSel = pListBox->GetCurSel();
  1070. if (iCurSel != LB_ERR)
  1071. {
  1072. //
  1073. // Put the old value into the edit box
  1074. //
  1075. CString szOldValue;
  1076. pListBox->GetText(iCurSel, szOldValue);
  1077. SetDlgItemText(IDC_VALUE_EDIT, szOldValue);
  1078. //
  1079. // Delete the item from the list box
  1080. //
  1081. pListBox->DeleteString(iCurSel);
  1082. }
  1083. }
  1084. //
  1085. // Manage Button States
  1086. //
  1087. ManageButtonStates();
  1088. //
  1089. // Update the width of the list box
  1090. //
  1091. UpdateListboxHorizontalExtent();
  1092. }
  1093. }
  1094. void CMultiIntEditor::ManageButtonStates()
  1095. {
  1096. if (m_bReadOnly)
  1097. {
  1098. GetDlgItem(IDC_ATTR_REMOVE_BUTTON)->EnableWindow(FALSE);
  1099. GetDlgItem(IDC_ATTR_ADD_BUTTON)->EnableWindow(FALSE);
  1100. }
  1101. else
  1102. {
  1103. //
  1104. // Change the default button to the Add button
  1105. //
  1106. int value = 0;
  1107. BOOL trans = FALSE;
  1108. value = GetDlgItemInt(IDC_VALUE_EDIT, &trans, TRUE);
  1109. if (!trans)
  1110. {
  1111. //
  1112. // Set the default button to OK
  1113. //
  1114. SendMessage(DM_SETDEFID, (WPARAM)IDOK, 0);
  1115. SendDlgItemMessage(IDC_ATTR_ADD_BUTTON,
  1116. BM_SETSTYLE,
  1117. BS_PUSHBUTTON,
  1118. MAKELPARAM(TRUE, 0));
  1119. SendDlgItemMessage(IDOK,
  1120. BM_SETSTYLE,
  1121. BS_DEFPUSHBUTTON,
  1122. MAKELPARAM(TRUE, 0));
  1123. }
  1124. else
  1125. {
  1126. //
  1127. // Set the default button to the Add button
  1128. //
  1129. SendMessage(DM_SETDEFID, (WPARAM)IDC_ATTR_ADD_BUTTON, 0);
  1130. SendDlgItemMessage(IDOK,
  1131. BM_SETSTYLE,
  1132. BS_PUSHBUTTON,
  1133. MAKELPARAM(TRUE, 0));
  1134. SendDlgItemMessage(IDC_ATTR_ADD_BUTTON,
  1135. BM_SETSTYLE,
  1136. BS_DEFPUSHBUTTON,
  1137. MAKELPARAM(TRUE, 0));
  1138. }
  1139. LRESULT lSelection = SendDlgItemMessage(IDC_VALUE_LIST, LB_GETCURSEL, 0, 0);
  1140. if (lSelection != LB_ERR)
  1141. {
  1142. GetDlgItem(IDC_ATTR_REMOVE_BUTTON)->EnableWindow(TRUE);
  1143. }
  1144. else
  1145. {
  1146. GetDlgItem(IDC_ATTR_REMOVE_BUTTON)->EnableWindow(FALSE);
  1147. }
  1148. }
  1149. }
  1150. void CMultiIntEditor::OnListSelChange()
  1151. {
  1152. ManageButtonStates();
  1153. }
  1154. void CMultiIntEditor::OnEditChange()
  1155. {
  1156. ManageButtonStates();
  1157. }
  1158. void CMultiIntEditor::UpdateListboxHorizontalExtent()
  1159. {
  1160. int nHorzExtent = 0;
  1161. CListBox* pListBox = reinterpret_cast<CListBox*>(GetDlgItem(IDC_VALUE_LIST));
  1162. if (pListBox != NULL)
  1163. {
  1164. CClientDC dc(pListBox);
  1165. int nItems = pListBox->GetCount();
  1166. for (int i=0; i < nItems; i++)
  1167. {
  1168. TEXTMETRIC tm;
  1169. VERIFY(dc.GetTextMetrics(&tm));
  1170. CString szBuffer;
  1171. pListBox->GetText(i, szBuffer);
  1172. CSize ext = dc.GetTextExtent(szBuffer,szBuffer.GetLength());
  1173. nHorzExtent = max(ext.cx ,nHorzExtent);
  1174. }
  1175. pListBox->SetHorizontalExtent(nHorzExtent);
  1176. }
  1177. }
  1178. HRESULT CMultiIntEditor::Initialize(LPDS_ATTRIBUTE_EDITORINFO pAttributeEditorInfo)
  1179. {
  1180. HRESULT hr = S_OK;
  1181. if (SUCCEEDED(CValueEditDialog::Initialize(pAttributeEditorInfo)))
  1182. {
  1183. if (pAttributeEditorInfo->dwNumValues > 0 &&
  1184. pAttributeEditorInfo->pADsValue != NULL)
  1185. {
  1186. for (int idx = 0; idx < pAttributeEditorInfo->dwNumValues; idx++)
  1187. {
  1188. switch (pAttributeEditorInfo->pADsValue[idx].dwType)
  1189. {
  1190. case ADSTYPE_INTEGER:
  1191. m_oldValueList.AddTail(pAttributeEditorInfo->pADsValue[idx].Integer);
  1192. break;
  1193. default:
  1194. ASSERT(FALSE);
  1195. break;
  1196. }
  1197. }
  1198. }
  1199. }
  1200. return hr;
  1201. }
  1202. // FUTURE-2002/03/05-artm Very similar functionality in CSingleIntEditor
  1203. // and CMultiStringEditor classes. Perhaps there is a way to combine the
  1204. // classes into a single class....or have one class inherit from the other.
  1205. HRESULT CMultiIntEditor::GetNewValue(PADSVALUE* ppADsValue, DWORD* pdwNumValues)
  1206. {
  1207. HRESULT hr = S_OK;
  1208. if (ppADsValue == NULL ||
  1209. pdwNumValues == NULL)
  1210. {
  1211. return E_OUTOFMEMORY;
  1212. }
  1213. int iCount = m_newValueList.GetCount();
  1214. if (iCount == 0)
  1215. {
  1216. *ppADsValue = NULL;
  1217. *pdwNumValues = 0;
  1218. }
  1219. else
  1220. {
  1221. *ppADsValue = new ADSVALUE[iCount];
  1222. if (*ppADsValue != NULL)
  1223. {
  1224. *pdwNumValues = iCount;
  1225. int idx = 0;
  1226. POSITION pos = m_newValueList.GetHeadPosition();
  1227. while (pos != NULL)
  1228. {
  1229. int newValue = m_newValueList.GetNext(pos);
  1230. (*ppADsValue)[idx].dwType = m_pOldADsValue->dwType;
  1231. switch (m_pOldADsValue->dwType)
  1232. {
  1233. case ADSTYPE_INTEGER:
  1234. (*ppADsValue)[idx].Integer = newValue;
  1235. break;
  1236. default:
  1237. ASSERT(FALSE);
  1238. DeleteADsValues(*ppADsValue, *pdwNumValues);
  1239. *ppADsValue = NULL;
  1240. *pdwNumValues = 0;
  1241. hr = E_FAIL;
  1242. break;
  1243. }
  1244. idx++;
  1245. }
  1246. }
  1247. else
  1248. {
  1249. *ppADsValue = NULL;
  1250. *pdwNumValues = 0;
  1251. hr = E_OUTOFMEMORY;
  1252. }
  1253. }
  1254. return hr;
  1255. }
  1256. ///////////////////////////////////////////////////////////////////////////////////////
  1257. // CSingleLargeIntEditor
  1258. CValueEditDialog* CreateSingleLargeIntEditor(PCWSTR pszClass,
  1259. PCWSTR pszAttribute,
  1260. ADSTYPE adsType,
  1261. BOOL bMultivalued)
  1262. {
  1263. return new CSingleLargeIntEditor;
  1264. }
  1265. BEGIN_MESSAGE_MAP(CSingleLargeIntEditor, CValueEditDialog)
  1266. ON_BN_CLICKED(IDC_CLEAR_BUTTON, OnClear)
  1267. END_MESSAGE_MAP()
  1268. BOOL CSingleLargeIntEditor::OnInitDialog()
  1269. {
  1270. //
  1271. // Initialize the static control with the attribute name
  1272. //
  1273. SetDlgItemText(IDC_ATTRIBUTE_STATIC, m_szAttribute);
  1274. //
  1275. // Initialize the edit box with the value
  1276. //
  1277. if (!m_bValueSet)
  1278. {
  1279. CString szNotSet;
  1280. VERIFY(szNotSet.LoadString(IDS_NOTSET));
  1281. SetDlgItemText(IDC_VALUE_EDIT, szNotSet);
  1282. }
  1283. else
  1284. {
  1285. CString szOldValue;
  1286. litow(m_liOldValue, szOldValue);
  1287. SetDlgItemText(IDC_VALUE_EDIT, szOldValue);
  1288. }
  1289. //
  1290. // Select the text in the edit box
  1291. //
  1292. SendDlgItemMessage(IDC_VALUE_EDIT, EM_SETSEL, 0, -1);
  1293. //
  1294. // Disable IME support on the edit box
  1295. //
  1296. ImmAssociateContext(::GetDlgItem(GetSafeHwnd(), IDC_VALUE_EDIT), NULL);
  1297. if (m_bReadOnly)
  1298. {
  1299. SendDlgItemMessage(IDC_VALUE_EDIT, EM_SETREADONLY, TRUE, 0);
  1300. GetDlgItem(IDC_CLEAR_BUTTON)->EnableWindow(FALSE);
  1301. }
  1302. return CDialog::OnInitDialog();
  1303. }
  1304. void CSingleLargeIntEditor::OnOK()
  1305. {
  1306. if (!m_bReadOnly)
  1307. {
  1308. CString szNotSet;
  1309. VERIFY(szNotSet.LoadString(IDS_NOTSET));
  1310. CString szNewValue;
  1311. GetDlgItemText(IDC_VALUE_EDIT, szNewValue);
  1312. if (szNewValue == szNotSet)
  1313. {
  1314. m_bValueSet = FALSE;
  1315. }
  1316. else
  1317. {
  1318. wtoli(szNewValue, m_liNewValue);
  1319. m_bValueSet = TRUE;
  1320. }
  1321. }
  1322. CDialog::OnOK();
  1323. }
  1324. HRESULT CSingleLargeIntEditor::Initialize(LPDS_ATTRIBUTE_EDITORINFO pAttributeEditorInfo)
  1325. {
  1326. HRESULT hr = S_OK;
  1327. if (SUCCEEDED(CValueEditDialog::Initialize(pAttributeEditorInfo)))
  1328. {
  1329. if (pAttributeEditorInfo->dwNumValues > 0 &&
  1330. pAttributeEditorInfo->pADsValue != NULL)
  1331. {
  1332. switch (pAttributeEditorInfo->pADsValue->dwType)
  1333. {
  1334. case ADSTYPE_LARGE_INTEGER:
  1335. m_liOldValue = pAttributeEditorInfo->pADsValue->LargeInteger;
  1336. m_bValueSet = TRUE;
  1337. break;
  1338. default:
  1339. ASSERT(FALSE);
  1340. break;
  1341. }
  1342. }
  1343. else
  1344. {
  1345. m_bValueSet = FALSE;
  1346. }
  1347. }
  1348. return hr;
  1349. }
  1350. void CSingleLargeIntEditor::OnClear()
  1351. {
  1352. if (!m_bReadOnly)
  1353. {
  1354. //
  1355. // Change the text in the edit box to "<not set>"
  1356. //
  1357. CString szNotSet;
  1358. VERIFY(szNotSet.LoadString(IDS_NOTSET));
  1359. SetDlgItemText(IDC_VALUE_EDIT, szNotSet);
  1360. //
  1361. // Change the focus to the edit box
  1362. //
  1363. GetDlgItem(IDC_VALUE_EDIT)->SetFocus();
  1364. //
  1365. // Select the text in the edit box
  1366. //
  1367. SendDlgItemMessage(IDC_VALUE_EDIT, EM_SETSEL, 0, -1);
  1368. m_bValueSet = FALSE;
  1369. }
  1370. }
  1371. HRESULT CSingleLargeIntEditor::GetNewValue(PADSVALUE* ppADsValue, DWORD* pdwNumValues)
  1372. {
  1373. HRESULT hr = S_OK;
  1374. if (ppADsValue == NULL ||
  1375. pdwNumValues == NULL)
  1376. {
  1377. return E_OUTOFMEMORY;
  1378. }
  1379. if (!m_bValueSet)
  1380. {
  1381. *ppADsValue = NULL;
  1382. *pdwNumValues = 0;
  1383. }
  1384. else
  1385. {
  1386. *ppADsValue = new ADSVALUE;
  1387. if (*ppADsValue != NULL)
  1388. {
  1389. *pdwNumValues = 1;
  1390. (*ppADsValue)->dwType = m_pOldADsValue->dwType;
  1391. switch (m_pOldADsValue->dwType)
  1392. {
  1393. case ADSTYPE_LARGE_INTEGER:
  1394. (*ppADsValue)->LargeInteger = m_liNewValue;
  1395. break;
  1396. default:
  1397. ASSERT(FALSE);
  1398. DeleteADsValues(*ppADsValue, *pdwNumValues);
  1399. *ppADsValue = NULL;
  1400. *pdwNumValues = 0;
  1401. hr = E_FAIL;
  1402. break;
  1403. }
  1404. }
  1405. else
  1406. {
  1407. *pdwNumValues = 0;
  1408. hr = E_OUTOFMEMORY;
  1409. }
  1410. }
  1411. return hr;
  1412. }
  1413. ///////////////////////////////////////////////////////////////////////////////////////
  1414. // CSingleBooleanEditor
  1415. CValueEditDialog* CreateSingleBooleanEditor(PCWSTR pszClass,
  1416. PCWSTR pszAttribute,
  1417. ADSTYPE adsType,
  1418. BOOL bMultivalued)
  1419. {
  1420. return new CSingleBooleanEditor;
  1421. }
  1422. BEGIN_MESSAGE_MAP(CSingleBooleanEditor, CValueEditDialog)
  1423. END_MESSAGE_MAP()
  1424. BOOL CSingleBooleanEditor::OnInitDialog()
  1425. {
  1426. //
  1427. // Initialize the static control with the attribute name
  1428. //
  1429. SetDlgItemText(IDC_ATTRIBUTE_STATIC, m_szAttribute);
  1430. //
  1431. // Initialize the edit box with the value
  1432. //
  1433. if (!m_bValueSet)
  1434. {
  1435. SendDlgItemMessage(IDC_NOTSET_RADIO, BM_SETCHECK, BST_CHECKED, 0);
  1436. }
  1437. else
  1438. {
  1439. if (m_bOldValue)
  1440. {
  1441. SendDlgItemMessage(IDC_TRUE_RADIO, BM_SETCHECK, BST_CHECKED, 0);
  1442. }
  1443. else
  1444. {
  1445. SendDlgItemMessage(IDC_FALSE_RADIO, BM_SETCHECK, BST_CHECKED, 0);
  1446. }
  1447. }
  1448. if (m_bReadOnly)
  1449. {
  1450. GetDlgItem(IDC_TRUE_RADIO)->EnableWindow(FALSE);
  1451. GetDlgItem(IDC_FALSE_RADIO)->EnableWindow(FALSE);
  1452. }
  1453. return CDialog::OnInitDialog();
  1454. }
  1455. void CSingleBooleanEditor::OnOK()
  1456. {
  1457. if (!m_bReadOnly)
  1458. {
  1459. LRESULT lTrueCheck = SendDlgItemMessage(IDC_TRUE_RADIO, BM_GETCHECK, 0, 0);
  1460. LRESULT lFalseCheck = SendDlgItemMessage(IDC_FALSE_RADIO, BM_GETCHECK, 0, 0);
  1461. LRESULT lNotSetCheck = SendDlgItemMessage(IDC_NOTSET_RADIO, BM_GETCHECK, 0, 0);
  1462. if (lTrueCheck == BST_CHECKED)
  1463. {
  1464. m_bNewValue = TRUE;
  1465. m_bValueSet = TRUE;
  1466. }
  1467. if (lFalseCheck == BST_CHECKED)
  1468. {
  1469. m_bNewValue = FALSE;
  1470. m_bValueSet = TRUE;
  1471. }
  1472. if (lNotSetCheck == BST_CHECKED)
  1473. {
  1474. m_bValueSet = FALSE;
  1475. }
  1476. }
  1477. CDialog::OnOK();
  1478. }
  1479. HRESULT CSingleBooleanEditor::Initialize(LPDS_ATTRIBUTE_EDITORINFO pAttributeEditorInfo)
  1480. {
  1481. HRESULT hr = S_OK;
  1482. if (SUCCEEDED(CValueEditDialog::Initialize(pAttributeEditorInfo)))
  1483. {
  1484. if (pAttributeEditorInfo->dwNumValues > 0 &&
  1485. pAttributeEditorInfo->pADsValue != NULL)
  1486. {
  1487. switch (pAttributeEditorInfo->pADsValue->dwType)
  1488. {
  1489. case ADSTYPE_BOOLEAN:
  1490. m_bOldValue = pAttributeEditorInfo->pADsValue->Boolean;
  1491. m_bValueSet = TRUE;
  1492. break;
  1493. default:
  1494. ASSERT(FALSE);
  1495. break;
  1496. }
  1497. }
  1498. else
  1499. {
  1500. m_bValueSet = FALSE;
  1501. }
  1502. }
  1503. return hr;
  1504. }
  1505. HRESULT CSingleBooleanEditor::GetNewValue(PADSVALUE* ppADsValue, DWORD* pdwNumValues)
  1506. {
  1507. HRESULT hr = S_OK;
  1508. if (ppADsValue == NULL ||
  1509. pdwNumValues == NULL)
  1510. {
  1511. return E_OUTOFMEMORY;
  1512. }
  1513. if (!m_bValueSet)
  1514. {
  1515. *ppADsValue = NULL;
  1516. *pdwNumValues = 0;
  1517. }
  1518. else
  1519. {
  1520. *ppADsValue = new ADSVALUE;
  1521. if (*ppADsValue != NULL)
  1522. {
  1523. *pdwNumValues = 1;
  1524. (*ppADsValue)->dwType = m_pOldADsValue->dwType;
  1525. switch (m_pOldADsValue->dwType)
  1526. {
  1527. case ADSTYPE_BOOLEAN:
  1528. (*ppADsValue)->Boolean = m_bNewValue;
  1529. break;
  1530. default:
  1531. ASSERT(FALSE);
  1532. DeleteADsValues(*ppADsValue, *pdwNumValues);
  1533. *ppADsValue = NULL;
  1534. *pdwNumValues = 0;
  1535. hr = E_FAIL;
  1536. break;
  1537. }
  1538. }
  1539. else
  1540. {
  1541. *pdwNumValues = 0;
  1542. hr = E_OUTOFMEMORY;
  1543. }
  1544. }
  1545. return hr;
  1546. }
  1547. ///////////////////////////////////////////////////////////////////////////////////////
  1548. // CMultiBooleanEditor
  1549. CValueEditDialog* CreateMultiBooleanEditor(PCWSTR pszClass,
  1550. PCWSTR pszAttribute,
  1551. ADSTYPE adsType,
  1552. BOOL bMultivalued)
  1553. {
  1554. return new CMultiBooleanEditor;
  1555. }
  1556. BEGIN_MESSAGE_MAP(CMultiBooleanEditor, CValueEditDialog)
  1557. ON_BN_CLICKED(IDC_ATTR_ADD_BUTTON, OnAddButton)
  1558. ON_BN_CLICKED(IDC_ATTR_REMOVE_BUTTON, OnRemoveButton)
  1559. ON_LBN_SELCHANGE(IDC_VALUE_LIST, OnListSelChange)
  1560. ON_BN_CLICKED(IDC_TRUE_RADIO, OnRadioChange)
  1561. ON_BN_CLICKED(IDC_FALSE_RADIO, OnRadioChange)
  1562. END_MESSAGE_MAP()
  1563. BOOL CMultiBooleanEditor::OnInitDialog()
  1564. {
  1565. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  1566. CDialog::OnInitDialog();
  1567. //
  1568. // Set the attribute name static
  1569. //
  1570. SetDlgItemText(IDC_ATTRIBUTE_STATIC, m_szAttribute);
  1571. //
  1572. // Fill the list box with the current values
  1573. //
  1574. CString szTrue;
  1575. szTrue.LoadString(IDS_TRUE);
  1576. CString szFalse;
  1577. szFalse.LoadString(IDS_FALSE);
  1578. POSITION pos = m_bOldValueList.GetHeadPosition();
  1579. while (pos != NULL)
  1580. {
  1581. BOOL bValue = m_bOldValueList.GetNext(pos);
  1582. SendDlgItemMessage(IDC_VALUE_LIST, LB_ADDSTRING, 0, (LPARAM)(LPCWSTR)(bValue ? szTrue : szFalse));
  1583. }
  1584. //
  1585. // The remove button should be disabled until something is selected in the listbox
  1586. //
  1587. GetDlgItem(IDC_ATTR_REMOVE_BUTTON)->EnableWindow(FALSE);
  1588. ManageButtonStates();
  1589. //
  1590. // Update the width of the list box
  1591. //
  1592. UpdateListboxHorizontalExtent();
  1593. if (m_bReadOnly)
  1594. {
  1595. GetDlgItem(IDC_TRUE_RADIO)->EnableWindow(FALSE);
  1596. GetDlgItem(IDC_FALSE_RADIO)->EnableWindow(FALSE);
  1597. GetDlgItem(IDC_ATTR_REMOVE_BUTTON)->EnableWindow(FALSE);
  1598. GetDlgItem(IDC_ATTR_ADD_BUTTON)->EnableWindow(FALSE);
  1599. }
  1600. //
  1601. // NOTE: I have explicitly set the focus so return 0
  1602. //
  1603. return FALSE;
  1604. }
  1605. void CMultiBooleanEditor::OnOK()
  1606. {
  1607. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  1608. if (!m_bReadOnly)
  1609. {
  1610. //
  1611. // Get the values out of the list box
  1612. //
  1613. m_bNewValueList.RemoveAll();
  1614. CString szTrue;
  1615. szTrue.LoadString(IDS_TRUE);
  1616. CListBox* pListBox = reinterpret_cast<CListBox*>(GetDlgItem(IDC_VALUE_LIST));
  1617. if (pListBox != NULL)
  1618. {
  1619. int iCount = pListBox->GetCount();
  1620. for (int idx = 0; idx < iCount; idx++)
  1621. {
  1622. CString szNewValue;
  1623. pListBox->GetText(idx, szNewValue);
  1624. if (szNewValue.CompareNoCase(szTrue) == 0)
  1625. {
  1626. m_bNewValueList.AddTail(TRUE);
  1627. }
  1628. else
  1629. {
  1630. m_bNewValueList.AddTail(FALSE);
  1631. }
  1632. }
  1633. }
  1634. }
  1635. CDialog::OnOK();
  1636. }
  1637. void CMultiBooleanEditor::OnAddButton()
  1638. {
  1639. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  1640. if (!m_bReadOnly)
  1641. {
  1642. //
  1643. // Add the value to the list box and clear the edit field
  1644. //
  1645. CString szNewValue;
  1646. LRESULT result = SendDlgItemMessage(IDC_TRUE_RADIO, BM_GETCHECK, 0, 0);
  1647. if (result == BST_CHECKED)
  1648. {
  1649. szNewValue.LoadString(IDS_TRUE);
  1650. }
  1651. else
  1652. {
  1653. szNewValue.LoadString(IDS_FALSE);
  1654. }
  1655. SendDlgItemMessage(IDC_VALUE_LIST, LB_ADDSTRING, 0, (LPARAM)(LPCWSTR)szNewValue);
  1656. ManageButtonStates();
  1657. //
  1658. // Update the width of the list box
  1659. //
  1660. UpdateListboxHorizontalExtent();
  1661. }
  1662. }
  1663. void CMultiBooleanEditor::OnRemoveButton()
  1664. {
  1665. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  1666. if (!m_bReadOnly)
  1667. {
  1668. CListBox* pListBox = reinterpret_cast<CListBox*>(GetDlgItem(IDC_VALUE_LIST));
  1669. if (pListBox != NULL)
  1670. {
  1671. int iCurSel = pListBox->GetCurSel();
  1672. if (iCurSel != LB_ERR)
  1673. {
  1674. //
  1675. // Put the old value into the radio buttons
  1676. //
  1677. CString szOldValue;
  1678. pListBox->GetText(iCurSel, szOldValue);
  1679. SetDlgItemText(IDC_VALUE_EDIT, szOldValue);
  1680. CString szTrue;
  1681. szTrue.LoadString(IDS_TRUE);
  1682. if (szOldValue.CompareNoCase(szTrue) == 0)
  1683. {
  1684. SendDlgItemMessage(IDC_TRUE_RADIO, BM_SETCHECK, BST_CHECKED, 0);
  1685. SendDlgItemMessage(IDC_FALSE_RADIO, BM_SETCHECK, BST_UNCHECKED, 0);
  1686. }
  1687. else
  1688. {
  1689. SendDlgItemMessage(IDC_TRUE_RADIO, BM_SETCHECK, BST_UNCHECKED, 0);
  1690. SendDlgItemMessage(IDC_FALSE_RADIO, BM_SETCHECK, BST_CHECKED, 0);
  1691. }
  1692. //
  1693. // Delete the item from the list box
  1694. //
  1695. pListBox->DeleteString(iCurSel);
  1696. }
  1697. }
  1698. //
  1699. // Manage Button States
  1700. //
  1701. ManageButtonStates();
  1702. //
  1703. // Update the width of the list box
  1704. //
  1705. UpdateListboxHorizontalExtent();
  1706. }
  1707. }
  1708. void CMultiBooleanEditor::ManageButtonStates()
  1709. {
  1710. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  1711. if (m_bReadOnly)
  1712. {
  1713. GetDlgItem(IDC_TRUE_RADIO)->EnableWindow(FALSE);
  1714. GetDlgItem(IDC_FALSE_RADIO)->EnableWindow(FALSE);
  1715. GetDlgItem(IDC_ATTR_REMOVE_BUTTON)->EnableWindow(FALSE);
  1716. GetDlgItem(IDC_ATTR_ADD_BUTTON)->EnableWindow(FALSE);
  1717. }
  1718. else
  1719. {
  1720. //
  1721. // Change the default button to the Add button
  1722. //
  1723. LRESULT trueResult = SendDlgItemMessage(IDC_TRUE_RADIO, BM_GETCHECK, 0, 0);
  1724. LRESULT falseResult = SendDlgItemMessage(IDC_FALSE_RADIO, BM_GETCHECK, 0, 0);
  1725. if (trueResult != BST_CHECKED &&
  1726. falseResult != BST_CHECKED)
  1727. {
  1728. //
  1729. // Set the default button to OK
  1730. //
  1731. SendMessage(DM_SETDEFID, (WPARAM)IDOK, 0);
  1732. SendDlgItemMessage(IDC_ATTR_ADD_BUTTON,
  1733. BM_SETSTYLE,
  1734. BS_PUSHBUTTON,
  1735. MAKELPARAM(TRUE, 0));
  1736. SendDlgItemMessage(IDOK,
  1737. BM_SETSTYLE,
  1738. BS_DEFPUSHBUTTON,
  1739. MAKELPARAM(TRUE, 0));
  1740. }
  1741. else
  1742. {
  1743. //
  1744. // Set the default button to the Add button
  1745. //
  1746. SendMessage(DM_SETDEFID, (WPARAM)IDC_ATTR_ADD_BUTTON, 0);
  1747. SendDlgItemMessage(IDOK,
  1748. BM_SETSTYLE,
  1749. BS_PUSHBUTTON,
  1750. MAKELPARAM(TRUE, 0));
  1751. SendDlgItemMessage(IDC_ATTR_ADD_BUTTON,
  1752. BM_SETSTYLE,
  1753. BS_DEFPUSHBUTTON,
  1754. MAKELPARAM(TRUE, 0));
  1755. }
  1756. LRESULT lSelection = SendDlgItemMessage(IDC_VALUE_LIST, LB_GETCURSEL, 0, 0);
  1757. if (lSelection != LB_ERR)
  1758. {
  1759. GetDlgItem(IDC_ATTR_REMOVE_BUTTON)->EnableWindow(TRUE);
  1760. }
  1761. else
  1762. {
  1763. GetDlgItem(IDC_ATTR_REMOVE_BUTTON)->EnableWindow(FALSE);
  1764. }
  1765. }
  1766. }
  1767. void CMultiBooleanEditor::OnListSelChange()
  1768. {
  1769. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  1770. ManageButtonStates();
  1771. }
  1772. void CMultiBooleanEditor::OnRadioChange()
  1773. {
  1774. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  1775. ManageButtonStates();
  1776. }
  1777. void CMultiBooleanEditor::UpdateListboxHorizontalExtent()
  1778. {
  1779. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  1780. int nHorzExtent = 0;
  1781. CListBox* pListBox = reinterpret_cast<CListBox*>(GetDlgItem(IDC_VALUE_LIST));
  1782. if (pListBox != NULL)
  1783. {
  1784. CClientDC dc(pListBox);
  1785. int nItems = pListBox->GetCount();
  1786. for (int i=0; i < nItems; i++)
  1787. {
  1788. TEXTMETRIC tm = {0};
  1789. VERIFY(dc.GetTextMetrics(&tm));
  1790. CString szBuffer;
  1791. pListBox->GetText(i, szBuffer);
  1792. CSize ext = dc.GetTextExtent(szBuffer,szBuffer.GetLength());
  1793. nHorzExtent = max(ext.cx ,nHorzExtent);
  1794. }
  1795. pListBox->SetHorizontalExtent(nHorzExtent);
  1796. }
  1797. }
  1798. HRESULT CMultiBooleanEditor::Initialize(LPDS_ATTRIBUTE_EDITORINFO pAttributeEditorInfo)
  1799. {
  1800. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  1801. HRESULT hr = S_OK;
  1802. if (SUCCEEDED(CValueEditDialog::Initialize(pAttributeEditorInfo)))
  1803. {
  1804. if (pAttributeEditorInfo->dwNumValues > 0 &&
  1805. pAttributeEditorInfo->pADsValue != NULL)
  1806. {
  1807. for (int idx = 0; idx < pAttributeEditorInfo->dwNumValues; idx++)
  1808. {
  1809. switch (pAttributeEditorInfo->pADsValue[idx].dwType)
  1810. {
  1811. case ADSTYPE_BOOLEAN:
  1812. m_bOldValueList.AddTail(pAttributeEditorInfo->pADsValue[idx].Boolean);
  1813. break;
  1814. default:
  1815. ASSERT(FALSE);
  1816. break;
  1817. }
  1818. }
  1819. }
  1820. }
  1821. return hr;
  1822. }
  1823. HRESULT CMultiBooleanEditor::GetNewValue(PADSVALUE* ppADsValue, DWORD* pdwNumValues)
  1824. {
  1825. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  1826. HRESULT hr = S_OK;
  1827. if (ppADsValue == NULL ||
  1828. pdwNumValues == NULL)
  1829. {
  1830. return E_OUTOFMEMORY;
  1831. }
  1832. int iCount = m_bNewValueList.GetCount();
  1833. if (iCount == 0)
  1834. {
  1835. *ppADsValue = NULL;
  1836. *pdwNumValues = 0;
  1837. }
  1838. else
  1839. {
  1840. *ppADsValue = new ADSVALUE[iCount];
  1841. if (*ppADsValue != NULL)
  1842. {
  1843. *pdwNumValues = iCount;
  1844. int idx = 0;
  1845. POSITION pos = m_bNewValueList.GetHeadPosition();
  1846. while (pos != NULL)
  1847. {
  1848. BOOL bNewValue = m_bNewValueList.GetNext(pos);
  1849. (*ppADsValue)[idx].dwType = m_pOldADsValue->dwType;
  1850. switch (m_pOldADsValue->dwType)
  1851. {
  1852. case ADSTYPE_BOOLEAN:
  1853. (*ppADsValue)[idx].Boolean = bNewValue;
  1854. break;
  1855. default:
  1856. ASSERT(FALSE);
  1857. DeleteADsValues(*ppADsValue, *pdwNumValues);
  1858. *ppADsValue = NULL;
  1859. *pdwNumValues = 0;
  1860. hr = E_FAIL;
  1861. break;
  1862. }
  1863. idx++;
  1864. }
  1865. }
  1866. else
  1867. {
  1868. *ppADsValue = NULL;
  1869. *pdwNumValues = 0;
  1870. hr = E_OUTOFMEMORY;
  1871. }
  1872. }
  1873. return hr;
  1874. }
  1875. ///////////////////////////////////////////////////////////////////////////////////////
  1876. // CSingleTimeEditor
  1877. CValueEditDialog* CreateSingleTimeEditor(PCWSTR pszClass,
  1878. PCWSTR pszAttribute,
  1879. ADSTYPE adsType,
  1880. BOOL bMultivalued)
  1881. {
  1882. return new CSingleTimeEditor;
  1883. }
  1884. BEGIN_MESSAGE_MAP(CSingleTimeEditor, CValueEditDialog)
  1885. END_MESSAGE_MAP()
  1886. BOOL CSingleTimeEditor::OnInitDialog()
  1887. {
  1888. //
  1889. // Initialize the static control with the attribute name
  1890. //
  1891. SetDlgItemText(IDC_ATTRIBUTE_STATIC, m_szAttribute);
  1892. if (m_bValueSet)
  1893. {
  1894. SendDlgItemMessage(IDC_DATE_PICKER, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&m_stOldValue);
  1895. SendDlgItemMessage(IDC_TIME_PICKER, DTM_SETSYSTEMTIME, GDT_VALID, (LPARAM)&m_stOldValue);
  1896. }
  1897. else
  1898. {
  1899. SendDlgItemMessage(IDC_DATE_PICKER, DTM_SETSYSTEMTIME, GDT_NONE, (LPARAM)&m_stOldValue);
  1900. SendDlgItemMessage(IDC_TIME_PICKER, DTM_SETSYSTEMTIME, GDT_NONE, (LPARAM)&m_stOldValue);
  1901. }
  1902. if (m_bReadOnly)
  1903. {
  1904. GetDlgItem(IDC_DATE_PICKER)->EnableWindow(FALSE);
  1905. GetDlgItem(IDC_TIME_PICKER)->EnableWindow(FALSE);
  1906. }
  1907. return CDialog::OnInitDialog();
  1908. }
  1909. void CSingleTimeEditor::OnOK()
  1910. {
  1911. if (!m_bReadOnly)
  1912. {
  1913. SYSTEMTIME stDateResult = {0};
  1914. SYSTEMTIME stTimeResult = {0};
  1915. LRESULT lDateRes = SendDlgItemMessage(IDC_DATE_PICKER, DTM_GETSYSTEMTIME, 0, (LPARAM)&stDateResult);
  1916. LRESULT lTimeRes = SendDlgItemMessage(IDC_TIME_PICKER, DTM_GETSYSTEMTIME, 0, (LPARAM)&stTimeResult);
  1917. if (lDateRes == GDT_VALID ||
  1918. lTimeRes == GDT_VALID)
  1919. {
  1920. memcpy(&m_stNewValue, &stDateResult, sizeof(SYSTEMTIME));
  1921. m_stNewValue.wHour = stTimeResult.wHour;
  1922. m_stNewValue.wMinute = stTimeResult.wMinute;
  1923. m_stNewValue.wSecond = stTimeResult.wSecond;
  1924. m_stNewValue.wMilliseconds = stTimeResult.wMilliseconds;
  1925. }
  1926. }
  1927. CDialog::OnOK();
  1928. }
  1929. HRESULT CSingleTimeEditor::Initialize(LPDS_ATTRIBUTE_EDITORINFO pAttributeEditorInfo)
  1930. {
  1931. HRESULT hr = S_OK;
  1932. if (SUCCEEDED(CValueEditDialog::Initialize(pAttributeEditorInfo)))
  1933. {
  1934. if (pAttributeEditorInfo->dwNumValues > 0 &&
  1935. pAttributeEditorInfo->pADsValue != NULL)
  1936. {
  1937. switch (pAttributeEditorInfo->pADsValue->dwType)
  1938. {
  1939. case ADSTYPE_UTC_TIME:
  1940. // NOTICE-2002/03/05-artm memcpy() OK...
  1941. // arg1 always valid pointer; arg2 valid ptr if
  1942. // pAttributeEditorInfo->pADsValue not NULL
  1943. // (which is the case if we've gotten this far)
  1944. memcpy(&m_stOldValue, &(pAttributeEditorInfo->pADsValue->UTCTime), sizeof(SYSTEMTIME));
  1945. m_bValueSet = TRUE;
  1946. break;
  1947. default:
  1948. ASSERT(FALSE);
  1949. // NTRAID#NTBUG9-565760-2002/03/05-artm Release code should return error code,
  1950. // not S_OK.
  1951. break;
  1952. }
  1953. }
  1954. else
  1955. {
  1956. m_bValueSet = FALSE;
  1957. }
  1958. }
  1959. return hr;
  1960. }
  1961. HRESULT CSingleTimeEditor::GetNewValue(PADSVALUE* ppADsValue, DWORD* pdwNumValues)
  1962. {
  1963. HRESULT hr = S_OK;
  1964. if (ppADsValue == NULL ||
  1965. pdwNumValues == NULL)
  1966. {
  1967. return E_OUTOFMEMORY;
  1968. }
  1969. *ppADsValue = new ADSVALUE;
  1970. if (*ppADsValue != NULL)
  1971. {
  1972. *pdwNumValues = 1;
  1973. (*ppADsValue)->dwType = m_pOldADsValue->dwType;
  1974. switch (m_pOldADsValue->dwType)
  1975. {
  1976. case ADSTYPE_UTC_TIME:
  1977. memcpy(&((*ppADsValue)->UTCTime), &m_stNewValue, sizeof(SYSTEMTIME));
  1978. break;
  1979. default:
  1980. ASSERT(FALSE);
  1981. DeleteADsValues(*ppADsValue, *pdwNumValues);
  1982. *ppADsValue = NULL;
  1983. *pdwNumValues = 0;
  1984. hr = E_FAIL;
  1985. break;
  1986. }
  1987. }
  1988. else
  1989. {
  1990. *pdwNumValues = 0;
  1991. hr = E_OUTOFMEMORY;
  1992. }
  1993. return hr;
  1994. }
  1995. ///////////////////////////////////////////////////////////////////////////////////////
  1996. // CMultiTimeEditor
  1997. CValueEditDialog* CreateMultiTimeEditor(PCWSTR pszClass,
  1998. PCWSTR pszAttribute,
  1999. ADSTYPE adsType,
  2000. BOOL bMultivalued)
  2001. {
  2002. return new CMultiTimeEditor;
  2003. }
  2004. BEGIN_MESSAGE_MAP(CMultiTimeEditor, CValueEditDialog)
  2005. ON_BN_CLICKED(IDC_ATTR_ADD_BUTTON, OnAddButton)
  2006. ON_BN_CLICKED(IDC_ATTR_REMOVE_BUTTON, OnRemoveButton)
  2007. ON_LBN_SELCHANGE(IDC_VALUE_LIST, OnListSelChange)
  2008. END_MESSAGE_MAP()
  2009. BOOL CMultiTimeEditor::OnInitDialog()
  2010. {
  2011. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  2012. CDialog::OnInitDialog();
  2013. //
  2014. // Set the attribute name static
  2015. //
  2016. SetDlgItemText(IDC_ATTRIBUTE_STATIC, m_szAttribute);
  2017. //
  2018. // Fill the list box with the current values
  2019. //
  2020. CListBox* pListBox = reinterpret_cast<CListBox*>(GetDlgItem(IDC_VALUE_LIST));
  2021. POSITION pos = m_stOldValueList.GetHeadPosition();
  2022. while (pos != NULL)
  2023. {
  2024. SYSTEMTIME* pstValue = m_stOldValueList.GetNext(pos);
  2025. CString szValue = GetStringValueFromSystemTime(pstValue);
  2026. int index = pListBox->AddString(szValue);
  2027. if (LB_ERR != index)
  2028. {
  2029. pListBox->SetItemDataPtr(index, pstValue);
  2030. }
  2031. }
  2032. //
  2033. // The remove button should be disabled until something is selected in the listbox
  2034. //
  2035. GetDlgItem(IDC_ATTR_REMOVE_BUTTON)->EnableWindow(FALSE);
  2036. ManageButtonStates();
  2037. //
  2038. // Update the width of the list box
  2039. //
  2040. UpdateListboxHorizontalExtent();
  2041. if (m_bReadOnly)
  2042. {
  2043. GetDlgItem(IDC_ATTR_REMOVE_BUTTON)->EnableWindow(FALSE);
  2044. GetDlgItem(IDC_ATTR_ADD_BUTTON)->EnableWindow(FALSE);
  2045. GetDlgItem(IDC_DATE_PICKER)->EnableWindow(FALSE);
  2046. GetDlgItem(IDC_TIME_PICKER)->EnableWindow(FALSE);
  2047. }
  2048. //
  2049. // NOTE: I have explicitly set the focus so return 0
  2050. //
  2051. return FALSE;
  2052. }
  2053. void CMultiTimeEditor::OnOK()
  2054. {
  2055. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  2056. if (!m_bReadOnly)
  2057. {
  2058. //
  2059. // Get the values out of the list box
  2060. //
  2061. m_stNewValueList.RemoveAll();
  2062. CListBox* pListBox = reinterpret_cast<CListBox*>(GetDlgItem(IDC_VALUE_LIST));
  2063. if (pListBox != NULL)
  2064. {
  2065. int iCount = pListBox->GetCount();
  2066. for (int idx = 0; idx < iCount; idx++)
  2067. {
  2068. SYSTEMTIME* pstValue = reinterpret_cast<SYSTEMTIME*>(pListBox->GetItemDataPtr(idx));
  2069. m_stNewValueList.AddTail(pstValue);
  2070. }
  2071. }
  2072. }
  2073. CDialog::OnOK();
  2074. }
  2075. void CMultiTimeEditor::OnAddButton()
  2076. {
  2077. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  2078. if (!m_bReadOnly)
  2079. {
  2080. //
  2081. // Add the value to the list box and clear the edit field
  2082. //
  2083. SYSTEMTIME stDateResult = {0};
  2084. SYSTEMTIME stTimeResult = {0};
  2085. SYSTEMTIME* pstFullResult = new SYSTEMTIME;
  2086. if (!pstFullResult)
  2087. {
  2088. return;
  2089. }
  2090. ZeroMemory(pstFullResult, sizeof(SYSTEMTIME));
  2091. LRESULT lDateRes = SendDlgItemMessage(IDC_DATE_PICKER, DTM_GETSYSTEMTIME, 0, (LPARAM)&stDateResult);
  2092. LRESULT lTimeRes = SendDlgItemMessage(IDC_TIME_PICKER, DTM_GETSYSTEMTIME, 0, (LPARAM)&stTimeResult);
  2093. if (lDateRes == GDT_VALID ||
  2094. lTimeRes == GDT_VALID)
  2095. {
  2096. memcpy(pstFullResult, &stDateResult, sizeof(SYSTEMTIME));
  2097. pstFullResult->wHour = stTimeResult.wHour;
  2098. pstFullResult->wMinute = stTimeResult.wMinute;
  2099. pstFullResult->wSecond = stTimeResult.wSecond;
  2100. pstFullResult->wMilliseconds = stTimeResult.wMilliseconds;
  2101. // Convert into a string that can be added to the list
  2102. CListBox* pListBox = reinterpret_cast<CListBox*>(GetDlgItem(IDC_VALUE_LIST));
  2103. if (pListBox != NULL)
  2104. {
  2105. CString szValue = GetStringValueFromSystemTime(pstFullResult);
  2106. int index = pListBox->AddString(szValue);
  2107. if (LB_ERR != index)
  2108. {
  2109. pListBox->SetItemDataPtr(index, pstFullResult);
  2110. }
  2111. }
  2112. }
  2113. ManageButtonStates();
  2114. //
  2115. // Update the width of the list box
  2116. //
  2117. UpdateListboxHorizontalExtent();
  2118. }
  2119. }
  2120. void CMultiTimeEditor::OnRemoveButton()
  2121. {
  2122. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  2123. if (!m_bReadOnly)
  2124. {
  2125. CListBox* pListBox = reinterpret_cast<CListBox*>(GetDlgItem(IDC_VALUE_LIST));
  2126. if (pListBox != NULL)
  2127. {
  2128. int iCurSel = pListBox->GetCurSel();
  2129. if (iCurSel != LB_ERR)
  2130. {
  2131. //
  2132. // Delete the item from the list box
  2133. //
  2134. pListBox->DeleteString(iCurSel);
  2135. }
  2136. }
  2137. //
  2138. // Manage Button States
  2139. //
  2140. ManageButtonStates();
  2141. //
  2142. // Update the width of the list box
  2143. //
  2144. UpdateListboxHorizontalExtent();
  2145. }
  2146. }
  2147. void CMultiTimeEditor::ManageButtonStates()
  2148. {
  2149. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  2150. if (m_bReadOnly)
  2151. {
  2152. GetDlgItem(IDC_ATTR_REMOVE_BUTTON)->EnableWindow(FALSE);
  2153. GetDlgItem(IDC_ATTR_ADD_BUTTON)->EnableWindow(FALSE);
  2154. GetDlgItem(IDC_DATE_PICKER)->EnableWindow(FALSE);
  2155. GetDlgItem(IDC_TIME_PICKER)->EnableWindow(FALSE);
  2156. }
  2157. else
  2158. {
  2159. //
  2160. // Change the default button to the Add button
  2161. //
  2162. SYSTEMTIME stDateResult = {0};
  2163. SYSTEMTIME stTimeResult = {0};
  2164. LRESULT lDateRes = SendDlgItemMessage(IDC_DATE_PICKER, DTM_GETSYSTEMTIME, 0, (LPARAM)&stDateResult);
  2165. LRESULT lTimeRes = SendDlgItemMessage(IDC_TIME_PICKER, DTM_GETSYSTEMTIME, 0, (LPARAM)&stTimeResult);
  2166. if (lDateRes == GDT_VALID &&
  2167. lTimeRes == GDT_VALID)
  2168. {
  2169. //
  2170. // Set the default button to OK
  2171. //
  2172. SendMessage(DM_SETDEFID, (WPARAM)IDOK, 0);
  2173. SendDlgItemMessage(IDC_ATTR_ADD_BUTTON,
  2174. BM_SETSTYLE,
  2175. BS_PUSHBUTTON,
  2176. MAKELPARAM(TRUE, 0));
  2177. SendDlgItemMessage(IDOK,
  2178. BM_SETSTYLE,
  2179. BS_DEFPUSHBUTTON,
  2180. MAKELPARAM(TRUE, 0));
  2181. }
  2182. else
  2183. {
  2184. //
  2185. // Set the default button to the Add button
  2186. //
  2187. SendMessage(DM_SETDEFID, (WPARAM)IDC_ATTR_ADD_BUTTON, 0);
  2188. SendDlgItemMessage(IDOK,
  2189. BM_SETSTYLE,
  2190. BS_PUSHBUTTON,
  2191. MAKELPARAM(TRUE, 0));
  2192. SendDlgItemMessage(IDC_ATTR_ADD_BUTTON,
  2193. BM_SETSTYLE,
  2194. BS_DEFPUSHBUTTON,
  2195. MAKELPARAM(TRUE, 0));
  2196. }
  2197. LRESULT lSelection = SendDlgItemMessage(IDC_VALUE_LIST, LB_GETCURSEL, 0, 0);
  2198. if (lSelection != LB_ERR)
  2199. {
  2200. GetDlgItem(IDC_ATTR_REMOVE_BUTTON)->EnableWindow(TRUE);
  2201. }
  2202. else
  2203. {
  2204. GetDlgItem(IDC_ATTR_REMOVE_BUTTON)->EnableWindow(FALSE);
  2205. }
  2206. }
  2207. }
  2208. void CMultiTimeEditor::OnListSelChange()
  2209. {
  2210. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  2211. ManageButtonStates();
  2212. }
  2213. void CMultiTimeEditor::UpdateListboxHorizontalExtent()
  2214. {
  2215. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  2216. int nHorzExtent = 0;
  2217. CListBox* pListBox = reinterpret_cast<CListBox*>(GetDlgItem(IDC_VALUE_LIST));
  2218. if (pListBox != NULL)
  2219. {
  2220. CClientDC dc(pListBox);
  2221. int nItems = pListBox->GetCount();
  2222. for (int i=0; i < nItems; i++)
  2223. {
  2224. TEXTMETRIC tm = {0};
  2225. VERIFY(dc.GetTextMetrics(&tm));
  2226. CString szBuffer;
  2227. pListBox->GetText(i, szBuffer);
  2228. CSize ext = dc.GetTextExtent(szBuffer,szBuffer.GetLength());
  2229. nHorzExtent = max(ext.cx ,nHorzExtent);
  2230. }
  2231. pListBox->SetHorizontalExtent(nHorzExtent);
  2232. }
  2233. }
  2234. HRESULT CMultiTimeEditor::Initialize(LPDS_ATTRIBUTE_EDITORINFO pAttributeEditorInfo)
  2235. {
  2236. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  2237. HRESULT hr = S_OK;
  2238. if (SUCCEEDED(CValueEditDialog::Initialize(pAttributeEditorInfo)))
  2239. {
  2240. if (pAttributeEditorInfo->dwNumValues > 0 &&
  2241. pAttributeEditorInfo->pADsValue != NULL)
  2242. {
  2243. for (int idx = 0; idx < pAttributeEditorInfo->dwNumValues; idx++)
  2244. {
  2245. switch (pAttributeEditorInfo->pADsValue[idx].dwType)
  2246. {
  2247. case ADSTYPE_UTC_TIME:
  2248. m_stOldValueList.AddTail(&(pAttributeEditorInfo->pADsValue[idx].UTCTime));
  2249. break;
  2250. default:
  2251. ASSERT(FALSE);
  2252. break;
  2253. }
  2254. }
  2255. }
  2256. }
  2257. return hr;
  2258. }
  2259. HRESULT CMultiTimeEditor::GetNewValue(PADSVALUE* ppADsValue, DWORD* pdwNumValues)
  2260. {
  2261. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  2262. HRESULT hr = S_OK;
  2263. if (ppADsValue == NULL ||
  2264. pdwNumValues == NULL)
  2265. {
  2266. return E_OUTOFMEMORY;
  2267. }
  2268. int iCount = m_stNewValueList.GetCount();
  2269. if (iCount == 0)
  2270. {
  2271. *ppADsValue = NULL;
  2272. *pdwNumValues = 0;
  2273. }
  2274. else
  2275. {
  2276. *ppADsValue = new ADSVALUE[iCount];
  2277. if (*ppADsValue != NULL)
  2278. {
  2279. *pdwNumValues = iCount;
  2280. int idx = 0;
  2281. POSITION pos = m_stNewValueList.GetHeadPosition();
  2282. while (pos != NULL)
  2283. {
  2284. SYSTEMTIME* pstNewValue = m_stNewValueList.GetNext(pos);
  2285. (*ppADsValue)[idx].dwType = m_pOldADsValue->dwType;
  2286. switch (m_pOldADsValue->dwType)
  2287. {
  2288. case ADSTYPE_UTC_TIME:
  2289. memcpy(&((*ppADsValue)[idx].UTCTime), pstNewValue, sizeof(SYSTEMTIME));
  2290. break;
  2291. default:
  2292. ASSERT(FALSE);
  2293. DeleteADsValues(*ppADsValue, *pdwNumValues);
  2294. *ppADsValue = NULL;
  2295. *pdwNumValues = 0;
  2296. hr = E_FAIL;
  2297. break;
  2298. }
  2299. idx++;
  2300. }
  2301. }
  2302. else
  2303. {
  2304. *ppADsValue = NULL;
  2305. *pdwNumValues = 0;
  2306. hr = E_OUTOFMEMORY;
  2307. }
  2308. }
  2309. return hr;
  2310. }
  2311. ///////////////////////////////////////////////////////////////////////////////////////
  2312. // COctetStringEditor
  2313. CValueEditDialog* CreateSingleOctetStringEditor(PCWSTR pszClass,
  2314. PCWSTR pszAttribute,
  2315. ADSTYPE adsType,
  2316. BOOL bMultivalued)
  2317. {
  2318. return new COctetStringEditor;
  2319. }
  2320. BEGIN_MESSAGE_MAP(COctetStringEditor, CValueEditDialog)
  2321. ON_EN_CHANGE(IDC_PROCESS_EDIT, OnProcessEdit)
  2322. ON_BN_CLICKED(IDC_ATTR_EDIT_BUTTON, OnEditButton)
  2323. ON_BN_CLICKED(IDC_CLEAR_BUTTON, OnClearButton)
  2324. END_MESSAGE_MAP()
  2325. BOOL COctetStringEditor::OnInitDialog()
  2326. {
  2327. //
  2328. // Initialize the static control with the attribute name
  2329. //
  2330. SetDlgItemText(IDC_ATTRIBUTE_STATIC, m_szAttribute);
  2331. DWORD dwDisplayFlags = BYTE_ARRAY_DISPLAY_HEX |
  2332. BYTE_ARRAY_DISPLAY_DEC |
  2333. BYTE_ARRAY_DISPLAY_OCT |
  2334. BYTE_ARRAY_DISPLAY_BIN;
  2335. VERIFY(m_display.Initialize(IDC_VALUE_EDIT,
  2336. IDC_VIEW_TYPE_COMBO,
  2337. dwDisplayFlags,
  2338. BYTE_ARRAY_DISPLAY_HEX, // default display
  2339. this,
  2340. 1024,
  2341. IDS_OCTET_DISPLAY_SIZE_EXCEEDED)); // Only show 1K of data in the edit box
  2342. m_display.SetData(m_pOldValue, m_dwOldLength);
  2343. if (m_bReadOnly)
  2344. {
  2345. SendDlgItemMessage(IDC_VALUE_EDIT, EM_SETREADONLY, TRUE, 0);
  2346. GetDlgItem(IDC_CLEAR_BUTTON)->EnableWindow(FALSE);
  2347. CString szView;
  2348. BOOL bResult = szView.LoadString(IDS_VIEW);
  2349. ASSERT(bResult);
  2350. SetDlgItemText(IDC_ATTR_EDIT_BUTTON, szView);
  2351. }
  2352. return CDialog::OnInitDialog();
  2353. }
  2354. void COctetStringEditor::OnOK()
  2355. {
  2356. if (!m_bReadOnly)
  2357. {
  2358. //
  2359. // Retrieve the new values from the control
  2360. //
  2361. if (m_pNewValue)
  2362. {
  2363. delete[] m_pNewValue;
  2364. m_pNewValue = 0;
  2365. m_dwNewLength = 0;
  2366. }
  2367. m_dwNewLength = m_display.GetData(&m_pNewValue);
  2368. }
  2369. CDialog::OnOK();
  2370. }
  2371. void COctetStringEditor::OnProcessEdit()
  2372. {
  2373. CString szProcess;
  2374. GetDlgItemText(IDC_PROCESS_EDIT, szProcess);
  2375. if (szProcess.IsEmpty())
  2376. {
  2377. GetDlgItem(IDC_ATTR_EDIT_BUTTON)->EnableWindow(FALSE);
  2378. //
  2379. // Set the default button to OK
  2380. //
  2381. SendMessage(DM_SETDEFID, (WPARAM)IDOK, 0);
  2382. SendDlgItemMessage(IDC_ATTR_EDIT_BUTTON,
  2383. BM_SETSTYLE,
  2384. BS_PUSHBUTTON,
  2385. MAKELPARAM(TRUE, 0));
  2386. SendDlgItemMessage(IDOK,
  2387. BM_SETSTYLE,
  2388. BS_DEFPUSHBUTTON,
  2389. MAKELPARAM(TRUE, 0));
  2390. }
  2391. else
  2392. {
  2393. GetDlgItem(IDC_ATTR_EDIT_BUTTON)->EnableWindow(TRUE);
  2394. //
  2395. // Set the default button to the Edit button
  2396. //
  2397. SendMessage(DM_SETDEFID, (WPARAM)IDC_ATTR_EDIT_BUTTON, 0);
  2398. SendDlgItemMessage(IDOK,
  2399. BM_SETSTYLE,
  2400. BS_PUSHBUTTON,
  2401. MAKELPARAM(TRUE, 0));
  2402. SendDlgItemMessage(IDC_ATTR_EDIT_BUTTON,
  2403. BM_SETSTYLE,
  2404. BS_DEFPUSHBUTTON,
  2405. MAKELPARAM(TRUE, 0));
  2406. }
  2407. }
  2408. void COctetStringEditor::OnEditButton()
  2409. {
  2410. CString szProcess;
  2411. GetDlgItemText(IDC_PROCESS_EDIT, szProcess);
  2412. //
  2413. // Create a temp file and write out the contents of the octet string
  2414. //
  2415. WCHAR szTempPath[MAX_PATH];
  2416. if (!::GetTempPath(MAX_PATH, szTempPath))
  2417. {
  2418. ADSIEditMessageBox(IDS_MSG_FAIL_CREATE_TEMPFILE, MB_OK);
  2419. return;
  2420. }
  2421. CString szDataPath;
  2422. if (!::GetTempFileName(szTempPath, _T("attredit"), 0x0, szDataPath.GetBuffer(MAX_PATH)))
  2423. {
  2424. ADSIEditMessageBox(IDS_MSG_FAIL_CREATE_TEMPFILE, MB_OK);
  2425. return;
  2426. }
  2427. szDataPath.ReleaseBuffer();
  2428. //
  2429. // Open the temp file so we can write out the data
  2430. //
  2431. CFile tempDataFile;
  2432. if (!tempDataFile.Open(szDataPath,
  2433. CFile::modeCreate | CFile::modeReadWrite |CFile::shareExclusive | CFile::typeBinary))
  2434. {
  2435. //
  2436. // Failed to open temp file, display error message
  2437. //
  2438. ADSIEditMessageBox(IDS_MSG_FAIL_CREATE_TEMPFILE, MB_OK);
  2439. return;
  2440. }
  2441. //
  2442. // Write the byte array to a temp file
  2443. //
  2444. BYTE* pData = 0;
  2445. DWORD dwDataLength = m_display.GetData(&pData);
  2446. if (dwDataLength != 0 && pData)
  2447. {
  2448. tempDataFile.Write(pData, dwDataLength);
  2449. }
  2450. tempDataFile.Close();
  2451. if (pData)
  2452. {
  2453. delete[] pData;
  2454. pData = 0;
  2455. }
  2456. dwDataLength = 0;
  2457. //
  2458. // Construct the command line from the executable and the temp file
  2459. //
  2460. CString szCommandLine = szProcess + L" " + szDataPath;
  2461. //
  2462. // Launch the process with the temp file as an argument
  2463. //
  2464. STARTUPINFO si;
  2465. PROCESS_INFORMATION pi;
  2466. ::ZeroMemory(&pi,sizeof(PROCESS_INFORMATION));
  2467. ::ZeroMemory(&si,sizeof(STARTUPINFO));
  2468. si.cb = sizeof (STARTUPINFO);
  2469. // NTRAID#NTBUG9-566011-2002/03/05-artm CreateProcess() incorrectly used.
  2470. // Vulnerability exists b/c application name is NULL, meaning that
  2471. // the first whitespace delimited token in the command line is the
  2472. // executable name. This opens up a hole for trojan programs
  2473. // (e.g. C:\Program.exe).
  2474. //
  2475. // Since we have the process name separate from data path,
  2476. // fix is to pass szProcess as first argument and szDataPath
  2477. // as command line argument.
  2478. //
  2479. // I couldn't tell if the program name and data path were
  2480. // complete paths or not---but they should be if they are not!
  2481. if(CreateProcess( NULL,
  2482. (LPWSTR)(LPCWSTR)szCommandLine,
  2483. NULL,
  2484. NULL,
  2485. FALSE,
  2486. 0,
  2487. NULL,
  2488. NULL,
  2489. &si,
  2490. &pi) )
  2491. {
  2492. // wait to finish the runing setup process
  2493. WaitForSingleObject(pi.hProcess,INFINITE);
  2494. // close process handle
  2495. if (pi.hProcess && pi.hProcess != INVALID_HANDLE_VALUE)
  2496. {
  2497. CloseHandle (pi.hProcess) ;
  2498. }
  2499. if (pi.hThread && pi.hThread != INVALID_HANDLE_VALUE)
  2500. {
  2501. CloseHandle (pi.hThread) ;
  2502. }
  2503. }
  2504. else
  2505. {
  2506. ADSIEditMessageBox(IDS_MSG_FAIL_LAUNCH_PROCESS, MB_OK);
  2507. return;
  2508. }
  2509. if (!m_bReadOnly)
  2510. {
  2511. //
  2512. // Load the data from the saved temp file
  2513. //
  2514. if (!LoadFileAsByteArray(szDataPath, &pData, &dwDataLength))
  2515. {
  2516. ADSIEditMessageBox(IDS_MSG_FAIL_RETRIEVE_SAVED_DATA, MB_OK);
  2517. return;
  2518. }
  2519. //
  2520. // Delete temp file after picture is displayed
  2521. //
  2522. CFile::Remove(szDataPath);
  2523. //
  2524. // Update the UI with the new data
  2525. //
  2526. m_display.SetData(pData, dwDataLength);
  2527. }
  2528. }
  2529. void COctetStringEditor::OnClearButton()
  2530. {
  2531. if (!m_bReadOnly)
  2532. {
  2533. m_display.ClearData();
  2534. }
  2535. }
  2536. HRESULT COctetStringEditor::Initialize(LPDS_ATTRIBUTE_EDITORINFO pAttributeEditorInfo)
  2537. {
  2538. HRESULT hr = S_OK;
  2539. if (SUCCEEDED(CValueEditDialog::Initialize(pAttributeEditorInfo)))
  2540. {
  2541. if (pAttributeEditorInfo->dwNumValues > 0 &&
  2542. pAttributeEditorInfo->pADsValue)
  2543. {
  2544. switch (pAttributeEditorInfo->pADsValue->dwType)
  2545. {
  2546. case ADSTYPE_OCTET_STRING:
  2547. m_dwOldLength = pAttributeEditorInfo->pADsValue->OctetString.dwLength;
  2548. m_pOldValue = new BYTE[m_dwOldLength];
  2549. if (m_pOldValue)
  2550. {
  2551. // NOTICE-2002/03/05-artm memcpy() OK.
  2552. // arg1 is same size as lpValue
  2553. memcpy(m_pOldValue, pAttributeEditorInfo->pADsValue->OctetString.lpValue, m_dwOldLength);
  2554. }
  2555. else
  2556. {
  2557. hr = E_OUTOFMEMORY;
  2558. }
  2559. m_bValueSet = TRUE;
  2560. break;
  2561. default:
  2562. ASSERT(FALSE);
  2563. break;
  2564. }
  2565. }
  2566. else
  2567. {
  2568. m_bValueSet = FALSE;
  2569. }
  2570. }
  2571. return hr;
  2572. }
  2573. HRESULT COctetStringEditor::GetNewValue(PADSVALUE* ppADsValue, DWORD* pdwNumValues)
  2574. {
  2575. HRESULT hr = S_OK;
  2576. if (ppADsValue == NULL ||
  2577. pdwNumValues == NULL)
  2578. {
  2579. return E_OUTOFMEMORY;
  2580. }
  2581. if (m_dwNewLength > 0 && m_pNewValue)
  2582. {
  2583. *ppADsValue = new ADSVALUE;
  2584. if (*ppADsValue)
  2585. {
  2586. *pdwNumValues = 1;
  2587. (*ppADsValue)->dwType = m_pOldADsValue->dwType;
  2588. switch (m_pOldADsValue->dwType)
  2589. {
  2590. case ADSTYPE_OCTET_STRING:
  2591. (*ppADsValue)->OctetString.dwLength = m_dwNewLength;
  2592. (*ppADsValue)->OctetString.lpValue = new BYTE[m_dwNewLength];
  2593. if ((*ppADsValue)->OctetString.lpValue)
  2594. {
  2595. // NOTICE-2002/03/05-artm memcpy() OK.
  2596. // arg1 and arg2 both m_dwNewLength in size.
  2597. memcpy((*ppADsValue)->OctetString.lpValue, m_pNewValue, m_dwNewLength);
  2598. }
  2599. else
  2600. {
  2601. hr = E_OUTOFMEMORY;
  2602. }
  2603. break;
  2604. default:
  2605. ASSERT(FALSE);
  2606. DeleteADsValues(*ppADsValue, *pdwNumValues);
  2607. *ppADsValue = 0;
  2608. *pdwNumValues = 0;
  2609. hr = E_FAIL;
  2610. break;
  2611. }
  2612. }
  2613. else
  2614. {
  2615. *pdwNumValues = 0;
  2616. hr = E_OUTOFMEMORY;
  2617. }
  2618. }
  2619. else
  2620. {
  2621. *ppADsValue = 0;
  2622. *pdwNumValues = 0;
  2623. }
  2624. return hr;
  2625. }
  2626. CValueEditDialog* CreateMultiOctetStringEditor(PCWSTR pszClass,
  2627. PCWSTR pszAttribute,
  2628. ADSTYPE adsType,
  2629. BOOL bMultivalued)
  2630. {
  2631. return new CMultiOctetStringEditor;
  2632. }
  2633. BEGIN_MESSAGE_MAP(CMultiOctetStringEditor, CValueEditDialog)
  2634. ON_BN_CLICKED(IDC_ATTR_ADD_BUTTON, OnAddButton)
  2635. ON_BN_CLICKED(IDC_ATTR_REMOVE_BUTTON, OnRemoveButton)
  2636. ON_BN_CLICKED(IDC_EDIT_BUTTON, OnEditButton)
  2637. ON_LBN_SELCHANGE(IDC_VALUE_LIST, OnListSelChange)
  2638. END_MESSAGE_MAP()
  2639. BOOL CMultiOctetStringEditor::OnInitDialog()
  2640. {
  2641. CDialog::OnInitDialog();
  2642. //
  2643. // Set the attribute name static
  2644. //
  2645. SetDlgItemText(IDC_ATTRIBUTE_STATIC, m_szAttribute);
  2646. //
  2647. // Fill the list box with the current values
  2648. //
  2649. POSITION pos = m_OldValueList.GetHeadPosition();
  2650. while (pos)
  2651. {
  2652. PADSVALUE pADsValue = m_OldValueList.GetNext(pos);
  2653. if (pADsValue)
  2654. {
  2655. CString szValue;
  2656. GetStringFromADsValue(pADsValue, szValue, MAX_OCTET_STRING_VALUE_LENGTH);
  2657. LRESULT lIdx = SendDlgItemMessage(IDC_VALUE_LIST,
  2658. LB_ADDSTRING,
  2659. 0,
  2660. (LPARAM)(LPCWSTR)szValue);
  2661. if (lIdx != LB_ERR &&
  2662. lIdx != LB_ERRSPACE)
  2663. {
  2664. LRESULT lSetData = SendDlgItemMessage(IDC_VALUE_LIST,
  2665. LB_SETITEMDATA,
  2666. (WPARAM)lIdx,
  2667. (LPARAM)pADsValue);
  2668. if (lSetData == LB_ERR)
  2669. {
  2670. ASSERT(lSetData != LB_ERR);
  2671. continue;
  2672. }
  2673. }
  2674. }
  2675. }
  2676. //
  2677. // The remove button should be disabled until something is selected in the listbox
  2678. //
  2679. GetDlgItem(IDC_ATTR_REMOVE_BUTTON)->EnableWindow(FALSE);
  2680. SendDlgItemMessage(IDC_VALUE_LIST, LB_SETCURSEL, 0, 0);
  2681. ManageButtonStates();
  2682. //
  2683. // Update the width of the list box
  2684. //
  2685. UpdateListboxHorizontalExtent();
  2686. if (m_bReadOnly)
  2687. {
  2688. GetDlgItem(IDC_ATTR_REMOVE_BUTTON)->EnableWindow(FALSE);
  2689. GetDlgItem(IDC_ATTR_ADD_BUTTON)->EnableWindow(FALSE);
  2690. CString szView;
  2691. BOOL bResult = szView.LoadString(IDS_VIEW);
  2692. ASSERT(bResult);
  2693. SetDlgItemText(IDC_EDIT_BUTTON, szView);
  2694. }
  2695. //
  2696. // NOTE: I have explicitly set the focus so return 0
  2697. //
  2698. return FALSE;
  2699. }
  2700. void CMultiOctetStringEditor::OnOK()
  2701. {
  2702. if (!m_bReadOnly)
  2703. {
  2704. //
  2705. // Get the values out of the list box
  2706. //
  2707. m_NewValueList.RemoveAll();
  2708. CListBox* pListBox = reinterpret_cast<CListBox*>(GetDlgItem(IDC_VALUE_LIST));
  2709. if (pListBox != NULL)
  2710. {
  2711. int iCount = pListBox->GetCount();
  2712. for (int idx = 0; idx < iCount; idx++)
  2713. {
  2714. CString szNewValue;
  2715. LRESULT lData = SendDlgItemMessage(IDC_VALUE_LIST,
  2716. LB_GETITEMDATA,
  2717. (WPARAM)idx,
  2718. 0);
  2719. if (lData == LB_ERR)
  2720. {
  2721. ASSERT(lData != LB_ERR);
  2722. continue;
  2723. }
  2724. m_NewValueList.AddTail(reinterpret_cast<PADSVALUE>(lData));
  2725. }
  2726. }
  2727. }
  2728. CDialog::OnOK();
  2729. }
  2730. void CMultiOctetStringEditor::OnEditButton()
  2731. {
  2732. CThemeContextActivator activator;
  2733. LRESULT lIdx = SendDlgItemMessage(IDC_VALUE_LIST, LB_GETCURSEL, 0, 0);
  2734. if (lIdx == LB_ERR)
  2735. {
  2736. ASSERT(lIdx != LB_ERR);
  2737. return;
  2738. }
  2739. LRESULT lData = SendDlgItemMessage(IDC_VALUE_LIST, LB_GETITEMDATA, (WPARAM)lIdx, 0);
  2740. if (lData == LB_ERR)
  2741. {
  2742. ASSERT(lIdx != LB_ERR);
  2743. return;
  2744. }
  2745. PADSVALUE pADsValue = reinterpret_cast<PADSVALUE>(lData);
  2746. if (!pADsValue)
  2747. {
  2748. ASSERT(pADsValue);
  2749. return;
  2750. }
  2751. DS_ATTRIBUTE_EDITORINFO attrEditInfo;
  2752. ::ZeroMemory(&attrEditInfo, sizeof(DS_ATTRIBUTE_EDITORINFO));
  2753. attrEditInfo.pADsValue = pADsValue;
  2754. attrEditInfo.dwNumValues = 1;
  2755. attrEditInfo.lpszClass = (PWSTR)(PCWSTR)m_szClass;
  2756. attrEditInfo.lpszAttribute = (PWSTR)(PCWSTR)m_szAttribute;
  2757. attrEditInfo.bMultivalued = FALSE;
  2758. attrEditInfo.bReadOnly = m_bReadOnly;
  2759. attrEditInfo.lpfnBind = m_pfnBindingFunction;
  2760. attrEditInfo.lParam = m_lParam;
  2761. COctetStringEditor dlg;
  2762. HRESULT hr = dlg.Initialize(&attrEditInfo);
  2763. if (FAILED(hr))
  2764. {
  2765. ADSIEditErrorMessage(hr, IDS_FAILED_INITIALIZE_EDITOR, MB_OK | MB_ICONEXCLAMATION);
  2766. return;
  2767. }
  2768. if (dlg.DoModal() == IDOK &&
  2769. !m_bReadOnly)
  2770. {
  2771. PADSVALUE pNewADsValue = 0;
  2772. DWORD dwNumNewValues = 0;
  2773. hr = dlg.GetNewValue(&pNewADsValue, &dwNumNewValues);
  2774. if (FAILED(hr))
  2775. {
  2776. ADSIEditErrorMessage(hr, IDS_FAILED_GET_NEW_VALUE_EDITOR, MB_OK | MB_ICONEXCLAMATION);
  2777. return;
  2778. }
  2779. ASSERT(pNewADsValue);
  2780. ASSERT(dwNumNewValues == 1);
  2781. CString szNewValue;
  2782. GetStringFromADsValue(pNewADsValue, szNewValue, MAX_OCTET_STRING_VALUE_LENGTH);
  2783. ASSERT(!szNewValue.IsEmpty());
  2784. LRESULT lNewIdx = SendDlgItemMessage(IDC_VALUE_LIST,
  2785. LB_INSERTSTRING,
  2786. lIdx + 1,
  2787. (LPARAM)(PCWSTR)szNewValue);
  2788. if (lNewIdx != LB_ERR)
  2789. {
  2790. //
  2791. // Update the new item and delete the old
  2792. //
  2793. SendDlgItemMessage(IDC_VALUE_LIST, LB_SETITEMDATA, (WPARAM)lNewIdx, (LPARAM)pNewADsValue);
  2794. SendDlgItemMessage(IDC_VALUE_LIST, LB_DELETESTRING, (WPARAM)lIdx, 0);
  2795. }
  2796. else
  2797. {
  2798. //
  2799. // Since we had trouble adding the new item just update the old one. The string
  2800. // will be incorrect but the value will be fine.
  2801. //
  2802. SendDlgItemMessage(IDC_VALUE_LIST, LB_SETITEMDATA, (WPARAM)lIdx, (LPARAM)pNewADsValue);
  2803. }
  2804. }
  2805. }
  2806. void CMultiOctetStringEditor::OnRemoveButton()
  2807. {
  2808. if (!m_bReadOnly)
  2809. {
  2810. CListBox* pListBox = reinterpret_cast<CListBox*>(GetDlgItem(IDC_VALUE_LIST));
  2811. if (pListBox != NULL)
  2812. {
  2813. int iCurSel = pListBox->GetCurSel();
  2814. if (iCurSel != LB_ERR)
  2815. {
  2816. //
  2817. // Delete the item from the list box
  2818. //
  2819. pListBox->DeleteString(iCurSel);
  2820. }
  2821. }
  2822. //
  2823. // Manage Button States
  2824. //
  2825. ManageButtonStates();
  2826. //
  2827. // Update the width of the list box
  2828. //
  2829. UpdateListboxHorizontalExtent();
  2830. }
  2831. }
  2832. void CMultiOctetStringEditor::OnAddButton()
  2833. {
  2834. CThemeContextActivator activator;
  2835. if (!m_bReadOnly)
  2836. {
  2837. DS_ATTRIBUTE_EDITORINFO attrEditInfo;
  2838. ZeroMemory(&attrEditInfo, sizeof(DS_ATTRIBUTE_EDITORINFO));
  2839. attrEditInfo.pADsValue = new ADSVALUE;
  2840. if (attrEditInfo.pADsValue)
  2841. {
  2842. ::ZeroMemory(attrEditInfo.pADsValue, sizeof(ADSVALUE));
  2843. }
  2844. else
  2845. {
  2846. // NOTICE-NTRAID#NTBUG9-566088-2002/03/05-artm If mem. allocation fails, short circuit function.
  2847. // If we cannot allocate enough memory inform the user and return w/out
  2848. // performing the rest of the operation.
  2849. ADSIEditErrorMessage(E_OUTOFMEMORY);
  2850. return;
  2851. }
  2852. attrEditInfo.pADsValue->dwType = ADSTYPE_OCTET_STRING;
  2853. attrEditInfo.dwNumValues = 0;
  2854. attrEditInfo.lpszClass = (PWSTR)(PCWSTR)m_szClass;
  2855. attrEditInfo.lpszAttribute = (PWSTR)(PCWSTR)m_szAttribute;
  2856. attrEditInfo.bMultivalued = FALSE;
  2857. attrEditInfo.bReadOnly = m_bReadOnly;
  2858. attrEditInfo.lpfnBind = m_pfnBindingFunction;
  2859. attrEditInfo.lParam = m_lParam;
  2860. COctetStringEditor dlg;
  2861. HRESULT hr = dlg.Initialize(&attrEditInfo);
  2862. if (FAILED(hr))
  2863. {
  2864. ADSIEditErrorMessage(hr, IDS_FAILED_INITIALIZE_EDITOR, MB_OK | MB_ICONEXCLAMATION);
  2865. return;
  2866. }
  2867. if (dlg.DoModal() == IDOK)
  2868. {
  2869. PADSVALUE pNewADsValue = 0;
  2870. DWORD dwNumNewValues = 0;
  2871. hr = dlg.GetNewValue(&pNewADsValue, &dwNumNewValues);
  2872. if (FAILED(hr))
  2873. {
  2874. ADSIEditErrorMessage(hr, IDS_FAILED_GET_NEW_VALUE_EDITOR, MB_OK | MB_ICONEXCLAMATION);
  2875. return;
  2876. }
  2877. ASSERT(pNewADsValue);
  2878. ASSERT(dwNumNewValues == 1);
  2879. CString szNewValue;
  2880. GetStringFromADsValue(pNewADsValue,
  2881. szNewValue,
  2882. MAX_OCTET_STRING_VALUE_LENGTH);
  2883. if (!szNewValue.IsEmpty())
  2884. {
  2885. LRESULT lNewIdx = SendDlgItemMessage(IDC_VALUE_LIST,
  2886. LB_ADDSTRING,
  2887. 0,
  2888. (WPARAM)(PCWSTR)szNewValue);
  2889. if (lNewIdx != LB_ERR)
  2890. {
  2891. SendDlgItemMessage(IDC_VALUE_LIST, LB_SETITEMDATA, (WPARAM)lNewIdx, (LPARAM)pNewADsValue);
  2892. }
  2893. }
  2894. }
  2895. }
  2896. }
  2897. void CMultiOctetStringEditor::ManageButtonStates()
  2898. {
  2899. if (m_bReadOnly)
  2900. {
  2901. GetDlgItem(IDC_ATTR_REMOVE_BUTTON)->EnableWindow(FALSE);
  2902. GetDlgItem(IDC_EDIT_BUTTON)->EnableWindow(FALSE);
  2903. }
  2904. else
  2905. {
  2906. LRESULT lSelection = SendDlgItemMessage(IDC_VALUE_LIST, LB_GETCURSEL, 0, 0);
  2907. if (lSelection != LB_ERR)
  2908. {
  2909. GetDlgItem(IDC_ATTR_REMOVE_BUTTON)->EnableWindow(TRUE);
  2910. GetDlgItem(IDC_EDIT_BUTTON)->EnableWindow(TRUE);
  2911. }
  2912. else
  2913. {
  2914. GetDlgItem(IDC_ATTR_REMOVE_BUTTON)->EnableWindow(FALSE);
  2915. GetDlgItem(IDC_EDIT_BUTTON)->EnableWindow(FALSE);
  2916. }
  2917. }
  2918. }
  2919. void CMultiOctetStringEditor::OnListSelChange()
  2920. {
  2921. ManageButtonStates();
  2922. }
  2923. void CMultiOctetStringEditor::UpdateListboxHorizontalExtent()
  2924. {
  2925. //
  2926. // Note if the size passed to SetHorizontalExtent is less than the width of the control
  2927. // then the scroll bar will be removed
  2928. //
  2929. int nHorzExtent = 0;
  2930. CListBox* pListBox = reinterpret_cast<CListBox*>(GetDlgItem(IDC_VALUE_LIST));
  2931. if (pListBox != NULL)
  2932. {
  2933. CClientDC dc(pListBox);
  2934. int nItems = pListBox->GetCount();
  2935. for (int i=0; i < nItems; i++)
  2936. {
  2937. TEXTMETRIC tm;
  2938. VERIFY(dc.GetTextMetrics(&tm));
  2939. CString szBuffer;
  2940. pListBox->GetText(i, szBuffer);
  2941. CSize ext = dc.GetTextExtent(szBuffer,szBuffer.GetLength());
  2942. nHorzExtent = max(ext.cx ,nHorzExtent);
  2943. }
  2944. pListBox->SetHorizontalExtent(nHorzExtent);
  2945. }
  2946. }
  2947. HRESULT CMultiOctetStringEditor::Initialize(LPDS_ATTRIBUTE_EDITORINFO pAttributeEditorInfo)
  2948. {
  2949. HRESULT hr = S_OK;
  2950. if (SUCCEEDED(CValueEditDialog::Initialize(pAttributeEditorInfo)))
  2951. {
  2952. if (pAttributeEditorInfo->dwNumValues > 0 &&
  2953. pAttributeEditorInfo->pADsValue != NULL)
  2954. {
  2955. for (int idx = 0; idx < pAttributeEditorInfo->dwNumValues; idx++)
  2956. {
  2957. switch (pAttributeEditorInfo->pADsValue[idx].dwType)
  2958. {
  2959. case ADSTYPE_OCTET_STRING:
  2960. m_OldValueList.AddTail(&(pAttributeEditorInfo->pADsValue[idx]));
  2961. break;
  2962. default:
  2963. ASSERT(FALSE);
  2964. break;
  2965. }
  2966. }
  2967. }
  2968. }
  2969. return hr;
  2970. }
  2971. HRESULT CMultiOctetStringEditor::GetNewValue(PADSVALUE* ppADsValue, DWORD* pdwNumValues)
  2972. {
  2973. HRESULT hr = S_OK;
  2974. if (!ppADsValue ||
  2975. !pdwNumValues)
  2976. {
  2977. return E_OUTOFMEMORY;
  2978. }
  2979. int iCount = m_NewValueList.GetCount();
  2980. if (iCount == 0)
  2981. {
  2982. *ppADsValue = 0;
  2983. *pdwNumValues = 0;
  2984. }
  2985. else
  2986. {
  2987. *ppADsValue = new ADSVALUE[iCount];
  2988. if (*ppADsValue)
  2989. {
  2990. *pdwNumValues = iCount;
  2991. int idx = 0;
  2992. POSITION pos = m_NewValueList.GetHeadPosition();
  2993. while (pos)
  2994. {
  2995. PADSVALUE pADsValue = m_NewValueList.GetNext(pos);
  2996. (*ppADsValue)[idx].dwType = m_pOldADsValue->dwType;
  2997. switch (m_pOldADsValue->dwType)
  2998. {
  2999. case ADSTYPE_OCTET_STRING:
  3000. (*ppADsValue)[idx].OctetString.dwLength = pADsValue->OctetString.dwLength;
  3001. (*ppADsValue)[idx].OctetString.lpValue = new BYTE[pADsValue->OctetString.dwLength];
  3002. if ((*ppADsValue)[idx].OctetString.lpValue)
  3003. {
  3004. // NOTICE-2002/03/05-artm memcpy() OK.
  3005. // arg1 and arg2 are both dwLength in size.
  3006. memcpy((*ppADsValue)[idx].OctetString.lpValue,
  3007. pADsValue->OctetString.lpValue,
  3008. pADsValue->OctetString.dwLength);
  3009. }
  3010. else
  3011. {
  3012. DeleteADsValues(*ppADsValue, *pdwNumValues);
  3013. *ppADsValue = 0;
  3014. *pdwNumValues = 0;
  3015. hr = E_OUTOFMEMORY;
  3016. }
  3017. break;
  3018. default:
  3019. ASSERT(FALSE);
  3020. DeleteADsValues(*ppADsValue, *pdwNumValues);
  3021. *ppADsValue = 0;
  3022. *pdwNumValues = 0;
  3023. hr = E_FAIL;
  3024. break;
  3025. }
  3026. if (FAILED(hr))
  3027. {
  3028. return hr;
  3029. }
  3030. idx++;
  3031. }
  3032. }
  3033. else
  3034. {
  3035. *ppADsValue = NULL;
  3036. *pdwNumValues = 0;
  3037. hr = E_OUTOFMEMORY;
  3038. }
  3039. }
  3040. return hr;
  3041. }
  3042. /////////////////////////////////////////////////////////////////
  3043. // CDNWithStringEditor
  3044. CValueEditDialog* CreateDNWithStringEditor(PCWSTR pszClass,
  3045. PCWSTR pszAttribute,
  3046. ADSTYPE adsType,
  3047. BOOL bMultivalued)
  3048. {
  3049. return new CDNWithStringEditor;
  3050. }
  3051. BEGIN_MESSAGE_MAP(CDNWithStringEditor, CValueEditDialog)
  3052. ON_BN_CLICKED(IDC_CLEAR_BUTTON, OnClear)
  3053. END_MESSAGE_MAP()
  3054. BOOL CDNWithStringEditor::OnInitDialog()
  3055. {
  3056. CDialog::OnInitDialog();
  3057. return TRUE;
  3058. }
  3059. void CDNWithStringEditor::OnOK()
  3060. {
  3061. if (!m_bReadOnly)
  3062. {
  3063. GetDlgItemText(IDC_VALUE_EDIT, m_NewDNValue);
  3064. GetDlgItemText(IDC_STRING_VALUE_EDIT, m_NewStringValue);
  3065. }
  3066. CDialog::OnOK();
  3067. }
  3068. HRESULT CDNWithStringEditor::Initialize(LPDS_ATTRIBUTE_EDITORINFO pAttributeEditorInfo)
  3069. {
  3070. HRESULT hr = S_OK;
  3071. if (SUCCEEDED(CValueEditDialog::Initialize(pAttributeEditorInfo)))
  3072. {
  3073. if (pAttributeEditorInfo->dwNumValues > 0 &&
  3074. pAttributeEditorInfo->pADsValue != NULL)
  3075. {
  3076. ASSERT(pAttributeEditorInfo->dwNumValues == 1);
  3077. ASSERT(pAttributeEditorInfo->pADsValue->dwType == ADSTYPE_DN_WITH_STRING);
  3078. m_OldDNValue = pAttributeEditorInfo->pADsValue->pDNWithString->pszDNString;
  3079. m_OldStringValue = pAttributeEditorInfo->pADsValue->pDNWithString->pszStringValue;
  3080. }
  3081. }
  3082. return hr;
  3083. }
  3084. void CDNWithStringEditor::OnClear()
  3085. {
  3086. //
  3087. // Change the text in the edit box to "<not set>"
  3088. //
  3089. CString szNotSet;
  3090. VERIFY(szNotSet.LoadString(IDS_NOTSET));
  3091. SetDlgItemText(IDC_VALUE_EDIT, szNotSet);
  3092. SetDlgItemText(IDC_STRING_VALUE_EDIT, szNotSet);
  3093. //
  3094. // Change the focus to the edit box
  3095. //
  3096. GetDlgItem(IDC_VALUE_EDIT)->SetFocus();
  3097. //
  3098. // Select the text in the edit box
  3099. //
  3100. SendDlgItemMessage(IDC_VALUE_EDIT, EM_SETSEL, 0, -1);
  3101. }
  3102. HRESULT CDNWithStringEditor::GetNewValue(PADSVALUE* ppADsValue, DWORD* pdwNumValues)
  3103. {
  3104. HRESULT hr = S_OK;
  3105. if (ppADsValue == NULL ||
  3106. pdwNumValues == NULL)
  3107. {
  3108. return E_OUTOFMEMORY;
  3109. }
  3110. CString szNotSet;
  3111. VERIFY(szNotSet.LoadString(IDS_NOTSET));
  3112. if (m_NewDNValue == szNotSet ||
  3113. m_NewStringValue == szNotSet)
  3114. {
  3115. // User is clearing the attribute
  3116. *ppADsValue = NULL;
  3117. *pdwNumValues = 0;
  3118. return hr;
  3119. }
  3120. if (!m_NewDNValue.IsEmpty() ||
  3121. !m_NewStringValue.IsEmpty())
  3122. {
  3123. *ppADsValue = new ADSVALUE;
  3124. if (*ppADsValue)
  3125. {
  3126. *pdwNumValues = 1;
  3127. (*ppADsValue)->dwType = m_pOldADsValue->dwType;
  3128. ASSERT((*ppADsValue)->dwType == ADSTYPE_DN_WITH_STRING);
  3129. (*ppADsValue)->pDNWithString = new ADS_DN_WITH_STRING;
  3130. if ((*ppADsValue)->pDNWithString)
  3131. {
  3132. ZeroMemory((*ppADsValue)->pDNWithString, sizeof (ADS_DN_WITH_STRING));
  3133. int length = m_NewStringValue.GetLength();
  3134. (*ppADsValue)->pDNWithString->pszStringValue = new WCHAR[length + 1];
  3135. if ((*ppADsValue)->pDNWithString->pszStringValue)
  3136. {
  3137. ZeroMemory((*ppADsValue)->pDNWithString->pszStringValue, sizeof(WCHAR) * (length + 1));
  3138. wcsncpy((*ppADsValue)->pDNWithString->pszStringValue, m_NewStringValue, length);
  3139. length = m_NewDNValue.GetLength();
  3140. (*ppADsValue)->pDNWithString->pszDNString = new WCHAR[length + 1];
  3141. if ((*ppADsValue)->pDNWithString->pszDNString)
  3142. {
  3143. ZeroMemory((*ppADsValue)->pDNWithString->pszDNString, sizeof(WCHAR) * (length + 1));
  3144. wcsncpy((*ppADsValue)->pDNWithString->pszDNString, m_NewDNValue, length);
  3145. }
  3146. else
  3147. {
  3148. hr = E_OUTOFMEMORY;
  3149. }
  3150. }
  3151. else
  3152. {
  3153. hr = E_OUTOFMEMORY;
  3154. }
  3155. }
  3156. else
  3157. {
  3158. hr = E_OUTOFMEMORY;
  3159. }
  3160. }
  3161. else
  3162. {
  3163. hr = E_OUTOFMEMORY;
  3164. }
  3165. }
  3166. else
  3167. {
  3168. // Set an empty value
  3169. *ppADsValue = new ADSVALUE;
  3170. if (*ppADsValue)
  3171. {
  3172. *pdwNumValues = 1;
  3173. (*ppADsValue)->dwType = m_pOldADsValue->dwType;
  3174. ASSERT((*ppADsValue)->dwType == ADSTYPE_DN_WITH_STRING);
  3175. (*ppADsValue)->pDNWithString = new ADS_DN_WITH_STRING;
  3176. if ((*ppADsValue)->pDNWithString)
  3177. {
  3178. ZeroMemory((*ppADsValue)->pDNWithString, sizeof (ADS_DN_WITH_STRING));
  3179. }
  3180. else
  3181. {
  3182. hr = E_OUTOFMEMORY;
  3183. }
  3184. }
  3185. else
  3186. {
  3187. hr = E_OUTOFMEMORY;
  3188. }
  3189. }
  3190. if (FAILED(hr))
  3191. {
  3192. DeleteADsValues(*ppADsValue, *pdwNumValues);
  3193. *ppADsValue = 0;
  3194. *pdwNumValues = 0;
  3195. }
  3196. return hr;
  3197. }
  3198. ///////////////////////////////////////////////////////////////////////////////////////
  3199. // CAttributeEditorPropertyPage
  3200. BEGIN_MESSAGE_MAP(CAttributeEditorPropertyPage, CPropertyPage)
  3201. ON_BN_CLICKED(IDC_MANDATORY_CHECK, OnMandatoryCheck)
  3202. ON_BN_CLICKED(IDC_OPTIONAL_CHECK, OnOptionalCheck)
  3203. ON_BN_CLICKED(IDC_SET_CHECK, OnValueSetCheck)
  3204. ON_BN_CLICKED(IDC_ATTR_EDIT_BUTTON,OnEditAttribute)
  3205. ON_WM_CREATE()
  3206. ON_WM_DESTROY()
  3207. ON_NOTIFY(LVN_ITEMACTIVATE, IDC_ATTRIBUTE_LIST, OnNotifyEditAttribute)
  3208. ON_NOTIFY(LVN_ITEMCHANGED, IDC_ATTRIBUTE_LIST, OnListItemChanged)
  3209. ON_NOTIFY(LVN_COLUMNCLICK, IDC_ATTRIBUTE_LIST, OnSortList)
  3210. END_MESSAGE_MAP()
  3211. CAttributeEditorPropertyPage::CAttributeEditorPropertyPage(IADs* pIADs,
  3212. IADsClass* pIADsClass,
  3213. LPDS_ATTREDITOR_BINDINGINFO pBindingInfo,
  3214. CADSIEditPropertyPageHolder* pHolder)
  3215. : CPropertyPage(IDD_ATTRIBUTE_EDITOR_DIALOG)
  3216. {
  3217. m_spIADs = pIADs;
  3218. m_spIADsClass = pIADsClass;
  3219. m_bMandatory = TRUE;
  3220. m_bOptional = TRUE;
  3221. m_bSet = FALSE;
  3222. m_nSortColumn = 0;
  3223. ASSERT(pBindingInfo != NULL);
  3224. ASSERT(pBindingInfo->dwSize == sizeof(DS_ATTREDITOR_BINDINGINFO));
  3225. ASSERT(pBindingInfo->lpfnBind != NULL);
  3226. ASSERT(pBindingInfo->lpszProviderServer != NULL);
  3227. m_szPrefix = pBindingInfo->lpszProviderServer;
  3228. m_pfnBind = pBindingInfo->lpfnBind;
  3229. m_BindLPARAM = pBindingInfo->lParam;
  3230. m_dwBindFlags = pBindingInfo->dwFlags;
  3231. m_pHolder = pHolder;
  3232. ASSERT(m_pHolder);
  3233. }
  3234. CAttributeEditorPropertyPage::~CAttributeEditorPropertyPage()
  3235. {
  3236. }
  3237. BOOL CAttributeEditorPropertyPage::OnInitDialog()
  3238. {
  3239. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  3240. CWaitCursor cursor;
  3241. // Set the hwnd in the property page holder so that we can
  3242. // be activated when necessary
  3243. m_pHolder->SetSheetWindow(GetParent()->GetSafeHwnd());
  3244. ((CButton*)GetDlgItem(IDC_MANDATORY_CHECK))->SetCheck(TRUE);
  3245. ((CButton*)GetDlgItem(IDC_OPTIONAL_CHECK))->SetCheck(TRUE);
  3246. ((CButton*)GetDlgItem(IDC_SET_CHECK))->SetCheck(FALSE);
  3247. GetDlgItem(IDC_ATTR_EDIT_BUTTON)->EnableWindow(FALSE);
  3248. HRESULT hr = GetSchemaNamingContext();
  3249. ShowListCtrl();
  3250. hr = RetrieveAttributes();
  3251. if (FAILED(hr))
  3252. {
  3253. TRACE(_T("OnInitDialog() : error returned from RetrieveAttributes() = 0x%x\n"), hr);
  3254. }
  3255. CComBSTR bstr;
  3256. hr = m_spIADs->get_Class(&bstr);
  3257. if (FAILED(hr))
  3258. {
  3259. TRACE(_T("OnInitDialog() : error returned from m_pIADs->get_Class() = 0x%x\n"), hr);
  3260. }
  3261. else
  3262. {
  3263. m_szClass = bstr;
  3264. }
  3265. FillListControl();
  3266. return FALSE;
  3267. }
  3268. int CAttributeEditorPropertyPage::OnCreate(LPCREATESTRUCT lpCreateStruct)
  3269. {
  3270. m_pHolder->AddRef();
  3271. int res = CPropertyPage::OnCreate(lpCreateStruct);
  3272. ASSERT(res == 0);
  3273. ASSERT(m_hWnd != NULL);
  3274. ASSERT(::IsWindow(m_hWnd));
  3275. HWND hParent = ::GetParent(m_hWnd);
  3276. ASSERT(hParent);
  3277. m_pHolder->SetSheetWindow(hParent);
  3278. return res;
  3279. }
  3280. void CAttributeEditorPropertyPage::OnDestroy()
  3281. {
  3282. ASSERT(m_hWnd != NULL);
  3283. CPropertyPage::OnDestroy();
  3284. m_pHolder->Release();
  3285. }
  3286. HRESULT CAttributeEditorPropertyPage::GetSchemaNamingContext()
  3287. {
  3288. HRESULT hr = S_OK;
  3289. CComPtr<IADs> spIADs;
  3290. CString m_szPath = m_szPrefix + _T("RootDSE");
  3291. hr = m_pfnBind(m_szPath,
  3292. ADS_SECURE_AUTHENTICATION,
  3293. IID_IADs,
  3294. (PVOID*)&spIADs,
  3295. m_BindLPARAM);
  3296. if (SUCCEEDED(hr))
  3297. {
  3298. CComVariant var;
  3299. hr = spIADs->Get(CComBSTR(L"schemaNamingContext"), &var);
  3300. if (SUCCEEDED(hr))
  3301. {
  3302. m_szSchemaNamingContext = var.bstrVal;
  3303. }
  3304. }
  3305. m_szSchemaNamingContext = m_szPrefix + m_szSchemaNamingContext;
  3306. return hr;
  3307. }
  3308. BOOL CAttributeEditorPropertyPage::OnApply()
  3309. {
  3310. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  3311. CThemeContextActivator activator;
  3312. if (m_AttrList.HasDirty())
  3313. {
  3314. CComPtr<IDirectoryObject> spDirObject;
  3315. // bind to object with authentication
  3316. //
  3317. HRESULT hr = S_OK;
  3318. hr = m_spIADs->QueryInterface(IID_IDirectoryObject, (PVOID*) &spDirObject);
  3319. if (FAILED(hr))
  3320. {
  3321. AfxMessageBox(L"Failed to QI the IDirectoryObject from the IADs.");
  3322. return FALSE;
  3323. }
  3324. // Change or add values to ADSI cache that have changed
  3325. //
  3326. hr = CADSIAttribute::SetValuesInDS(&m_AttrList, spDirObject);
  3327. if (FAILED(hr))
  3328. {
  3329. ADSIEditErrorMessage(hr);
  3330. //
  3331. // Instead of removing all the attributes we need to query for the ones that failed
  3332. // or something to that effect.
  3333. //
  3334. // m_AttrList.RemoveAllAttr();
  3335. return FALSE;
  3336. }
  3337. }
  3338. return TRUE;
  3339. }
  3340. void CAttributeEditorPropertyPage::OnMandatoryCheck()
  3341. {
  3342. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  3343. TRACE(_T("OnMandatoryCheck()\n"));
  3344. m_bMandatory = ((CButton*)GetDlgItem(IDC_MANDATORY_CHECK))->GetCheck();
  3345. FillListControl();
  3346. }
  3347. void CAttributeEditorPropertyPage::OnOptionalCheck()
  3348. {
  3349. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  3350. TRACE(_T("OnOptionalCheck()\n"));
  3351. m_bOptional = ((CButton*)GetDlgItem(IDC_OPTIONAL_CHECK))->GetCheck();
  3352. FillListControl();
  3353. }
  3354. void CAttributeEditorPropertyPage::OnValueSetCheck()
  3355. {
  3356. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  3357. TRACE(_T("OnValueSetCheck()\n"));
  3358. m_bSet = ((CButton*)GetDlgItem(IDC_SET_CHECK))->GetCheck();
  3359. FillListControl();
  3360. }
  3361. //
  3362. // Callback function used by CListCtrl::SortItems the items by the column that was clicked
  3363. //
  3364. static int CALLBACK CompareAttrColumns(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
  3365. {
  3366. CAttributeEditorPropertyPage* pProppage = reinterpret_cast<CAttributeEditorPropertyPage*>(lParamSort);
  3367. if (!pProppage)
  3368. {
  3369. ASSERT(pProppage);
  3370. return 0;
  3371. }
  3372. UINT nColumn = pProppage->GetSortColumn();
  3373. CListCtrl* pListCtrl = (CListCtrl*)pProppage->GetDlgItem(IDC_ATTRIBUTE_LIST);
  3374. if (!pListCtrl)
  3375. {
  3376. ASSERT(pListCtrl);
  3377. return 0;
  3378. }
  3379. //
  3380. // Since lParam1 and lParam2 are pointers to the data we have to search for each item
  3381. // in the list and remember their index
  3382. //
  3383. int iItem1 = -1;
  3384. int iItem2 = -1;
  3385. LVFINDINFO findInfo;
  3386. ZeroMemory(&findInfo, sizeof(LVFINDINFO));
  3387. findInfo.flags = LVFI_PARAM;
  3388. findInfo.lParam = lParam1;
  3389. iItem1 = pListCtrl->FindItem(&findInfo);
  3390. findInfo.lParam = lParam2;
  3391. iItem2 = pListCtrl->FindItem(&findInfo);
  3392. //
  3393. // Put any items with values above those that don't have values
  3394. //
  3395. int iRetVal = 0;
  3396. if (iItem1 != -1 &&
  3397. iItem2 == -1)
  3398. {
  3399. iRetVal = -1;
  3400. }
  3401. else if (iItem1 == -1 &&
  3402. iItem2 != -1)
  3403. {
  3404. iRetVal = 1;
  3405. }
  3406. else if (iItem1 == -1 &&
  3407. iItem2 == -1)
  3408. {
  3409. iRetVal = 0;
  3410. }
  3411. else
  3412. {
  3413. CString szItem1 = pListCtrl->GetItemText(iItem1, nColumn);
  3414. CString szItem2 = pListCtrl->GetItemText(iItem2, nColumn);
  3415. //
  3416. // Have to put this in so that empty strings end up at the bottom
  3417. //
  3418. if (szItem1.IsEmpty() && !szItem2.IsEmpty())
  3419. {
  3420. iRetVal = 1;
  3421. }
  3422. else if (!szItem1.IsEmpty() && szItem2.IsEmpty())
  3423. {
  3424. iRetVal = -1;
  3425. }
  3426. else
  3427. {
  3428. // NOTICE-2002/03/05-artm _wcsicmp() okay since comparing 2 CStrings.
  3429. iRetVal = _wcsicmp(szItem1, szItem2);
  3430. }
  3431. }
  3432. return iRetVal;
  3433. }
  3434. void CAttributeEditorPropertyPage::OnSortList(NMHDR* pNotifyStruct, LRESULT* result)
  3435. {
  3436. if (!result ||
  3437. !pNotifyStruct)
  3438. {
  3439. return;
  3440. }
  3441. *result = 0;
  3442. //
  3443. // Get the list view notify struct
  3444. //
  3445. LPNMLISTVIEW pnmv = (LPNMLISTVIEW)pNotifyStruct;
  3446. if (!pnmv)
  3447. {
  3448. return;
  3449. }
  3450. //
  3451. // Right now I only have 3 columns
  3452. //
  3453. if (pnmv->iSubItem < 0 ||
  3454. pnmv->iSubItem >= 3)
  3455. {
  3456. return;
  3457. }
  3458. //
  3459. // Store the sort column
  3460. //
  3461. m_nSortColumn = pnmv->iSubItem;
  3462. CListCtrl* pAttrListCtrl = (CListCtrl*)GetDlgItem(IDC_ATTRIBUTE_LIST);
  3463. ASSERT(pAttrListCtrl);
  3464. pAttrListCtrl->SortItems(CompareAttrColumns, reinterpret_cast<LPARAM>(this));
  3465. }
  3466. void CAttributeEditorPropertyPage::OnListItemChanged(NMHDR* /*pNotifyStruct*/, LRESULT* result)
  3467. {
  3468. if (!result)
  3469. {
  3470. return;
  3471. }
  3472. *result = 0;
  3473. SetEditButton();
  3474. }
  3475. void CAttributeEditorPropertyPage::SetEditButton()
  3476. {
  3477. //
  3478. // Enable the edit button if something is selected in the ListCtrl
  3479. //
  3480. BOOL bEnableEdit = FALSE;
  3481. CListCtrl* pAttrListCtrl = (CListCtrl*)GetDlgItem(IDC_ATTRIBUTE_LIST);
  3482. ASSERT(pAttrListCtrl != NULL);
  3483. int nSelectedItem = pAttrListCtrl->GetNextItem(-1, LVIS_SELECTED);
  3484. if (nSelectedItem != -1 &&
  3485. !(m_dwBindFlags & DSATTR_EDITOR_ROOTDSE))
  3486. {
  3487. bEnableEdit = TRUE;
  3488. }
  3489. GetDlgItem(IDC_ATTR_EDIT_BUTTON)->EnableWindow(bEnableEdit);
  3490. }
  3491. void CAttributeEditorPropertyPage::OnNotifyEditAttribute(NMHDR* pNotifyStruct, LRESULT* result)
  3492. {
  3493. if (result == NULL ||
  3494. pNotifyStruct == NULL)
  3495. {
  3496. return;
  3497. }
  3498. // No editing values on RootDSE (for now)
  3499. if (m_dwBindFlags & DSATTR_EDITOR_ROOTDSE)
  3500. {
  3501. return;
  3502. }
  3503. LPNMITEMACTIVATE pnmia = (LPNMITEMACTIVATE)pNotifyStruct;
  3504. ASSERT(pnmia != NULL);
  3505. if (pnmia != NULL)
  3506. {
  3507. int iSelectedItem = pnmia->iItem;
  3508. if (iSelectedItem != -1)
  3509. {
  3510. CADSIAttribute* pSelectedAttr = GetAttributeFromList(iSelectedItem);
  3511. if (pSelectedAttr != NULL)
  3512. {
  3513. EditAttribute(pSelectedAttr);
  3514. }
  3515. else
  3516. {
  3517. //
  3518. // REVIEW_JEFFJON : display an appropriate error message
  3519. //
  3520. }
  3521. }
  3522. }
  3523. *result = 0;
  3524. }
  3525. void CAttributeEditorPropertyPage::OnEditAttribute()
  3526. {
  3527. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  3528. TRACE(_T("OnEditAttribute()\n"));
  3529. CListCtrl* pAttrListCtrl = (CListCtrl*)GetDlgItem(IDC_ATTRIBUTE_LIST);
  3530. ASSERT(pAttrListCtrl != NULL);
  3531. int nSelectedItem = pAttrListCtrl->GetNextItem(-1, LVIS_SELECTED);
  3532. if (nSelectedItem == -1)
  3533. {
  3534. return;
  3535. }
  3536. CADSIAttribute* pSelectedAttr = GetAttributeFromList(nSelectedItem);
  3537. ASSERT(pSelectedAttr != NULL);
  3538. if (m_dwBindFlags & DSATTR_EDITOR_ROOTDSE)
  3539. {
  3540. // We have add the value to the attribute holder from
  3541. // the RootDSE list
  3542. // CString szValue;
  3543. // szValue = m_RootDSEValueList.GetAt(m_RootDSEValueList.FindIndex(nSelectedItem));
  3544. }
  3545. EditAttribute(pSelectedAttr);
  3546. }
  3547. void CAttributeEditorPropertyPage::EditAttribute(CADSIAttribute* pSelectedAttr)
  3548. {
  3549. HRESULT hr = S_OK;
  3550. CThemeContextActivator activator;
  3551. //
  3552. // Retrieve all necessary info for initializing the appropriate editor
  3553. //
  3554. LPDS_ATTRIBUTE_EDITORINFO pAttributeEditorInfo = NULL;
  3555. BOOL bOwnValueMemory = FALSE;
  3556. hr = GetAttributeInfo(*pSelectedAttr, &pAttributeEditorInfo, &bOwnValueMemory);
  3557. if (hr == E_OUTOFMEMORY)
  3558. {
  3559. ADSIEditErrorMessage(hr);
  3560. return;
  3561. }
  3562. if (pAttributeEditorInfo == NULL || FAILED(hr))
  3563. {
  3564. ADSIEditMessageBox(IDS_NO_ATTRIBUTE_INFO, MB_OK);
  3565. return;
  3566. }
  3567. //
  3568. // Obtain the editor from the attribute and syntax map
  3569. //
  3570. CValueEditDialog* pEditorDialog = RetrieveEditor(pAttributeEditorInfo);
  3571. if (pEditorDialog)
  3572. {
  3573. hr = pEditorDialog->Initialize(pAttributeEditorInfo);
  3574. if (SUCCEEDED(hr))
  3575. {
  3576. if (pEditorDialog->DoModal() == IDOK)
  3577. {
  3578. PADSVALUE pNewValue = 0;
  3579. DWORD dwNumValues = 0;
  3580. hr = pEditorDialog->GetNewValue(&pNewValue, &dwNumValues);
  3581. if (SUCCEEDED(hr))
  3582. {
  3583. //
  3584. // Do what ever needs done with the new value
  3585. //
  3586. hr = pSelectedAttr->SetValues(pNewValue, dwNumValues);
  3587. //
  3588. // REVIEW_JEFFJON : what should be done here if that failed?
  3589. //
  3590. pSelectedAttr->SetDirty(TRUE);
  3591. CListCtrl* pAttrListCtrl = (CListCtrl*)GetDlgItem(IDC_ATTRIBUTE_LIST);
  3592. ASSERT(pAttrListCtrl != NULL);
  3593. int nSelectedItem = pAttrListCtrl->GetNextItem(-1, LVIS_SELECTED);
  3594. if (nSelectedItem != -1)
  3595. {
  3596. if (dwNumValues > 0)
  3597. {
  3598. //
  3599. // Get the new values (limit each individual value to MAX_OCTET_STRING_VALUE_LENGTH characters)
  3600. //
  3601. CStringList szValuesList;
  3602. pSelectedAttr->GetValues(szValuesList, MAX_OCTET_STRING_VALUE_LENGTH);
  3603. CString szCombinedString;
  3604. POSITION pos = szValuesList.GetHeadPosition();
  3605. while (pos != NULL)
  3606. {
  3607. CString szTemp = szValuesList.GetNext(pos);
  3608. szCombinedString += szTemp;
  3609. if (pos != NULL)
  3610. {
  3611. szCombinedString += L";";
  3612. }
  3613. }
  3614. VERIFY(-1 != pAttrListCtrl->SetItemText(nSelectedItem, 2, szCombinedString));
  3615. }
  3616. else
  3617. {
  3618. CString szNotSet;
  3619. VERIFY(szNotSet.LoadString(IDS_ATTR_NOTSET));
  3620. VERIFY(-1 != pAttrListCtrl->SetItemText(nSelectedItem, 2, szNotSet));
  3621. }
  3622. }
  3623. SetModified();
  3624. }
  3625. else
  3626. {
  3627. //
  3628. // REVIEW_JEFFJON : handle the GetNewValue() failure
  3629. //
  3630. ASSERT(FALSE);
  3631. ADSIEditErrorMessage(hr);
  3632. }
  3633. }
  3634. }
  3635. else
  3636. {
  3637. //
  3638. // REVIEW_JEFFJON : Handle the error Initialize
  3639. //
  3640. ASSERT(FALSE);
  3641. ADSIEditErrorMessage(hr);
  3642. }
  3643. if (pEditorDialog)
  3644. {
  3645. delete pEditorDialog;
  3646. pEditorDialog = 0;
  3647. }
  3648. }
  3649. else
  3650. {
  3651. //
  3652. // Unable to retrieve an appropriate editor for this attribute
  3653. //
  3654. ADSIEditMessageBox(IDS_NO_EDITOR, MB_OK);
  3655. }
  3656. if (pAttributeEditorInfo)
  3657. {
  3658. if (pAttributeEditorInfo->lpszAttribute)
  3659. {
  3660. delete[] pAttributeEditorInfo->lpszAttribute;
  3661. }
  3662. if (pAttributeEditorInfo->lpszClass)
  3663. {
  3664. delete[] pAttributeEditorInfo->lpszClass;
  3665. }
  3666. if (pAttributeEditorInfo->pADsValue && bOwnValueMemory)
  3667. {
  3668. delete pAttributeEditorInfo->pADsValue;
  3669. pAttributeEditorInfo->pADsValue = 0;
  3670. }
  3671. delete pAttributeEditorInfo;
  3672. pAttributeEditorInfo = 0;
  3673. }
  3674. }
  3675. CADSIAttribute* CAttributeEditorPropertyPage::GetAttributeFromList(int iSelectedItem)
  3676. {
  3677. if (iSelectedItem == -1)
  3678. {
  3679. return NULL;
  3680. }
  3681. CListCtrl* pAttrListCtrl = (CListCtrl*)GetDlgItem(IDC_ATTRIBUTE_LIST);
  3682. ASSERT(pAttrListCtrl != NULL);
  3683. return (CADSIAttribute*)pAttrListCtrl->GetItemData(iSelectedItem);
  3684. }
  3685. HRESULT CAttributeEditorPropertyPage::GetAttributeInfo(CADSIAttribute& attr,
  3686. LPDS_ATTRIBUTE_EDITORINFO* ppAttributeEditorInfo,
  3687. BOOL* pbOwnValueMemory)
  3688. {
  3689. HRESULT err = S_OK;
  3690. ASSERT(ppAttributeEditorInfo != NULL);
  3691. ASSERT(pbOwnValueMemory != NULL);
  3692. if (!ppAttributeEditorInfo || !pbOwnValueMemory)
  3693. {
  3694. return E_POINTER;
  3695. }
  3696. // Temporary variable to hold values that will be passed out of
  3697. // function. We use this instead of *ppAttributeEditorInfo to remove
  3698. // a level of indirection while we are collecting the information.
  3699. LPDS_ATTRIBUTE_EDITORINFO attributeEditorInfo;
  3700. // Set initial default (error) values.
  3701. attributeEditorInfo = NULL;
  3702. *pbOwnValueMemory = FALSE;
  3703. //
  3704. // Set read-only if necessary
  3705. //
  3706. bool readOnly = false;
  3707. if ( m_dwBindFlags & DSATTR_EDITOR_ROOTDSE
  3708. || m_dwBindFlags & DSATTR_EDITOR_GC)
  3709. {
  3710. readOnly = true;
  3711. }
  3712. //
  3713. // Get the attribute to be edited
  3714. //
  3715. CString szAttribute = _T("");
  3716. attr.GetProperty(szAttribute);
  3717. //
  3718. // Get the type and whether it is multi-valued or not by the syntax
  3719. // of the attribute
  3720. //
  3721. CString szSyntax;
  3722. BOOL bMultiValued = FALSE;
  3723. ADSTYPE adsType = RetrieveADsTypeFromSyntax(szAttribute, &bMultiValued, szSyntax);
  3724. DWORD dwNumValues = 0;
  3725. PADSVALUE pADsValue = attr.GetADsValues();
  3726. if (!pADsValue)
  3727. {
  3728. //
  3729. // Value for attribute was not set so we have to
  3730. // create an empty ADSVALUE to pass the type
  3731. //
  3732. pADsValue = new ADSVALUE;
  3733. if (pADsValue)
  3734. {
  3735. ::ZeroMemory(pADsValue, sizeof(ADSVALUE));
  3736. pADsValue->dwType = adsType;
  3737. dwNumValues = 0;
  3738. *pbOwnValueMemory = TRUE;
  3739. }
  3740. else
  3741. {
  3742. return E_OUTOFMEMORY;
  3743. }
  3744. }
  3745. else
  3746. {
  3747. //
  3748. // Get the number of values in the attribute
  3749. //
  3750. dwNumValues = attr.GetNumValues();
  3751. }
  3752. //
  3753. // Figure out how much space we need
  3754. //
  3755. DWORD dwStructSize = sizeof(DS_ATTRIBUTE_EDITORINFO);
  3756. DWORD dwClassSize = m_szClass.GetLength() + 1;
  3757. DWORD dwAttrSize = szAttribute.GetLength() + 1;
  3758. do // false loop
  3759. {
  3760. attributeEditorInfo = new DS_ATTRIBUTE_EDITORINFO;
  3761. if (!attributeEditorInfo)
  3762. {
  3763. err = E_OUTOFMEMORY;
  3764. break;
  3765. }
  3766. ::ZeroMemory(attributeEditorInfo, sizeof(DS_ATTRIBUTE_EDITORINFO));
  3767. // NOTICE-NTRAID#NTBUG9-566199-2002/03/05-artm Check mem. alloc. succeeded.
  3768. attributeEditorInfo->lpszClass = new WCHAR[dwClassSize];
  3769. if (!attributeEditorInfo->lpszClass)
  3770. {
  3771. err = E_OUTOFMEMORY;
  3772. break;
  3773. }
  3774. wcscpy(attributeEditorInfo->lpszClass, m_szClass);
  3775. // NOTICE-NTRAID#NTBUG9-566199-2002/03/05-artm Check mem. alloc. succeeded.
  3776. attributeEditorInfo->lpszAttribute = new WCHAR[dwAttrSize];
  3777. if (!attributeEditorInfo->lpszAttribute)
  3778. {
  3779. err = E_OUTOFMEMORY;
  3780. break;
  3781. }
  3782. wcscpy(attributeEditorInfo->lpszAttribute, szAttribute);
  3783. attributeEditorInfo->adsType = adsType;
  3784. attributeEditorInfo->bMultivalued = bMultiValued;
  3785. attributeEditorInfo->bReadOnly = readOnly;
  3786. attributeEditorInfo->dwNumValues = dwNumValues;
  3787. attributeEditorInfo->pADsValue = pADsValue;
  3788. attributeEditorInfo->dwSize = sizeof(DS_ATTRIBUTE_EDITORINFO);
  3789. }
  3790. while (false); // end false loop
  3791. // If we were unable to get all the information, clean up memory.
  3792. if (FAILED(err))
  3793. {
  3794. // Only delete the value structure if we allocated it.
  3795. if (*pbOwnValueMemory)
  3796. {
  3797. delete pADsValue;
  3798. pADsValue = NULL;
  3799. *pbOwnValueMemory = FALSE;
  3800. }
  3801. if (attributeEditorInfo)
  3802. {
  3803. if (attributeEditorInfo->lpszClass)
  3804. {
  3805. delete [] attributeEditorInfo->lpszClass;
  3806. }
  3807. if (attributeEditorInfo->lpszAttribute)
  3808. {
  3809. delete [] attributeEditorInfo->lpszAttribute;
  3810. }
  3811. delete attributeEditorInfo;
  3812. attributeEditorInfo = NULL;
  3813. }
  3814. }
  3815. *ppAttributeEditorInfo = attributeEditorInfo;
  3816. return err;
  3817. }
  3818. void CAttributeEditorPropertyPage::ShowListCtrl()
  3819. {
  3820. CListCtrl* pAttrListCtrl = (CListCtrl*)GetDlgItem(IDC_ATTRIBUTE_LIST);
  3821. ASSERT(pAttrListCtrl != NULL);
  3822. // Set full row select
  3823. ListView_SetExtendedListViewStyle(
  3824. pAttrListCtrl->GetSafeHwnd(),
  3825. LVS_EX_FULLROWSELECT);
  3826. //
  3827. // Insert the Attribute column
  3828. //
  3829. CString szAttribute;
  3830. VERIFY(szAttribute.LoadString(IDS_ATTR_COL_ATTRIBUTE));
  3831. int iRet = pAttrListCtrl->InsertColumn(0, szAttribute, LVCFMT_LEFT, 120);
  3832. if (iRet == -1)
  3833. {
  3834. TRACE(_T("Failed to insert the \"Attribute\" column.\n"));
  3835. }
  3836. //
  3837. // Insert the Syntax column
  3838. // This column will be hidden by default
  3839. //
  3840. CString szSyntax;
  3841. VERIFY(szSyntax.LoadString(IDS_ATTR_COL_SYNTAX));
  3842. iRet = pAttrListCtrl->InsertColumn(1, szSyntax, LVCFMT_LEFT, 90);
  3843. if (iRet == -1)
  3844. {
  3845. TRACE(_T("Failed to insert the \"Syntax\" column.\n"));
  3846. }
  3847. //
  3848. // Insert the Value column
  3849. //
  3850. CString szValue;
  3851. VERIFY(szValue.LoadString(IDS_ATTR_COL_VALUE));
  3852. iRet = pAttrListCtrl->InsertColumn(2, szValue, LVCFMT_LEFT, 400);
  3853. if (iRet == -1)
  3854. {
  3855. TRACE(_T("Failed to insert the \"Value\" column.\n"));
  3856. }
  3857. }
  3858. void CAttributeEditorPropertyPage::FillListControl()
  3859. {
  3860. TRACE(_T("FillListControl()\n"));
  3861. CListCtrl* pAttrListCtrl = (CListCtrl*)GetDlgItem(IDC_ATTRIBUTE_LIST);
  3862. ASSERT(pAttrListCtrl != NULL);
  3863. CString szNotSet;
  3864. VERIFY(szNotSet.LoadString(IDS_ATTR_NOTSET));
  3865. //
  3866. // Clear the list control
  3867. //
  3868. pAttrListCtrl->DeleteAllItems();
  3869. //
  3870. // Add the attributes and their values into the list control
  3871. //
  3872. UINT nState = 0;
  3873. int nIndex = 0;
  3874. POSITION pos = m_AttrList.GetHeadPosition();
  3875. while (pos != NULL)
  3876. {
  3877. CADSIAttribute* pAttr = m_AttrList.GetNext(pos);
  3878. ASSERT(pAttr != NULL);
  3879. CString szProperty;
  3880. pAttr->GetProperty(szProperty);
  3881. //
  3882. // Don't add the nTSecurityDescriptor, we use the ACL UI instead
  3883. //
  3884. if (szProperty.CompareNoCase(L"nTSecurityDescriptor") == 0)
  3885. {
  3886. continue;
  3887. }
  3888. if (m_dwBindFlags & DSATTR_EDITOR_ROOTDSE)
  3889. {
  3890. int iNewIndex = pAttrListCtrl->InsertItem(LVIF_TEXT | LVIF_PARAM, nIndex,
  3891. szProperty, nState, 0, 0, (LPARAM)pAttr);
  3892. if (iNewIndex != -1)
  3893. {
  3894. // Insert the syntax
  3895. VERIFY(-1 != pAttrListCtrl->SetItemText(iNewIndex, 1, pAttr->GetSyntax()));
  3896. // Insert the value
  3897. CString szValue;
  3898. szValue = m_RootDSEValueList.GetAt(m_RootDSEValueList.FindIndex(nIndex));
  3899. if (!szValue.IsEmpty())
  3900. {
  3901. VERIFY(-1 != pAttrListCtrl->SetItemText(iNewIndex, 2, szValue));
  3902. }
  3903. else
  3904. {
  3905. VERIFY(-1 != pAttrListCtrl->SetItemText(iNewIndex, 2, szNotSet));
  3906. }
  3907. }
  3908. nIndex++;
  3909. }
  3910. else // not RootDSE
  3911. {
  3912. if ((m_bMandatory && pAttr->IsMandatory()) || (m_bOptional && !pAttr->IsMandatory()))
  3913. {
  3914. if (!m_bSet || (m_bSet && pAttr->IsValueSet()))
  3915. {
  3916. int iNewIndex = pAttrListCtrl->InsertItem(LVIF_TEXT | LVIF_PARAM, nIndex,
  3917. szProperty, nState, 0, 0, (LPARAM)pAttr);
  3918. if (iNewIndex != -1)
  3919. {
  3920. // Insert the syntax
  3921. VERIFY(-1 != pAttrListCtrl->SetItemText(iNewIndex, 1, pAttr->GetSyntax()));
  3922. // Insert the value
  3923. if (pAttr->IsValueSet())
  3924. {
  3925. //
  3926. // Retrieve the values
  3927. //
  3928. CStringList szValuesList;
  3929. pAttr->GetValues(szValuesList);
  3930. CString szCombinedString;
  3931. POSITION posList = szValuesList.GetHeadPosition();
  3932. while (posList)
  3933. {
  3934. CString szTemp = szValuesList.GetNext(posList);
  3935. szCombinedString += szTemp;
  3936. if (posList)
  3937. {
  3938. szCombinedString += L";";
  3939. }
  3940. }
  3941. VERIFY(-1 != pAttrListCtrl->SetItemText(iNewIndex, 2, szCombinedString));
  3942. }
  3943. else
  3944. {
  3945. VERIFY(-1 != pAttrListCtrl->SetItemText(iNewIndex, 2, szNotSet));
  3946. }
  3947. }
  3948. nIndex++;
  3949. }
  3950. }
  3951. }
  3952. }
  3953. TRACE(_T("Added %u properties\n"), nIndex);
  3954. //
  3955. // Select the first attribute in the list
  3956. //
  3957. pAttrListCtrl->SetItemState(0, 1, LVIS_SELECTED);
  3958. SetEditButton();
  3959. }
  3960. HRESULT CAttributeEditorPropertyPage::RetrieveAttributes()
  3961. {
  3962. TRACE(_T("RetrieveAttributes()\n"));
  3963. HRESULT hr = S_OK;
  3964. CWaitCursor cursor;
  3965. if (m_dwBindFlags & DSATTR_EDITOR_ROOTDSE)
  3966. {
  3967. CStringList sMandList;
  3968. m_spIADs->GetInfo();
  3969. CComPtr<IADsPropertyList> spPropList;
  3970. hr = m_spIADs->QueryInterface(IID_IADsPropertyList, (PVOID*)&spPropList);
  3971. if (SUCCEEDED(hr))
  3972. {
  3973. LONG lCount = 0;
  3974. hr = spPropList->get_PropertyCount(&lCount);
  3975. if (SUCCEEDED(hr) && lCount > 0)
  3976. {
  3977. CComVariant var;
  3978. while (hr == S_OK)
  3979. {
  3980. hr = spPropList->Next(&var);
  3981. if (hr == S_OK)
  3982. {
  3983. ASSERT(var.vt == VT_DISPATCH);
  3984. CComPtr<IADsPropertyEntry> spEntry;
  3985. hr = V_DISPATCH(&var)->QueryInterface(IID_IADsPropertyEntry,
  3986. (PVOID*)&spEntry);
  3987. if (SUCCEEDED(hr))
  3988. {
  3989. CComBSTR bstrName;
  3990. hr = spEntry->get_Name(&bstrName);
  3991. if (SUCCEEDED(hr))
  3992. {
  3993. sMandList.AddTail(bstrName);
  3994. }
  3995. }
  3996. }
  3997. }
  3998. }
  3999. }
  4000. hr = CreateAttributeList(sMandList, TRUE);
  4001. }
  4002. else
  4003. {
  4004. //
  4005. // Retrieve mandatory properties
  4006. //
  4007. CStringList sMandList;
  4008. VARIANT varMand;
  4009. VariantInit(&varMand);
  4010. hr = m_spIADsClass->get_MandatoryProperties(&varMand);
  4011. if (SUCCEEDED(hr))
  4012. {
  4013. VariantToStringList( varMand, sMandList );
  4014. }
  4015. VariantClear(&varMand);
  4016. //
  4017. // Retrieve optional properties
  4018. //
  4019. CStringList sOptionalList;
  4020. VARIANT varOpt;
  4021. VariantInit(&varOpt);
  4022. hr = m_spIADsClass->get_OptionalProperties(&varOpt);
  4023. if (SUCCEEDED(hr))
  4024. {
  4025. VariantToStringList( varOpt, sOptionalList );
  4026. }
  4027. VariantClear(&varOpt);
  4028. hr = CreateAttributeList(sMandList, TRUE);
  4029. if (FAILED(hr))
  4030. {
  4031. return hr;
  4032. }
  4033. hr = CreateAttributeList(sOptionalList, FALSE);
  4034. if (FAILED(hr))
  4035. {
  4036. return hr;
  4037. }
  4038. }
  4039. return hr;
  4040. }
  4041. // The function checks to see if the pszAttrName contains ";range="
  4042. // If it does that means the attribute contains a range of values.
  4043. // We will return the attribute name (without the range), and the start
  4044. // and end of the range.
  4045. bool CAttributeEditorPropertyPage::IsRangeOfValues(PCWSTR pszAttrName,
  4046. CString& szAttrBase,
  4047. DWORD& rangeStart,
  4048. DWORD& rangeEnd)
  4049. {
  4050. bool result = false;
  4051. CString szAttrName = pszAttrName;
  4052. int iFind = szAttrName.Find(L";range=");
  4053. if (iFind != -1)
  4054. {
  4055. // This is a range, get the start and end
  4056. result = true;
  4057. szAttrBase = szAttrName.Left(iFind);
  4058. int length = szAttrName.GetLength();
  4059. // The range start is the value between the = and -
  4060. iFind = szAttrName.ReverseFind(L'=');
  4061. if (iFind != -1)
  4062. {
  4063. CString szStart = szAttrName.Right(length - iFind - 1);
  4064. long start = _wtol(szStart);
  4065. rangeStart = static_cast<DWORD>(start);
  4066. }
  4067. // The range end is the last value after the -.
  4068. // This could be * so a return value of 0 for this
  4069. // means we have the entire range
  4070. iFind = szAttrName.ReverseFind(L'-');
  4071. if (iFind != -1)
  4072. {
  4073. CString szEnd = szAttrName.Right(length - iFind - 1);
  4074. long end = _wtol(szEnd);
  4075. rangeEnd = static_cast<DWORD>(end);
  4076. }
  4077. }
  4078. return result;
  4079. }
  4080. HRESULT CAttributeEditorPropertyPage::CreateAttributeList(CStringList& sAttrList, BOOL bMandatory)
  4081. {
  4082. HRESULT hr = S_OK;
  4083. LPWSTR* lpszAttrArray;
  4084. UINT nCount = 0;
  4085. GetStringArrayFromStringList(sAttrList, &lpszAttrArray, &nCount);
  4086. TRACE(_T("There are %u properties to add\n"), nCount);
  4087. for (UINT idx = 0; idx < nCount; idx++)
  4088. {
  4089. CADSIAttribute* pNewAttr = new CADSIAttribute(lpszAttrArray[idx]);
  4090. ASSERT(pNewAttr != NULL);
  4091. pNewAttr->SetMandatory(bMandatory);
  4092. // Get the syntax
  4093. BOOL bMultivalued = FALSE;
  4094. CString szSyntax;
  4095. ADSTYPE adstype = RetrieveADsTypeFromSyntax(lpszAttrArray[idx], &bMultivalued, szSyntax);
  4096. pNewAttr->SetADsType(adstype);
  4097. pNewAttr->SetMultivalued(bMultivalued);
  4098. pNewAttr->SetSyntax(szSyntax);
  4099. m_AttrList.AddTail(pNewAttr);
  4100. }
  4101. //
  4102. // Retrieve the values that are set
  4103. //
  4104. #define RETRIEVESET
  4105. #ifdef RETRIEVESET
  4106. if (m_dwBindFlags & DSATTR_EDITOR_ROOTDSE)
  4107. {
  4108. //
  4109. // Special case RootDSE because it does not support IDirectoryObject
  4110. //
  4111. hr = m_spIADs->GetInfo();
  4112. for (UINT idx = 0; idx < nCount; idx++)
  4113. {
  4114. VARIANT var;
  4115. hr = m_spIADs->GetEx( CComBSTR(lpszAttrArray[idx]) , &var );
  4116. if ( FAILED(hr) )
  4117. {
  4118. m_RootDSEValueList.AddTail(L" ");
  4119. continue;
  4120. }
  4121. /////////////////////////////////////////
  4122. // Convert and populate
  4123. ///////////////////////////////////////////
  4124. CStringList sList;
  4125. hr = VariantToStringList( var, sList );
  4126. if (SUCCEEDED(hr))
  4127. {
  4128. CString szTempValue;
  4129. POSITION pos = sList.GetHeadPosition();
  4130. while (pos != NULL)
  4131. {
  4132. CString szValue = sList.GetNext(pos);
  4133. if (szTempValue.IsEmpty())
  4134. {
  4135. szTempValue += szValue;
  4136. }
  4137. else
  4138. {
  4139. szTempValue += L";" + szValue;
  4140. }
  4141. }
  4142. m_RootDSEValueList.AddTail(szTempValue);
  4143. }
  4144. }
  4145. }
  4146. else
  4147. {
  4148. CComPtr<IDirectoryObject> spDirObject;
  4149. hr = m_spIADs->QueryInterface(IID_IDirectoryObject, (PVOID*)&spDirObject);
  4150. if (FAILED(hr))
  4151. {
  4152. return hr;
  4153. }
  4154. PADS_ATTR_INFO pAttrInfo = NULL;
  4155. DWORD dwReturned = 0;
  4156. hr = spDirObject->GetObjectAttributes(lpszAttrArray, nCount, &pAttrInfo, &dwReturned);
  4157. if (SUCCEEDED(hr))
  4158. {
  4159. //
  4160. // Save the attribute info pointer for later deletion
  4161. //
  4162. if (bMandatory)
  4163. {
  4164. m_AttrList.SaveMandatoryValuesPointer(pAttrInfo);
  4165. }
  4166. else
  4167. {
  4168. m_AttrList.SaveOptionalValuesPointer(pAttrInfo);
  4169. }
  4170. for (DWORD idx = 0; idx < dwReturned; idx++)
  4171. {
  4172. POSITION pos = m_AttrList.FindProperty(pAttrInfo[idx].pszAttrName);
  4173. if (pos)
  4174. {
  4175. CADSIAttribute* pNewAttr = m_AttrList.GetAt(pos);
  4176. ASSERT(pNewAttr != NULL);
  4177. pNewAttr->SetValueSet(TRUE);
  4178. pNewAttr->SetAttrInfo(&(pAttrInfo[idx]));
  4179. }
  4180. else
  4181. {
  4182. // See if this is just a range of values for the attribute
  4183. CString szAttributeBase;
  4184. DWORD rangeStart = 0;
  4185. DWORD rangeEnd = static_cast<DWORD>(-1);
  4186. CADSIAttribute* pNewAttr = 0;
  4187. PADS_ATTR_INFO pCurrentInfo = &(pAttrInfo[idx]);
  4188. ASSERT(pCurrentInfo);
  4189. bool currentInMasterList = true;
  4190. // If we were sent only a portion of the values
  4191. // we have to loop through and get the rest
  4192. while (IsRangeOfValues(pCurrentInfo->pszAttrName,
  4193. szAttributeBase,
  4194. rangeStart,
  4195. rangeEnd))
  4196. {
  4197. if (!pNewAttr)
  4198. {
  4199. POSITION rangePos = m_AttrList.FindProperty(szAttributeBase);
  4200. if (rangePos)
  4201. {
  4202. pNewAttr = m_AttrList.GetAt(rangePos);
  4203. }
  4204. }
  4205. ASSERT(pNewAttr);
  4206. if (!pNewAttr)
  4207. {
  4208. break;
  4209. }
  4210. if (pNewAttr->IsValueSet())
  4211. {
  4212. hr = pNewAttr->AppendValues(pCurrentInfo->pADsValues,
  4213. pCurrentInfo->dwNumValues);
  4214. }
  4215. else
  4216. {
  4217. pNewAttr->SetValueSet(TRUE);
  4218. pNewAttr->SetAttrInfo(pCurrentInfo);
  4219. }
  4220. // If the current attribute info was not in the array
  4221. // of information from the initial request, release
  4222. // it here now that we are done with it.
  4223. if (!currentInMasterList)
  4224. {
  4225. ::FreeADsMem(pCurrentInfo);
  4226. pCurrentInfo = NULL;
  4227. }
  4228. if (rangeEnd == 0)
  4229. {
  4230. break;
  4231. }
  4232. // Request next batch of values for the attribute.
  4233. CString szNextAttribute = szAttributeBase;
  4234. CString szNextRange;
  4235. szNextRange.Format(L";range=%ld-*", rangeEnd);
  4236. szNextAttribute += szNextRange;
  4237. DWORD dwNextReturned = 0;
  4238. PWSTR pszAttrs = (PWSTR)(PCWSTR)szNextAttribute;
  4239. hr = spDirObject->GetObjectAttributes(&pszAttrs,
  4240. 1,
  4241. &pCurrentInfo,
  4242. &dwNextReturned);
  4243. if (FAILED(hr))
  4244. {
  4245. break;
  4246. }
  4247. if (dwNextReturned != 1 ||
  4248. !pCurrentInfo)
  4249. {
  4250. ASSERT(dwNextReturned == 1);
  4251. ASSERT(pCurrentInfo);
  4252. break;
  4253. }
  4254. // Since this pointer comes from an additional request to ADSI,
  4255. // we'll need to free it when we are done with it.
  4256. currentInMasterList = false;
  4257. rangeEnd = static_cast<DWORD>(-1);
  4258. }
  4259. }
  4260. }
  4261. TRACE(_T("Added %u properties to the list\nThe list has %u total properties\n"), dwReturned, m_AttrList.GetCount());
  4262. }
  4263. else
  4264. {
  4265. ADSIEditErrorMessage(hr, IDS_MSG_FAIL_LOAD_VALUES, MB_OK);
  4266. }
  4267. for (UINT nIndex = 0; nIndex < nCount; nIndex++)
  4268. {
  4269. delete lpszAttrArray[nIndex];
  4270. lpszAttrArray[nIndex] = NULL;
  4271. }
  4272. delete[] lpszAttrArray;
  4273. lpszAttrArray = NULL;
  4274. }
  4275. #endif //RETRIEVESET
  4276. return hr;
  4277. }
  4278. ATTR_EDITOR_MAP g_attrEditorMap[] = {
  4279. // Class, Attribute, ADSTYPE, Multivalued, Creation function
  4280. { NULL, NULL, ADSTYPE_DN_STRING, FALSE, CreateSingleStringEditor },
  4281. { NULL, NULL, ADSTYPE_DN_STRING, TRUE, CreateMultiStringEditor },
  4282. { NULL, NULL, ADSTYPE_CASE_IGNORE_STRING, FALSE, CreateSingleStringEditor },
  4283. { NULL, NULL, ADSTYPE_CASE_IGNORE_STRING, TRUE, CreateMultiStringEditor },
  4284. { NULL, NULL, ADSTYPE_CASE_EXACT_STRING, FALSE, CreateSingleStringEditor },
  4285. { NULL, NULL, ADSTYPE_CASE_EXACT_STRING, TRUE, CreateMultiStringEditor },
  4286. { NULL, NULL, ADSTYPE_PRINTABLE_STRING, FALSE, CreateSingleStringEditor },
  4287. { NULL, NULL, ADSTYPE_PRINTABLE_STRING, TRUE, CreateMultiStringEditor },
  4288. { NULL, NULL, ADSTYPE_NUMERIC_STRING, FALSE, CreateSingleStringEditor },
  4289. { NULL, NULL, ADSTYPE_NUMERIC_STRING, TRUE, CreateMultiStringEditor },
  4290. { NULL, NULL, ADSTYPE_OBJECT_CLASS, FALSE, CreateSingleStringEditor },
  4291. { NULL, NULL, ADSTYPE_OBJECT_CLASS, TRUE, CreateMultiStringEditor },
  4292. { NULL, NULL, ADSTYPE_INTEGER, FALSE, CreateSingleIntEditor },
  4293. { NULL, NULL, ADSTYPE_INTEGER, TRUE, CreateMultiIntEditor },
  4294. { NULL, NULL, ADSTYPE_LARGE_INTEGER, FALSE, CreateSingleLargeIntEditor },
  4295. { NULL, NULL, ADSTYPE_BOOLEAN, FALSE, CreateSingleBooleanEditor },
  4296. { NULL, NULL, ADSTYPE_BOOLEAN, TRUE, CreateMultiBooleanEditor },
  4297. { NULL, NULL, ADSTYPE_UTC_TIME, FALSE, CreateSingleTimeEditor },
  4298. { NULL, NULL, ADSTYPE_UTC_TIME, TRUE, CreateMultiTimeEditor },
  4299. { NULL, NULL, ADSTYPE_TIMESTAMP, FALSE, CreateSingleTimeEditor },
  4300. { NULL, NULL, ADSTYPE_TIMESTAMP, TRUE, CreateMultiTimeEditor },
  4301. { NULL, NULL, ADSTYPE_OCTET_STRING, FALSE, CreateSingleOctetStringEditor },
  4302. { NULL, NULL, ADSTYPE_OCTET_STRING, TRUE, CreateMultiOctetStringEditor },
  4303. { NULL, NULL, ADSTYPE_DN_WITH_STRING, FALSE, CreateDNWithStringEditor },
  4304. };
  4305. size_t g_attrEditMapCount = sizeof(g_attrEditorMap)/sizeof(ATTR_EDITOR_MAP);
  4306. CValueEditDialog* CAttributeEditorPropertyPage::RetrieveEditor(LPDS_ATTRIBUTE_EDITORINFO pAttributeEditorInfo)
  4307. {
  4308. CValueEditDialog* pNewDialog = NULL;
  4309. if (pAttributeEditorInfo != NULL)
  4310. {
  4311. int iMultivalued = 0;
  4312. CString szSyntax;
  4313. ADSTYPE adsType = RetrieveADsTypeFromSyntax(pAttributeEditorInfo->lpszAttribute, &iMultivalued, szSyntax);
  4314. for (size_t idx = 0; idx < g_attrEditMapCount; idx++)
  4315. {
  4316. //
  4317. // REVIEW_JEFFJON : for now I am just looking at ADSTYPE and single/multivalued
  4318. //
  4319. if (g_attrEditorMap[idx].adsType == adsType &&
  4320. g_attrEditorMap[idx].bMultivalued == pAttributeEditorInfo->bMultivalued)
  4321. {
  4322. pNewDialog = g_attrEditorMap[idx].pfnCreateFunc(pAttributeEditorInfo->lpszClass,
  4323. pAttributeEditorInfo->lpszAttribute,
  4324. adsType,
  4325. pAttributeEditorInfo->bMultivalued);
  4326. break;
  4327. }
  4328. }
  4329. }
  4330. return pNewDialog;
  4331. }
  4332. ADSTYPE CAttributeEditorPropertyPage::RetrieveADsTypeFromSyntax(LPCWSTR lpszAttribute, BOOL* pbMulti, CString& szSyntax)
  4333. {
  4334. ADSTYPE adsType = ADSTYPE_INVALID;
  4335. if (!pbMulti ||
  4336. !lpszAttribute)
  4337. {
  4338. ASSERT(pbMulti);
  4339. ASSERT(lpszAttribute);
  4340. return adsType;
  4341. }
  4342. if (m_dwBindFlags & DSATTR_EDITOR_ROOTDSE)
  4343. {
  4344. int idx=0, iCount = 0;
  4345. // NTRAID#NTBUG9-563093-2002/03/05-artm If lpszAttribute not null terminated,
  4346. // this will blow up.
  4347. iCount = wcslen(lpszAttribute);
  4348. while( g_ldapRootDSESyntax[idx].lpszAttr)
  4349. {
  4350. // NOTICE-2002/03/05-artm _wcsnicmp() OK.
  4351. // arg1 is global var that should be null terminated;
  4352. // arg2 is null terminated or we wouldn't have gotten this far.
  4353. if ( _wcsnicmp(g_ldapRootDSESyntax[idx].lpszAttr, lpszAttribute, iCount) == 0)
  4354. {
  4355. *pbMulti = g_ldapRootDSESyntax[idx].bMulti;
  4356. szSyntax = g_ldapRootDSESyntax[idx].lpszSyntax;
  4357. break;
  4358. }
  4359. idx++;
  4360. }
  4361. adsType = GetADsTypeFromString(szSyntax, szSyntax);
  4362. }
  4363. else
  4364. {
  4365. CADSIQueryObject schemaSearch;
  4366. HRESULT hr = S_OK;
  4367. CComPtr<IDirectorySearch> spDirSearch;
  4368. CString schemaBindPath(m_szSchemaNamingContext);
  4369. if (m_dwBindFlags & DSATTR_EDITOR_GC)
  4370. {
  4371. // GC by default does not have 'attributeSyntax' or 'isSingleValued'
  4372. // in the partial attribute set. To ensure we can get these attributes,
  4373. // we'll bind with LDAP instead of GC. This is ok b/c we are searching
  4374. // the schema, which is the same on the GC and all DC's.
  4375. // NTRAID#NTBUG9-762158-2003/01/15-artm
  4376. int numReplaced = schemaBindPath.Replace(L"GC://", L"LDAP://");
  4377. if (numReplaced != 1)
  4378. {
  4379. ASSERT(numReplaced == 1);
  4380. // fall back to connecting to the GC, since the path wasn't
  4381. // adapted the way we expected
  4382. schemaBindPath = m_szSchemaNamingContext;
  4383. }
  4384. }
  4385. // REVIEW_JEFFJON : this needs to be replaced with proper binding calls
  4386. // REVIEW_JEFFJON : maybe this interface pointer should be retained for future use
  4387. hr = m_pfnBind(schemaBindPath,
  4388. ADS_SECURE_AUTHENTICATION,
  4389. IID_IDirectorySearch,
  4390. (PVOID*)&spDirSearch,
  4391. m_BindLPARAM);
  4392. if (FAILED(hr))
  4393. {
  4394. return ADSTYPE_INVALID;
  4395. }
  4396. //
  4397. // Initialize search object with IDirectorySearch
  4398. //
  4399. hr = schemaSearch.Init(spDirSearch);
  4400. if (FAILED(hr))
  4401. {
  4402. return ADSTYPE_INVALID;
  4403. }
  4404. int cCols = 2;
  4405. LPWSTR pszAttributes[] = {L"isSingleValued", L"attributeSyntax"};
  4406. ADS_SEARCH_COLUMN ColumnData;
  4407. hr = schemaSearch.SetSearchPrefs(ADS_SCOPE_ONELEVEL);
  4408. if (FAILED(hr))
  4409. {
  4410. return ADSTYPE_INVALID;
  4411. }
  4412. CString csFilter;
  4413. csFilter.Format(L"(&(objectClass=attributeSchema)(lDAPDisplayName=%s)(!isDefunct=TRUE))", lpszAttribute);
  4414. schemaSearch.SetFilterString((LPWSTR)(LPCWSTR)csFilter);
  4415. schemaSearch.SetAttributeList (pszAttributes, cCols);
  4416. hr = schemaSearch.DoQuery ();
  4417. if (SUCCEEDED(hr))
  4418. {
  4419. hr = schemaSearch.GetNextRow();
  4420. if (SUCCEEDED(hr))
  4421. {
  4422. hr = schemaSearch.GetColumn(pszAttributes[0], &ColumnData);
  4423. if (SUCCEEDED(hr))
  4424. {
  4425. TRACE(_T("\t\tisSingleValued: %d\n"),
  4426. ColumnData.pADsValues->Boolean);
  4427. *pbMulti = !ColumnData.pADsValues->Boolean;
  4428. schemaSearch.FreeColumn(&ColumnData);
  4429. }
  4430. hr = schemaSearch.GetColumn(pszAttributes[1], &ColumnData);
  4431. if (SUCCEEDED(hr))
  4432. {
  4433. TRACE(_T("\t\tattributeSyntax: %s\n"),
  4434. ColumnData.pADsValues->CaseIgnoreString);
  4435. adsType = GetADsTypeFromString(ColumnData.pADsValues->CaseIgnoreString, szSyntax);
  4436. schemaSearch.FreeColumn(&ColumnData);
  4437. }
  4438. }
  4439. }
  4440. }
  4441. return adsType;
  4442. }