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.

1624 lines
49 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // Windows NT Directory Service Property Pages
  4. //
  5. // Microsoft Windows
  6. // Copyright (C) Microsoft Corporation, 1992 - 1999
  7. //
  8. // File: proppage.cxx
  9. //
  10. // Contents: CDsPropPagesHost, the class that exposes IShellExtInit and
  11. // IShellPropSheetExt
  12. //
  13. // History: 24-March-97 EricB created
  14. //
  15. //-----------------------------------------------------------------------------
  16. #include "pch.h"
  17. #include "proppage.h"
  18. #include <propcfg.h>
  19. #include <pcrack.h>
  20. CLIPFORMAT g_cfDsObjectNames = 0;
  21. CLIPFORMAT g_cfDsDispSpecOptions = 0;
  22. CLIPFORMAT g_cfShellIDListArray = 0;
  23. CLIPFORMAT g_cfMMCGetNodeType = 0;
  24. CLIPFORMAT g_cfDsPropCfg = 0;
  25. CLIPFORMAT g_cfDsSelList = 0;
  26. CLIPFORMAT g_cfDsMultiSelectProppages = 0;
  27. //CLIPFORMAT g_cfMMCGetCoClass = 0;
  28. static void ToggleMVDefaultBtn(HWND hDlg, BOOL fOK);
  29. //+----------------------------------------------------------------------------
  30. //
  31. // Member: CDsPropPagesHost::CDsPropPagesHost
  32. //
  33. //-----------------------------------------------------------------------------
  34. CDsPropPagesHost::CDsPropPagesHost(PDSCLASSPAGES pDsPP) :
  35. m_pDsPPages(pDsPP),
  36. m_pDataObj(NULL),
  37. m_hNotifyObj(NULL),
  38. m_uRefs(1)
  39. {
  40. TRACE2(CDsPropPagesHost,CDsPropPagesHost);
  41. #ifdef _DEBUG
  42. strcpy(szClass, "CDsPropPagesHost");
  43. #endif
  44. m_ObjMedium.tymed = TYMED_NULL;
  45. m_ObjMedium.hGlobal = NULL;
  46. }
  47. //+----------------------------------------------------------------------------
  48. //
  49. // Member: CDsPropPagesHost::~CDsPropPagesHost
  50. //
  51. //-----------------------------------------------------------------------------
  52. CDsPropPagesHost::~CDsPropPagesHost()
  53. {
  54. TRACE(CDsPropPagesHost,~CDsPropPagesHost);
  55. if (m_pDataObj)
  56. {
  57. m_pDataObj->Release();
  58. }
  59. if (m_ObjMedium.tymed != TYMED_NULL)
  60. {
  61. ReleaseStgMedium(&m_ObjMedium);
  62. }
  63. }
  64. //+----------------------------------------------------------------------------
  65. //
  66. // Member: CDsPropPagesHost::IShellExtInit::Initialize
  67. //
  68. // Synopsis:
  69. //
  70. // Arguments:
  71. //
  72. // Returns: HRESULTS
  73. //
  74. //-----------------------------------------------------------------------------
  75. STDMETHODIMP
  76. CDsPropPagesHost::Initialize(LPCITEMIDLIST, LPDATAOBJECT pDataObj,
  77. HKEY)
  78. {
  79. TRACE2(CDsPropPagesHost,Initialize);
  80. if (IsBadReadPtr(pDataObj, sizeof(LPDATAOBJECT)))
  81. {
  82. DBG_OUT("Failed because we don't have a data object");
  83. return E_INVALIDARG;
  84. }
  85. if (m_pDataObj)
  86. {
  87. m_pDataObj->Release();
  88. m_pDataObj = NULL;
  89. }
  90. // Hang onto the IDataObject we are being passed.
  91. m_pDataObj = pDataObj;
  92. if (m_pDataObj)
  93. {
  94. m_pDataObj->AddRef();
  95. }
  96. else
  97. {
  98. return E_INVALIDARG;
  99. }
  100. return S_OK;
  101. }
  102. //+----------------------------------------------------------------------------
  103. //
  104. // Member: CDsPropPagesHost::IShellExtInit::AddPages
  105. //
  106. // Synopsis:
  107. //
  108. // Arguments:
  109. //
  110. // Returns: HRESULTS
  111. //
  112. //-----------------------------------------------------------------------------
  113. STDMETHODIMP
  114. CDsPropPagesHost::AddPages(LPFNADDPROPSHEETPAGE pAddPageProc, LPARAM lParam)
  115. {
  116. TRACE(CDsPropPagesHost,AddPages);
  117. CWaitCursor cWait;
  118. HRESULT hr = S_OK;
  119. HPROPSHEETPAGE hPage;
  120. PWSTR pwzObjADsPath, pwzClass;
  121. DWORD i;
  122. BOOL fPageCreated = FALSE;
  123. //
  124. // Get the unique identifier for the notify object from the data object
  125. //
  126. FORMATETC mfmte = {g_cfDsMultiSelectProppages, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  127. STGMEDIUM objMedium;
  128. LPWSTR lpszUniqueID = NULL;
  129. LPWSTR lpszTempUniqueID = NULL;
  130. hr = m_pDataObj->GetData(&mfmte, &objMedium);
  131. if (SUCCEEDED(hr))
  132. {
  133. lpszTempUniqueID = (LPWSTR)objMedium.hGlobal;
  134. if (lpszTempUniqueID == NULL)
  135. {
  136. DBG_OUT("Unique identifier not available for property pages.");
  137. ReleaseStgMedium(&objMedium);
  138. return ERROR_INVALID_DATA;
  139. }
  140. size_t iLength = wcslen(lpszTempUniqueID);
  141. lpszUniqueID = new WCHAR[iLength + 1];
  142. if (lpszUniqueID)
  143. {
  144. wcscpy(lpszUniqueID, lpszTempUniqueID);
  145. }
  146. ReleaseStgMedium(&objMedium);
  147. }
  148. //
  149. // Retrieve the DS object names
  150. //
  151. FORMATETC fmte = {g_cfDsObjectNames, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  152. LPDSOBJECTNAMES pDsObjectNames;
  153. //
  154. // Get the path to the DS object from the data object.
  155. // Note: This call runs on the caller's main thread. The pages' window
  156. // procs run on a different thread, so don't reference the data object
  157. // from a winproc unless it is first marshalled on this thread.
  158. //
  159. hr = m_pDataObj->GetData(&fmte, &m_ObjMedium);
  160. CHECK_HRESULT(hr, return hr);
  161. pDsObjectNames = (LPDSOBJECTNAMES)m_ObjMedium.hGlobal;
  162. if (pDsObjectNames->cItems < 1)
  163. {
  164. DBG_OUT("Not enough objects in DSOBJECTNAMES structure");
  165. return ERROR_INVALID_DATA;
  166. }
  167. pwzObjADsPath = (PWSTR)ByteOffset(pDsObjectNames,
  168. pDsObjectNames->aObjects[0].offsetName);
  169. pwzClass = (PWSTR)ByteOffset(pDsObjectNames,
  170. pDsObjectNames->aObjects[0].offsetClass);
  171. dspDebugOut((DEB_ITRACE, "Object name: %ws, Class: %ws\n", pwzObjADsPath,
  172. pwzClass));
  173. // Crack the name to get the server name and use that to create a
  174. // CDSBasePathsInfo that can be used by the pages
  175. CDSBasePathsInfo* pBasePathsInfo = new CDSBasePathsInfo;
  176. CHECK_NULL(pBasePathsInfo, return E_OUTOFMEMORY);
  177. CDSSmartBasePathsInfo basePathsInfo(pBasePathsInfo);
  178. CPathCracker pathCracker;
  179. hr = pathCracker.Set(CComBSTR(pwzObjADsPath), ADS_SETTYPE_FULL);
  180. if (SUCCEEDED(hr))
  181. {
  182. CComBSTR sbstrServer;
  183. hr = pathCracker.Retrieve(ADS_FORMAT_SERVER, &sbstrServer);
  184. if (SUCCEEDED(hr))
  185. {
  186. hr = basePathsInfo->InitFromName(sbstrServer);
  187. }
  188. else
  189. {
  190. // The shell calls the prop-page without a server in the path.
  191. //
  192. hr = basePathsInfo->InitFromName(NULL);
  193. }
  194. }
  195. if (FAILED(hr))
  196. {
  197. DBG_OUT("Failed to create/initialize the base paths info for the pages");
  198. return ERROR_INVALID_DATA;
  199. }
  200. //
  201. // Loop to see if any pages will be created.
  202. //
  203. for (i = 0; i < m_pDsPPages->cPages; i++)
  204. {
  205. PDSPAGE pDsPage = m_pDsPPages->rgpDsPages[i];
  206. if ((pDsPage->dwFlags & DSPROVIDER_ADVANCED) &&
  207. !(pDsObjectNames->aObjects[0].dwProviderFlags & DSPROVIDER_ADVANCED))
  208. {
  209. // The page should only be displayed if in advanced mode.
  210. //
  211. continue;
  212. }
  213. if (pDsPage->nCLSIDs)
  214. {
  215. // Only show the page if there is a match on the snapin (namespace)
  216. // CLSID.
  217. //
  218. BOOL fFound = FALSE;
  219. for (DWORD j = 0; j < pDsPage->nCLSIDs; j++)
  220. {
  221. if (IsEqualCLSID(pDsPage->rgCLSID[j],
  222. pDsObjectNames->clsidNamespace))
  223. {
  224. fFound = TRUE;
  225. }
  226. }
  227. if (!fFound)
  228. {
  229. continue;
  230. }
  231. }
  232. fPageCreated = TRUE;
  233. }
  234. if (fPageCreated)
  235. {
  236. //
  237. // At least one page will be created, so contact the notification
  238. // object. If it doesn't already exist, it will be created.
  239. //
  240. if (lpszUniqueID == NULL)
  241. {
  242. //
  243. // Copy the path to be used as the unique ID for the page
  244. // This should only be done if the DataObject does not support g_cfDsMultiSelectProppages
  245. //
  246. size_t iLength = wcslen(pwzObjADsPath);
  247. lpszUniqueID = new WCHAR[iLength + 1];
  248. if (lpszUniqueID)
  249. {
  250. wcscpy(lpszUniqueID, pwzObjADsPath);
  251. }
  252. }
  253. hr = ADsPropCreateNotifyObj(m_pDataObj, lpszUniqueID, &m_hNotifyObj);
  254. delete[] lpszUniqueID;
  255. CHECK_HRESULT(hr, return hr);
  256. }
  257. else
  258. {
  259. if (lpszUniqueID)
  260. {
  261. delete[] lpszUniqueID;
  262. lpszUniqueID = 0;
  263. }
  264. }
  265. //
  266. // Create each page.
  267. //
  268. for (i = 0; i < m_pDsPPages->cPages; i++)
  269. {
  270. PDSPAGE pDsPage = m_pDsPPages->rgpDsPages[i];
  271. if ((pDsPage->dwFlags & DSPROVIDER_ADVANCED) &&
  272. !(pDsObjectNames->aObjects[0].dwProviderFlags & DSPROVIDER_ADVANCED))
  273. {
  274. // The page should only be displayed if in advanced mode.
  275. //
  276. continue;
  277. }
  278. if (pDsPage->nCLSIDs)
  279. {
  280. // Only show the page if there is a match on the snapin (namespace)
  281. // CLSID.
  282. //
  283. BOOL fFound = FALSE;
  284. for (DWORD j = 0; j < pDsPage->nCLSIDs; j++)
  285. {
  286. if (IsEqualCLSID(pDsPage->rgCLSID[j],
  287. pDsObjectNames->clsidNamespace))
  288. {
  289. fFound = TRUE;
  290. }
  291. }
  292. if (!fFound)
  293. {
  294. continue;
  295. }
  296. }
  297. // Call the page's creation function.
  298. //
  299. hr = (*pDsPage->pCreateFcn)(pDsPage, m_pDataObj, pwzObjADsPath,
  300. pwzClass, m_hNotifyObj,
  301. pDsObjectNames->aObjects[0].dwFlags,
  302. basePathsInfo,
  303. &hPage);
  304. if (hr == S_FALSE)
  305. {
  306. // If the page doesn't want to be shown, it should return S_FALSE.
  307. //
  308. continue;
  309. }
  310. if (hr == HRESULT_FROM_WIN32(ERROR_BAD_NET_RESP))
  311. {
  312. break;
  313. }
  314. CHECK_HRESULT(hr, continue);
  315. // Pass the page handle back to the app wanting to post the prop sheet.
  316. //
  317. if (!(*pAddPageProc)(hPage, lParam))
  318. {
  319. CHECK_HRESULT(E_FAIL, return E_FAIL);
  320. }
  321. }
  322. return hr;
  323. }
  324. //+----------------------------------------------------------------------------
  325. //
  326. // Member: CDsPropPagesHost::IShellExtInit::ReplacePage
  327. //
  328. // Synopsis: Unused.
  329. //
  330. //-----------------------------------------------------------------------------
  331. STDMETHODIMP
  332. CDsPropPagesHost::ReplacePage(UINT,
  333. LPFNADDPROPSHEETPAGE,
  334. LPARAM)
  335. {
  336. TRACE(CDsPropPagesHost,ReplacePage);
  337. return E_NOTIMPL;
  338. }
  339. //+----------------------------------------------------------------------------
  340. //
  341. // Multi-valued attribute editing.
  342. //
  343. //-----------------------------------------------------------------------------
  344. //+----------------------------------------------------------------------------
  345. //
  346. // Class: CMultiStringAttrDlg
  347. //
  348. // Purpose: Read, edit, and write a multi-valued, string property. This is
  349. // the dialog that contains the CMultiStringAttr class controls.
  350. //
  351. //-----------------------------------------------------------------------------
  352. CMultiStringAttrDlg::CMultiStringAttrDlg(CDsPropPageBase * pPage) :
  353. m_pPage(pPage),
  354. m_MSA(pPage)
  355. {
  356. }
  357. //+----------------------------------------------------------------------------
  358. //
  359. // Member: CMultiStringAttrDlg::Init
  360. //
  361. // Synopsis: Do initialization where failures can occur and then be
  362. // returned. Can be only called once as written.
  363. //
  364. // Arguments: [pAttrMap] - contains the attr name.
  365. // [pAttrInfo] - place to store the values.
  366. // [nLimit] - the max number of values (zero means no limit).
  367. // [fCommaList] - if TRUE, pAttrInfo is a single-valued, comma
  368. // delimited list.
  369. //-----------------------------------------------------------------------------
  370. HRESULT
  371. CMultiStringAttrDlg::Init(PATTR_MAP pAttrMap, PADS_ATTR_INFO pAttrInfo,
  372. BOOL fWritable, int nLimit, BOOL fCommaList, BOOL fMultiselectPage)
  373. {
  374. return m_MSA.Init(pAttrMap, pAttrInfo, fWritable, nLimit, fCommaList, fMultiselectPage);
  375. }
  376. //+----------------------------------------------------------------------------
  377. //
  378. // Member: CMultiStringAttrDlg::Write
  379. //
  380. // Synopsis: Return the ADS_ATTR_INFO array of values to be Applied.
  381. //
  382. //-----------------------------------------------------------------------------
  383. HRESULT CMultiStringAttrDlg::Write(PADS_ATTR_INFO pAttrInfo)
  384. {
  385. return m_MSA.Write(pAttrInfo);
  386. }
  387. //+----------------------------------------------------------------------------
  388. //
  389. // Member: CMultiStringAttrDlg::Edit
  390. //
  391. // Synopsis: Post the edit dialog.
  392. //
  393. //-----------------------------------------------------------------------------
  394. INT_PTR CMultiStringAttrDlg::Edit(void)
  395. {
  396. INT_PTR nRet;
  397. nRet = DialogBoxParam(g_hInstance, MAKEINTRESOURCE(IDD_MULTI_VALUE),
  398. m_pPage->GetHWnd(), StaticDlgProc, (LPARAM)this);
  399. if (IDOK == nRet)
  400. {
  401. EnableWindow(GetDlgItem(GetParent(m_pPage->GetHWnd()), IDOK), TRUE);
  402. m_pPage->SetDirty();
  403. }
  404. return nRet;
  405. }
  406. //+----------------------------------------------------------------------------
  407. //
  408. // Member: CMultiStringAttrDlg::StaticDlgProc
  409. //
  410. // Synopsis: The static dialog proc for editing a multi-valued attribute.
  411. //
  412. //-----------------------------------------------------------------------------
  413. INT_PTR CALLBACK
  414. CMultiStringAttrDlg::StaticDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam,
  415. LPARAM lParam)
  416. {
  417. CMultiStringAttrDlg * pMSAD = (CMultiStringAttrDlg *)GetWindowLongPtr(hDlg, DWLP_USER);
  418. if (uMsg == WM_INITDIALOG)
  419. {
  420. pMSAD = (CMultiStringAttrDlg *)lParam;
  421. SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)pMSAD);
  422. }
  423. if (pMSAD)
  424. {
  425. return pMSAD->MultiValDlgProc(hDlg, uMsg, wParam, lParam);
  426. }
  427. return FALSE;
  428. }
  429. //+----------------------------------------------------------------------------
  430. //
  431. // Member: CMultiStringAttrDlg::MultiValDlgProc
  432. //
  433. // Synopsis: The instancce dialog proc for editing a multi-valued attribute.
  434. //
  435. //-----------------------------------------------------------------------------
  436. INT_PTR CALLBACK
  437. CMultiStringAttrDlg::MultiValDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam,
  438. LPARAM lParam)
  439. {
  440. CMultiStringAttrDlg * pMSAD = (CMultiStringAttrDlg *)GetWindowLongPtr(hDlg, DWLP_USER);
  441. CMultiStringAttr * pMSA = &pMSAD->m_MSA;
  442. switch (uMsg)
  443. {
  444. case WM_INITDIALOG:
  445. CHECK_NULL_REPORT(pMSA, hDlg, return 0;);
  446. return pMSA->DoDlgInit(hDlg);
  447. case WM_COMMAND:
  448. CHECK_NULL_REPORT(pMSA, hDlg, return 0;);
  449. return pMSA->DoCommand(hDlg,
  450. GET_WM_COMMAND_ID(wParam, lParam),
  451. GET_WM_COMMAND_CMD(wParam, lParam));
  452. case WM_NOTIFY:
  453. CHECK_NULL_REPORT(pMSA, hDlg, return 0;);
  454. return pMSA->DoNotify(hDlg, (NMHDR *)lParam);
  455. case WM_HELP:
  456. LPHELPINFO pHelpInfo = (LPHELPINFO)lParam;
  457. dspDebugOut((DEB_ITRACE, "WM_HELP: CtrlId = %d, ContextId = 0x%x\n",
  458. pHelpInfo->iCtrlId, pHelpInfo->dwContextId));
  459. if (pHelpInfo->iCtrlId < 1)
  460. {
  461. return 0;
  462. }
  463. WinHelp(hDlg, DSPROP_HELP_FILE_NAME, HELP_CONTEXTPOPUP, pHelpInfo->dwContextId);
  464. break;
  465. }
  466. return 0;
  467. }
  468. //+----------------------------------------------------------------------------
  469. //
  470. // Class: CMultiStringAttr
  471. //
  472. // Purpose: Read, edit, and write a multi-valued, string property.
  473. //
  474. //-----------------------------------------------------------------------------
  475. CMultiStringAttr::CMultiStringAttr(CDsPropPageBase * pPage) :
  476. m_pPage(pPage),
  477. m_pAttrLDAPname(NULL),
  478. m_nMaxLen(0),
  479. m_nCurDefCtrl(IDC_CLOSE),
  480. m_fListHasSel(FALSE),
  481. m_nLimit(0),
  482. m_cValues(0),
  483. m_fWritable(TRUE),
  484. m_fCommaList(FALSE),
  485. m_fDirty(FALSE),
  486. m_fAppend(FALSE)
  487. {
  488. m_AttrInfo.pADsValues = NULL;
  489. m_AttrInfo.dwNumValues = 0;
  490. m_AttrInfo.pszAttrName = NULL;
  491. }
  492. CMultiStringAttr::~CMultiStringAttr()
  493. {
  494. ClearAttrInfo();
  495. DO_DEL(m_pAttrLDAPname);
  496. }
  497. void CMultiStringAttr::ClearAttrInfo(void)
  498. {
  499. for (DWORD i = 0; i < m_AttrInfo.dwNumValues; i++)
  500. {
  501. delete [] m_AttrInfo.pADsValues[i].CaseIgnoreString;
  502. }
  503. if (m_AttrInfo.pADsValues)
  504. {
  505. delete [] m_AttrInfo.pADsValues;
  506. }
  507. m_AttrInfo.pADsValues = NULL;
  508. m_AttrInfo.dwNumValues = 0;
  509. }
  510. //+----------------------------------------------------------------------------
  511. //
  512. // Member: CMultiStringAttr::Init
  513. //
  514. // Synopsis: Do initialization where failures can occur and then be
  515. // returned. Can be only called once as written.
  516. //
  517. // Arguments: [pAttrMap] - contains the attr name.
  518. // [pAttrInfo] - place to store the values.
  519. // [nLimit] - the max number of values (zero means no limit).
  520. // [fCommaList] - if TRUE, pAttrInfo is a single-valued, comma
  521. // delimited list.
  522. //-----------------------------------------------------------------------------
  523. HRESULT
  524. CMultiStringAttr::Init(PATTR_MAP pAttrMap, PADS_ATTR_INFO pAttrInfo,
  525. BOOL fWritable, int nLimit, BOOL fCommaList, BOOL fAppend)
  526. {
  527. if (!AllocWStr(pAttrMap->AttrInfo.pszAttrName, &m_pAttrLDAPname))
  528. {
  529. REPORT_ERROR(E_OUTOFMEMORY, m_pPage->GetHWnd());
  530. return E_OUTOFMEMORY;
  531. }
  532. m_nLimit = nLimit;
  533. m_fCommaList = fCommaList;
  534. m_fWritable = fWritable;
  535. m_fAppend = fAppend;
  536. m_nMaxLen = pAttrMap->nSizeLimit;
  537. m_AttrInfo.dwADsType = pAttrMap->AttrInfo.dwADsType;
  538. if (NULL == pAttrInfo)
  539. {
  540. return S_OK;
  541. }
  542. DWORD cItems = 0;
  543. PWSTR pwzComma, pwzCur;
  544. if (fCommaList)
  545. {
  546. pwzCur = pAttrInfo->pADsValues->CaseIgnoreString;
  547. //
  548. // Count the number of elements. This count includes empty elements,
  549. // e.g. leading, trailing, or adjacent commas.
  550. //
  551. while (*pwzCur)
  552. {
  553. cItems++;
  554. pwzComma = wcschr(pwzCur, L',');
  555. if (pwzComma)
  556. {
  557. pwzCur = pwzComma + 1;
  558. }
  559. else
  560. {
  561. break;
  562. }
  563. }
  564. }
  565. else
  566. {
  567. cItems = pAttrInfo->dwNumValues;
  568. }
  569. m_AttrInfo.pADsValues = new ADSVALUE[cItems];
  570. CHECK_NULL_REPORT(m_AttrInfo.pADsValues, m_pPage->GetHWnd(), return E_OUTOFMEMORY);
  571. for (DWORD i = 0, j = 0; i < cItems; i++)
  572. {
  573. if (fCommaList)
  574. {
  575. if (i == 0)
  576. {
  577. pwzCur = wcstok(pAttrInfo->pADsValues->CaseIgnoreString, L",\0");
  578. }
  579. else
  580. {
  581. pwzCur = wcstok(NULL, L",\0");
  582. }
  583. if (!pwzCur)
  584. {
  585. break;
  586. }
  587. if (!*pwzCur)
  588. {
  589. // Skip empty elements.
  590. //
  591. continue;
  592. }
  593. if (!AllocWStr(pwzCur, &m_AttrInfo.pADsValues[j].CaseIgnoreString))
  594. {
  595. REPORT_ERROR(E_OUTOFMEMORY, m_pPage->GetHWnd());
  596. return E_OUTOFMEMORY;
  597. }
  598. }
  599. else
  600. {
  601. dspAssert(i == j);
  602. if (!AllocWStr(pAttrInfo->pADsValues[j].CaseIgnoreString,
  603. &m_AttrInfo.pADsValues[j].CaseIgnoreString))
  604. {
  605. REPORT_ERROR(E_OUTOFMEMORY, m_pPage->GetHWnd());
  606. return E_OUTOFMEMORY;
  607. }
  608. }
  609. m_AttrInfo.pADsValues[j].dwType = m_AttrInfo.dwADsType;
  610. m_AttrInfo.dwNumValues++;
  611. j++;
  612. }
  613. return S_OK;
  614. }
  615. //+----------------------------------------------------------------------------
  616. //
  617. // Member: CMultiStringAttr::ToggleDefaultBtn
  618. //
  619. // Synopsis: Calls ToggleMVDefaultBtn which sets the default button
  620. // to the correct control for the state of the dialog
  621. //
  622. //-----------------------------------------------------------------------------
  623. void
  624. CMultiStringAttr::ToggleDefaultBtn(HWND hDlg, BOOL fOK)
  625. {
  626. ToggleMVDefaultBtn(hDlg, fOK);
  627. }
  628. //+----------------------------------------------------------------------------
  629. //
  630. // Member: CMultiStringAttr::Write
  631. //
  632. // Synopsis: Return the ADS_ATTR_INFO array of values to be Applied.
  633. //
  634. //-----------------------------------------------------------------------------
  635. HRESULT CMultiStringAttr::Write(PADS_ATTR_INFO pAttrInfo)
  636. {
  637. pAttrInfo->dwADsType = m_AttrInfo.dwADsType;
  638. pAttrInfo->dwNumValues = 0;
  639. if (!m_fWritable)
  640. {
  641. return ADM_S_SKIP;
  642. }
  643. if (m_AttrInfo.dwNumValues)
  644. {
  645. PADSVALUE pADsValues;
  646. int nValues = (m_fCommaList) ? 1 : m_AttrInfo.dwNumValues;
  647. pADsValues = new ADSVALUE[nValues];
  648. CHECK_NULL_REPORT(pADsValues, m_pPage->GetHWnd(), return E_OUTOFMEMORY);
  649. if (m_fAppend)
  650. {
  651. pAttrInfo->dwControlCode = ADS_ATTR_APPEND;
  652. }
  653. else
  654. {
  655. pAttrInfo->dwControlCode = ADS_ATTR_UPDATE;
  656. }
  657. pAttrInfo->pADsValues = pADsValues;
  658. if (m_fCommaList)
  659. {
  660. // For simplicity, just go ahead and allocate the max. That is,
  661. // there are m_AttrInfo.dwNumValues values each which can be a max
  662. // length of m_nMaxLen. The comma separator is included in the
  663. // count.
  664. //
  665. pADsValues->CaseIgnoreString = new WCHAR[(m_AttrInfo.dwNumValues * (m_nMaxLen + 1)) + 1];
  666. CHECK_NULL_REPORT(pADsValues->CaseIgnoreString, m_pPage->GetHWnd(), return E_OUTOFMEMORY);
  667. wcscpy(pADsValues->CaseIgnoreString,
  668. m_AttrInfo.pADsValues[0].CaseIgnoreString);
  669. for (DWORD i = 1; i < m_AttrInfo.dwNumValues; i++)
  670. {
  671. wcscat(pADsValues->CaseIgnoreString, L",");
  672. wcscat(pADsValues->CaseIgnoreString,
  673. m_AttrInfo.pADsValues[i].CaseIgnoreString);
  674. }
  675. pADsValues->dwType = m_AttrInfo.dwADsType;
  676. pAttrInfo->dwNumValues = 1;
  677. }
  678. else
  679. {
  680. for (DWORD i = 0; i < m_AttrInfo.dwNumValues; i++)
  681. {
  682. PWSTR pwz;
  683. if (!AllocWStr(m_AttrInfo.pADsValues[i].CaseIgnoreString, &pwz))
  684. {
  685. REPORT_ERROR(E_OUTOFMEMORY, m_pPage->GetHWnd());
  686. return E_OUTOFMEMORY;
  687. }
  688. pADsValues[i].dwType = m_AttrInfo.dwADsType;
  689. pADsValues[i].CaseIgnoreString = pwz;
  690. pAttrInfo->dwNumValues++;
  691. }
  692. }
  693. }
  694. else
  695. {
  696. pAttrInfo->pADsValues = NULL;
  697. pAttrInfo->dwControlCode = ADS_ATTR_CLEAR;
  698. }
  699. return S_OK;
  700. }
  701. //+----------------------------------------------------------------------------
  702. //
  703. // Member: CMultiStringAttr::SetDirty
  704. //
  705. // Synopsis: Marks the page dirty and enables the OK button
  706. //
  707. //-----------------------------------------------------------------------------
  708. void CMultiStringAttr::SetDirty(HWND hDlg)
  709. {
  710. m_fDirty = TRUE;
  711. EnableWindow(GetDlgItem(hDlg, IDC_CLOSE), m_fDirty);
  712. }
  713. //+----------------------------------------------------------------------------
  714. //
  715. // Member: CMultiStringAttr::EnableControls
  716. //
  717. // Synopsis: Enable or disable all of the controls.
  718. //
  719. //-----------------------------------------------------------------------------
  720. void
  721. CMultiStringAttr::EnableControls(HWND hDlg, BOOL fEnable)
  722. {
  723. EnableWindow(GetDlgItem(hDlg, IDC_EDIT), fEnable);
  724. EnableWindow(GetDlgItem(hDlg, IDC_LIST), fEnable);
  725. if (!fEnable)
  726. {
  727. EnableWindow(GetDlgItem(hDlg, IDC_ADD_BTN), FALSE);
  728. EnableWindow(GetDlgItem(hDlg, IDC_DELETE_BTN), FALSE);
  729. EnableWindow(GetDlgItem(hDlg, IDC_EDIT_BTN), FALSE);
  730. m_fListHasSel = FALSE;
  731. }
  732. EnableWindow(GetDlgItem(hDlg, IDC_CLOSE), IsDirty());
  733. }
  734. //+----------------------------------------------------------------------------
  735. //
  736. // Member: CMultiStringAttr::DoDlgInit
  737. //
  738. // Synopsis: WM_INITDIALOG code.
  739. //
  740. //-----------------------------------------------------------------------------
  741. BOOL
  742. CMultiStringAttr::DoDlgInit(HWND hDlg)
  743. {
  744. LPTSTR ptz;
  745. HRESULT hr = S_OK;
  746. LONG i;
  747. HWND hList;
  748. LV_ITEM lvi;
  749. /*
  750. //
  751. // Create the dialog caption: "<obj-name> - <attribute-name>"
  752. //
  753. TCHAR szCaption[MAX_PATH];
  754. if (!UnicodeToTchar(m_pPage->GetObjRDName(), &ptz))
  755. {
  756. CHECK_WIN32_REPORT(ERROR_NOT_ENOUGH_MEMORY, hDlg, return FALSE);
  757. }
  758. _tcscpy(szCaption, ptz);
  759. delete [] ptz;
  760. _tcscat(szCaption, TEXT(" - "));
  761. int len = _tcslen(szCaption);
  762. */
  763. // Get the attribute "friendly" name.
  764. //
  765. WCHAR wzBuf[MAX_PATH + 1];
  766. IDsDisplaySpecifier * pDispSpec;
  767. hr = m_pPage->GetIDispSpec(&pDispSpec);
  768. CHECK_HRESULT_REPORT(hr, hDlg, return 0);
  769. //
  770. // If this is multi-select it must be a homogenous selection so if
  771. // m_pPage->GetObjClass() returns NULL then get the class from the data object
  772. //
  773. CStrW szClassName = m_pPage->GetObjClass();
  774. if (szClassName.IsEmpty())
  775. {
  776. //
  777. // For the retrieval of the DS Object names
  778. //
  779. FORMATETC fmte = {g_cfDsObjectNames, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  780. STGMEDIUM objMedium;
  781. hr = m_pPage->m_pWPTDataObj->GetData(&fmte, &objMedium);
  782. CHECK_HRESULT(hr, return FALSE);
  783. LPDSOBJECTNAMES pDsObjectNames = (LPDSOBJECTNAMES)objMedium.hGlobal;
  784. //
  785. // Get the objects class
  786. //
  787. szClassName = (PWSTR)ByteOffset(pDsObjectNames,
  788. pDsObjectNames->aObjects[0].offsetClass);
  789. ReleaseStgMedium(&objMedium);
  790. }
  791. hr = pDispSpec->GetFriendlyAttributeName((LPCWSTR)szClassName,
  792. m_pAttrLDAPname, wzBuf, MAX_PATH);
  793. CHECK_HRESULT_REPORT(hr, hDlg, return 0);
  794. if (!UnicodeToTchar(wzBuf, &ptz))
  795. {
  796. REPORT_ERROR(E_OUTOFMEMORY, hDlg);
  797. return 0;
  798. }
  799. //_tcscat(szCaption, ptz);
  800. SetWindowText(hDlg, ptz);
  801. delete [] ptz;
  802. // Limit the entry length of the edit control.
  803. //
  804. SendDlgItemMessage(hDlg, IDC_EDIT, EM_LIMITTEXT, m_nMaxLen, 0);
  805. // Initialize the list view.
  806. //
  807. RECT rect;
  808. LV_COLUMN lvc;
  809. hList = GetDlgItem(hDlg, IDC_LIST);
  810. ListView_SetExtendedListViewStyle(hList, LVS_EX_FULLROWSELECT);
  811. if (!m_fWritable)
  812. {
  813. LONG_PTR lStyle = GetWindowLongPtr(hList, GWL_STYLE);
  814. lStyle &= ~(LVS_EDITLABELS);
  815. SetWindowLongPtr(hList, GWL_STYLE, lStyle);
  816. }
  817. GetClientRect(hList, &rect);
  818. lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_SUBITEM;
  819. lvc.fmt = LVCFMT_LEFT;
  820. lvc.cx = rect.right;
  821. lvc.iSubItem = 0;
  822. ListView_InsertColumn(hList, 0, &lvc);
  823. // Load the list view.
  824. //
  825. lvi.mask = LVIF_TEXT | LVIF_PARAM;
  826. lvi.iSubItem = 0;
  827. lvi.lParam = m_nMaxLen;
  828. for (i = 0; (DWORD)i < m_AttrInfo.dwNumValues; i++)
  829. {
  830. if (!UnicodeToTchar(m_AttrInfo.pADsValues[i].CaseIgnoreString,
  831. &ptz))
  832. {
  833. ReportError(E_OUTOFMEMORY, 0, hDlg);
  834. return 0;
  835. }
  836. lvi.pszText = ptz;
  837. lvi.iItem = i;
  838. ListView_InsertItem(hList, &lvi);
  839. m_cValues++;
  840. delete[] ptz;
  841. ptz = 0;
  842. }
  843. //
  844. // Disable the Add, Change, and Remove buttons.
  845. //
  846. EnableWindow(GetDlgItem(hDlg, IDC_ADD_BTN), FALSE);
  847. EnableWindow(GetDlgItem(hDlg, IDC_DELETE_BTN), FALSE);
  848. EnableWindow(GetDlgItem(hDlg, IDC_EDIT_BTN), FALSE);
  849. EnableWindow(GetDlgItem(hDlg, IDC_CLOSE), FALSE);
  850. if (!m_fWritable)
  851. {
  852. EnableWindow(GetDlgItem(hDlg, IDC_EDIT), FALSE);
  853. EnableWindow(GetDlgItem(hDlg, IDC_CLOSE), TRUE);
  854. CStr close;
  855. BOOL loadResult = close.LoadString(g_hInstance, IDS_CLOSE);
  856. dspAssert(loadResult);
  857. if (loadResult)
  858. {
  859. SetDlgItemText(hDlg, IDC_CLOSE, close);
  860. }
  861. }
  862. //
  863. // Make the CLOSE button the default.
  864. //
  865. int style;
  866. style = (int)GetWindowLongPtr(GetDlgItem(hDlg, IDCANCEL), GWL_STYLE);
  867. style |= BS_DEFPUSHBUTTON;
  868. SendMessage(hDlg, DM_SETDEFID, (WPARAM)IDCANCEL, 0);
  869. SendDlgItemMessage(hDlg, IDC_CLOSE, BM_SETSTYLE, (WPARAM)BS_PUSHBUTTON, MAKELPARAM(TRUE, 0));
  870. SendDlgItemMessage(hDlg, IDCANCEL, BM_SETSTYLE,
  871. (WPARAM)LOWORD(style), MAKELPARAM(TRUE, 0));
  872. m_nCurDefCtrl = IDCANCEL;
  873. return 1;
  874. }
  875. //+----------------------------------------------------------------------------
  876. //
  877. // Member: CMultiStringAttr::DoCommand
  878. //
  879. // Synopsis: WM_COMMAND code.
  880. //
  881. //-----------------------------------------------------------------------------
  882. int
  883. CMultiStringAttr::DoCommand(HWND hDlg, int id, int code)
  884. {
  885. LPTSTR ptz;
  886. LONG i;
  887. HWND hList;
  888. LV_ITEM lvi;
  889. switch (code)
  890. {
  891. case BN_CLICKED:
  892. if (id == IDOK)
  893. {
  894. // Hitting Return causes IDOK to be sent. Replace that with the
  895. // ID of the control that is currently the default.
  896. //
  897. id = m_nCurDefCtrl;
  898. }
  899. switch (id)
  900. {
  901. case IDC_ADD_BTN:
  902. if (m_nLimit && (m_cValues >= m_nLimit))
  903. {
  904. ErrMsgParam(IDS_MULTISEL_LIMIT, (LPARAM)m_nLimit, hDlg);
  905. return 1;
  906. }
  907. ptz = new TCHAR[m_nMaxLen + 1];
  908. CHECK_NULL_REPORT(ptz, hDlg, return -1);
  909. // NTRAID#NTBUG9-525208-2002/01/29-ronmart-off by one error on buffer len
  910. if (GetWindowText(GetDlgItem(hDlg, IDC_EDIT), ptz,
  911. m_nMaxLen + 1))
  912. {
  913. hList = GetDlgItem(hDlg, IDC_LIST);
  914. //
  915. // See if the string already exists
  916. //
  917. LVFINDINFO lvSearchInfo = {0};
  918. lvSearchInfo.flags = LVFI_STRING;
  919. lvSearchInfo.psz = ptz;
  920. i = ListView_FindItem(hList, -1, &lvSearchInfo);
  921. if (i == -1)
  922. {
  923. i = ListView_GetItemCount(hList);
  924. // NTRAID#NTBUG9-525198-2002/01/29-ronmart-store max length in lparam
  925. lvi.mask = LVIF_TEXT | LVIF_PARAM;
  926. lvi.iSubItem = 0;
  927. lvi.pszText = ptz;
  928. // NTRAID#NTBUG9-525198-2002/01/29-ronmart-Set the max length allowed
  929. lvi.lParam = m_nMaxLen;
  930. lvi.iItem = i;
  931. ListView_InsertItem(hList, &lvi);
  932. //Make this item selected and make it visible
  933. ListView_SetItemState( hList,
  934. i,
  935. LVIS_SELECTED|LVIS_FOCUSED ,
  936. LVIS_SELECTED|LVIS_FOCUSED );
  937. }
  938. ListView_EnsureVisible(hList, i, FALSE);
  939. m_cValues++;
  940. SetWindowText(GetDlgItem(hDlg, IDC_EDIT), TEXT(""));
  941. //
  942. // Disable the Save button and make the OK button the
  943. // default.
  944. //
  945. ToggleMVDefaultBtn(hDlg, TRUE);
  946. m_nCurDefCtrl = IDC_CLOSE;
  947. SetDirty(hDlg);
  948. }
  949. delete [] ptz;
  950. return 1;
  951. case IDC_DELETE_BTN:
  952. case IDC_EDIT_BTN:
  953. hList = GetDlgItem(hDlg, IDC_LIST);
  954. i = ListView_GetNextItem(hList, -1, LVNI_SELECTED);
  955. dspDebugOut((DEB_ITRACE, "List element %d selected\n", i));
  956. if (i >= 0)
  957. {
  958. if (id == IDC_DELETE_BTN)
  959. {
  960. ListView_DeleteItem(hList, i);
  961. m_cValues--;
  962. //Get the count of list view items
  963. LONG itemCount = ListView_GetItemCount(hList);
  964. if(itemCount)
  965. {
  966. ListView_SetItemState( hList,
  967. (itemCount > i) ? i : i-1,
  968. LVIS_SELECTED|LVIS_FOCUSED ,
  969. LVIS_SELECTED|LVIS_FOCUSED );
  970. }
  971. else
  972. {
  973. EnableWindow(GetDlgItem(hDlg, IDC_DELETE_BTN), FALSE);
  974. EnableWindow(GetDlgItem(hDlg, IDC_EDIT_BTN), FALSE);
  975. SetFocus(GetDlgItem(hDlg, IDC_EDIT));
  976. m_fListHasSel = FALSE;
  977. }
  978. SetDirty(hDlg);
  979. ToggleMVDefaultBtn(hDlg, TRUE);
  980. }
  981. else
  982. {
  983. ToggleMVDefaultBtn(hDlg, TRUE);
  984. SetFocus(GetDlgItem(hDlg, IDC_LIST));
  985. ListView_EditLabel(hList, i);
  986. }
  987. }
  988. return 1;
  989. case IDC_CLOSE:
  990. {
  991. // Copy the list box back to the attr info list.
  992. //
  993. int nItems;
  994. ClearAttrInfo();
  995. m_fListHasSel = FALSE;
  996. hList = GetDlgItem(hDlg, IDC_LIST);
  997. nItems = ListView_GetItemCount(hList);
  998. if (nItems == 0)
  999. {
  1000. EndDialog(hDlg, IDOK);
  1001. return 1;
  1002. }
  1003. m_AttrInfo.pADsValues = new ADSVALUE[nItems];
  1004. CHECK_NULL_REPORT(m_AttrInfo.pADsValues, hDlg, return -1);
  1005. ptz = new TCHAR[m_nMaxLen + 1];
  1006. CHECK_NULL_REPORT(ptz, hDlg, return -1);
  1007. lvi.mask = LVIF_TEXT;
  1008. lvi.iSubItem = 0;
  1009. lvi.pszText = ptz;
  1010. lvi.cchTextMax = m_nMaxLen + 1;
  1011. for (i = 0; i < nItems; i++)
  1012. {
  1013. lvi.iItem = i;
  1014. if (!ListView_GetItem(hList, &lvi))
  1015. {
  1016. REPORT_ERROR(GetLastError(), hDlg);
  1017. delete [] ptz;
  1018. EndDialog(hDlg, IDCANCEL);
  1019. return -1;
  1020. }
  1021. if (!TcharToUnicode(ptz,
  1022. &m_AttrInfo.pADsValues[i].CaseIgnoreString))
  1023. {
  1024. REPORT_ERROR(E_OUTOFMEMORY, hDlg);
  1025. return E_OUTOFMEMORY;
  1026. }
  1027. m_AttrInfo.pADsValues[i].dwType = m_AttrInfo.dwADsType;
  1028. m_AttrInfo.dwNumValues++;
  1029. }
  1030. delete [] ptz;
  1031. EndDialog(hDlg, IDOK);
  1032. }
  1033. return IDOK;
  1034. case IDCANCEL:
  1035. m_fListHasSel = FALSE;
  1036. EndDialog(hDlg, IDCANCEL);
  1037. return IDCANCEL;
  1038. }
  1039. break;
  1040. case EN_CHANGE:
  1041. if (id == IDC_EDIT)
  1042. {
  1043. BOOL fEnableAdd = FALSE;
  1044. LRESULT lTextLen = SendDlgItemMessage(hDlg, IDC_EDIT,
  1045. WM_GETTEXTLENGTH,
  1046. 0, 0);
  1047. PTSTR pszText = new TCHAR[lTextLen + 1];
  1048. if (pszText != NULL)
  1049. {
  1050. if (!GetDlgItemText(hDlg, IDC_EDIT, pszText, static_cast<int>(lTextLen + 1)))
  1051. {
  1052. fEnableAdd = lTextLen > 0;
  1053. }
  1054. else
  1055. {
  1056. CStr strText;
  1057. strText = pszText;
  1058. strText.TrimLeft();
  1059. strText.TrimRight();
  1060. if (strText.IsEmpty())
  1061. {
  1062. fEnableAdd = FALSE;
  1063. }
  1064. else
  1065. {
  1066. fEnableAdd = TRUE;
  1067. }
  1068. }
  1069. delete[] pszText;
  1070. }
  1071. else
  1072. {
  1073. fEnableAdd = lTextLen > 0;
  1074. }
  1075. if (fEnableAdd && (m_nCurDefCtrl == IDC_ADD_BTN))
  1076. {
  1077. return 1;
  1078. }
  1079. m_nCurDefCtrl = (fEnableAdd) ? IDC_ADD_BTN : IDC_CLOSE;
  1080. EnableWindow(GetDlgItem(hDlg, IDC_ADD_BTN), fEnableAdd);
  1081. ToggleMVDefaultBtn(hDlg, !fEnableAdd);
  1082. return 1;
  1083. }
  1084. break;
  1085. }
  1086. return 0;
  1087. }
  1088. //+----------------------------------------------------------------------------
  1089. //
  1090. // Member: CMultiStringAttr::DoNotify
  1091. //
  1092. // Synopsis: WM_NOTIFY code.
  1093. //
  1094. //-----------------------------------------------------------------------------
  1095. BOOL
  1096. CMultiStringAttr::DoNotify(HWND hDlg, NMHDR * pNmHdr)
  1097. {
  1098. if (pNmHdr->idFrom != IDC_LIST)
  1099. {
  1100. return TRUE;
  1101. }
  1102. LV_DISPINFO * pldi = (LV_DISPINFO *)pNmHdr;
  1103. switch (pNmHdr->code)
  1104. {
  1105. case LVN_ENDLABELEDIT:
  1106. if (pldi->item.pszText)
  1107. {
  1108. // NTRAID#NTBUG9-525223-2002/01/29-ronmart-don't allow zero length string
  1109. // NTRAID#NTBUG9-525198-2002/01/29-ronmart-Check the lParam for the max length allowed
  1110. int nLen = lstrlen(pldi->item.pszText);
  1111. if(nLen < 1 || nLen > pldi->item.lParam)
  1112. return FALSE;
  1113. dspDebugOut((DEB_ITRACE, "Editing item %d, new value %S\n",
  1114. pldi->item.iItem, pldi->item.pszText));
  1115. ListView_SetItemText(pldi->hdr.hwndFrom, pldi->item.iItem, 0,
  1116. pldi->item.pszText);
  1117. //
  1118. // Disable the Save button and make the OK button the
  1119. // default.
  1120. //
  1121. SetDirty(hDlg);
  1122. ToggleMVDefaultBtn(hDlg, TRUE);
  1123. }
  1124. break;
  1125. case NM_SETFOCUS:
  1126. dspDebugOut((DEB_ITRACE, "NM_SETFOCUS received\n"));
  1127. if (pldi->hdr.idFrom == IDC_LIST)
  1128. {
  1129. //
  1130. // If the list control gets the focus by tabbing and no item
  1131. // is selected, then set the selection to the first item.
  1132. //
  1133. if (!m_fListHasSel && ListView_GetItemCount(GetDlgItem(hDlg, IDC_LIST)))
  1134. {
  1135. dspDebugOut((DEB_ITRACE, "setting the list selection\n"));
  1136. m_fListHasSel = TRUE;
  1137. ListView_SetItemState(GetDlgItem(hDlg, IDC_LIST), 0,
  1138. LVIS_FOCUSED | LVIS_SELECTED,
  1139. LVIS_FOCUSED | LVIS_SELECTED);
  1140. if (m_fWritable)
  1141. {
  1142. EnableWindow(GetDlgItem(hDlg, IDC_DELETE_BTN), TRUE);
  1143. EnableWindow(GetDlgItem(hDlg, IDC_EDIT_BTN), TRUE);
  1144. }
  1145. }
  1146. }
  1147. return 1;
  1148. case LVN_ITEMCHANGED:
  1149. if (pldi->hdr.idFrom == IDC_LIST)
  1150. {
  1151. if(ListView_GetSelectedCount(GetDlgItem(hDlg, IDC_LIST)))
  1152. {
  1153. m_fListHasSel = TRUE;
  1154. if (m_fWritable)
  1155. {
  1156. EnableWindow(GetDlgItem(hDlg, IDC_DELETE_BTN), TRUE);
  1157. EnableWindow(GetDlgItem(hDlg, IDC_EDIT_BTN), TRUE);
  1158. }
  1159. }
  1160. else
  1161. {
  1162. m_fListHasSel = FALSE;
  1163. if (m_fWritable)
  1164. {
  1165. EnableWindow(GetDlgItem(hDlg, IDC_DELETE_BTN), FALSE);
  1166. EnableWindow(GetDlgItem(hDlg, IDC_EDIT_BTN), FALSE);
  1167. }
  1168. }
  1169. }
  1170. return 1;
  1171. }
  1172. return 0;
  1173. }
  1174. //+----------------------------------------------------------------------------
  1175. //
  1176. // Function: OtherValuesBtn
  1177. //
  1178. // Synopsis: "Others..." button that brings up a dialog (similar to the
  1179. // multi-valued attribute dialog) to modify the otherXXXX
  1180. // attribute. Usage: if a multi-valued property needs to
  1181. // have one value designated at the primary value, then this
  1182. // must be expressed as two separate attributes since multi-
  1183. // valued attributes are un-ordered. For example, consider tele-
  1184. // phone numbers; Telephone-Number, which is single-valued is the
  1185. // primary value and Phone-Office-Other, which is multi-valued,
  1186. // is used to store the "other" numbers.
  1187. //
  1188. //-----------------------------------------------------------------------------
  1189. HRESULT
  1190. OtherValuesBtn(CDsPropPageBase * pPage, PATTR_MAP pAttrMap,
  1191. PADS_ATTR_INFO pAttrInfo, LPARAM lParam, PATTR_DATA pAttrData,
  1192. DLG_OP DlgOp)
  1193. {
  1194. HRESULT hr = S_OK;
  1195. CMultiStringAttrDlg * pMultiS = NULL;
  1196. switch (DlgOp)
  1197. {
  1198. case fInit:
  1199. {
  1200. pMultiS = new CMultiStringAttrDlg(pPage);
  1201. CHECK_NULL_REPORT(pMultiS, pPage->GetHWnd(), return E_OUTOFMEMORY);
  1202. BOOL fMultiselectPage = pPage->IsMultiselectPage();
  1203. hr = pMultiS->Init(pAttrMap, pAttrInfo, PATTR_DATA_IS_WRITABLE(pAttrData), 0, FALSE, fMultiselectPage);
  1204. CHECK_HRESULT(hr, return hr);
  1205. pAttrData->pVoid = reinterpret_cast<LPARAM>(pMultiS); // save the object pointer.
  1206. }
  1207. break;
  1208. case fOnCommand:
  1209. if (lParam == BN_CLICKED)
  1210. {
  1211. CHECK_NULL(pAttrData->pVoid, return E_OUTOFMEMORY);
  1212. pMultiS = (CMultiStringAttrDlg *)pAttrData->pVoid;
  1213. if (IDOK == pMultiS->Edit())
  1214. {
  1215. PATTR_DATA_SET_DIRTY(pAttrData);
  1216. }
  1217. }
  1218. break;
  1219. case fApply:
  1220. if (!PATTR_DATA_IS_DIRTY(pAttrData))
  1221. {
  1222. return ADM_S_SKIP;
  1223. }
  1224. CHECK_NULL(pAttrData->pVoid, return E_OUTOFMEMORY);
  1225. pMultiS = (CMultiStringAttrDlg *)pAttrData->pVoid;
  1226. return pMultiS->Write(pAttrInfo);
  1227. case fOnDestroy:
  1228. if (pAttrData->pVoid)
  1229. {
  1230. delete (CMultiStringAttrDlg *)pAttrData->pVoid;
  1231. }
  1232. break;
  1233. }
  1234. return S_OK;
  1235. }
  1236. //+----------------------------------------------------------------------------
  1237. //
  1238. // Function ToggleMVDefaultBtn
  1239. //
  1240. // Synopsis: Toggle the default pushbutton of the multi-valued dialog.
  1241. //
  1242. //-----------------------------------------------------------------------------
  1243. void
  1244. ToggleMVDefaultBtn(HWND hDlg, BOOL fOK)
  1245. {
  1246. LONG style, newstyle;
  1247. int nDefault = IDC_CLOSE, nNotDefault = IDC_ADD_BTN;
  1248. if (!fOK)
  1249. {
  1250. nDefault = IDC_ADD_BTN;
  1251. nNotDefault = IDC_CLOSE;
  1252. }
  1253. //
  1254. // Clear the default bit on this one.
  1255. //
  1256. style = (LONG)GetWindowLongPtr(GetDlgItem(hDlg, nNotDefault), GWL_STYLE);
  1257. newstyle = style & ~(BS_DEFPUSHBUTTON);
  1258. SendDlgItemMessage(hDlg, nNotDefault, BM_SETSTYLE, (WPARAM)LOWORD(newstyle),
  1259. MAKELPARAM(TRUE, 0));
  1260. //
  1261. // Make this one the default.
  1262. //
  1263. style = (LONG)GetWindowLongPtr(GetDlgItem(hDlg, nDefault), GWL_STYLE);
  1264. newstyle = style | BS_DEFPUSHBUTTON;
  1265. SendMessage(hDlg, DM_SETDEFID, (WPARAM)nDefault, 0);
  1266. SendDlgItemMessage(hDlg, nDefault, BM_SETSTYLE, (WPARAM)LOWORD(newstyle),
  1267. MAKELPARAM(TRUE, 0));
  1268. if (fOK)
  1269. {
  1270. SetFocus(GetDlgItem(hDlg, IDC_EDIT));
  1271. }
  1272. }
  1273. //+----------------------------------------------------------------------------
  1274. //
  1275. // Function: GetObjectClass
  1276. //
  1277. // Synopsis: Object page attribute function for object class.
  1278. //
  1279. //-----------------------------------------------------------------------------
  1280. HRESULT
  1281. GetObjectClass(CDsPropPageBase * pPage, PATTR_MAP,
  1282. PADS_ATTR_INFO, LPARAM, PATTR_DATA,
  1283. DLG_OP DlgOp)
  1284. {
  1285. if (DlgOp == fInit)
  1286. {
  1287. WCHAR wszBuf[120];
  1288. PTSTR ptz;
  1289. HRESULT hr;
  1290. IDsDisplaySpecifier * pDispSpec;
  1291. hr = pPage->GetIDispSpec(&pDispSpec);
  1292. CHECK_HRESULT_REPORT(hr, pPage->GetHWnd(), return hr);
  1293. //
  1294. // Look up the localized class name on the object display
  1295. // specification cache.
  1296. //
  1297. hr = pDispSpec->GetFriendlyClassName(pPage->GetObjClass(), wszBuf, 120);
  1298. CHECK_HRESULT_REPORT(hr, pPage->GetHWnd(), return hr);
  1299. if (!UnicodeToTchar(wszBuf, &ptz))
  1300. {
  1301. REPORT_ERROR(E_OUTOFMEMORY, pPage->GetHWnd());
  1302. return E_OUTOFMEMORY;
  1303. }
  1304. SetDlgItemText(pPage->GetHWnd(), IDC_CLASS_STATIC, ptz);
  1305. delete [] ptz;
  1306. }
  1307. return S_OK;
  1308. }
  1309. //+----------------------------------------------------------------------------
  1310. //
  1311. // Function: GetObjectTimestamp
  1312. //
  1313. // Synopsis: Object page attribute function for object timestamps.
  1314. //
  1315. //-----------------------------------------------------------------------------
  1316. HRESULT
  1317. GetObjectTimestamp(CDsPropPageBase * pPage, PATTR_MAP pAttrMap,
  1318. PADS_ATTR_INFO pAttrInfo, LPARAM, PATTR_DATA,
  1319. DLG_OP DlgOp)
  1320. {
  1321. DWORD dwErr;
  1322. if ((DlgOp == fInit) && pPage)
  1323. {
  1324. TCHAR tszBuf[MAX_MSG_LEN];
  1325. if (pAttrInfo && pAttrInfo->dwNumValues && pAttrInfo->pADsValues &&
  1326. pAttrInfo->pADsValues->dwType == ADSTYPE_UTC_TIME)
  1327. {
  1328. SYSTEMTIME st = {0};
  1329. if (!SystemTimeToTzSpecificLocalTime(NULL, &pAttrInfo->pADsValues->UTCTime, &st))
  1330. {
  1331. dwErr = GetLastError();
  1332. CHECK_WIN32_REPORT(dwErr, pPage->GetHWnd(), return dwErr);
  1333. }
  1334. int cch = GetDateFormat(LOCALE_USER_DEFAULT, 0, &st, NULL,
  1335. tszBuf, MAX_MSG_LEN);
  1336. if (cch == 0)
  1337. {
  1338. dwErr = GetLastError();
  1339. CHECK_WIN32_REPORT(dwErr, pPage->GetHWnd(), return dwErr);
  1340. }
  1341. //NTRAID#NTBUG9-573434-2002/03/10-jmessec possible buffer overrun
  1342. _tcscat(tszBuf, TEXT(" "));
  1343. cch = static_cast<int>(_tcslen(tszBuf));
  1344. GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, tszBuf + cch,
  1345. MAX_MSG_LEN - cch);
  1346. }
  1347. else
  1348. {
  1349. if (!LoadString(g_hInstance, IDS_NO_VALUE, tszBuf, MAX_MSG_LEN - 1))
  1350. {
  1351. _tcscpy(tszBuf, TEXT(" "));
  1352. }
  1353. }
  1354. int nCtrl = 0;
  1355. switch (pAttrMap->nCtrlID)
  1356. {
  1357. case IDC_CREATED_TIME_STATIC:
  1358. DBG_OUT("Getting creation timestamp.");
  1359. nCtrl = IDC_CREATED_TIME_STATIC;
  1360. break;
  1361. case IDC_MODIFIED_TIME_STATIC:
  1362. DBG_OUT("Getting last modification timestamp.");
  1363. nCtrl = IDC_MODIFIED_TIME_STATIC;
  1364. break;
  1365. default:
  1366. REPORT_ERROR(E_INVALIDARG, pPage->GetHWnd());
  1367. }
  1368. SetDlgItemText(pPage->GetHWnd(), nCtrl, tszBuf);
  1369. }
  1370. return S_OK;
  1371. }
  1372. //+----------------------------------------------------------------------------
  1373. //
  1374. // Function: UnescapeCanonicalNameEx
  1375. //
  1376. // Synopsis: Takes a canonical name in the DS_CANONICAL_NAME format
  1377. // and removes the escaping
  1378. //
  1379. //-----------------------------------------------------------------------------
  1380. HRESULT
  1381. UnescapeCanonicalNameEx(
  1382. PCWSTR pszName,
  1383. CStrW& strUnescapedName)
  1384. {
  1385. HRESULT hr = S_OK;
  1386. strUnescapedName = pszName;
  1387. return hr;
  1388. }
  1389. //+----------------------------------------------------------------------------
  1390. //
  1391. // Function: ObjectPathField
  1392. //
  1393. // Synopsis: Handles the Object page path field.
  1394. //
  1395. //-----------------------------------------------------------------------------
  1396. HRESULT
  1397. ObjectPathField(CDsPropPageBase * pPage, PATTR_MAP,
  1398. PADS_ATTR_INFO, LPARAM, PATTR_DATA,
  1399. DLG_OP DlgOp)
  1400. {
  1401. if (DlgOp == fInit)
  1402. {
  1403. PWSTR pwzPath, pwzDNSname;
  1404. HRESULT hr = pPage->SkipPrefix(pPage->GetObjPathName(), &pwzPath);
  1405. CHECK_HRESULT_REPORT(hr, pPage->GetHWnd(), return hr);
  1406. hr = CrackName(pwzPath, &pwzDNSname, GET_OBJ_CAN_NAME, pPage->GetHWnd());
  1407. delete [] pwzPath;
  1408. CHECK_HRESULT(hr, return hr);
  1409. CStrW strUnescapedCanonicalName;
  1410. hr = UnescapeCanonicalNameEx(pwzDNSname, strUnescapedCanonicalName);
  1411. dspAssert(SUCCEEDED(hr));
  1412. LocalFreeStringW(&pwzDNSname);
  1413. PTSTR ptszPath;
  1414. if (!UnicodeToTchar((PWSTR)(PCWSTR)strUnescapedCanonicalName, &ptszPath))
  1415. {
  1416. REPORT_ERROR(E_OUTOFMEMORY, pPage->GetHWnd());
  1417. return E_OUTOFMEMORY;
  1418. }
  1419. SetDlgItemText(pPage->GetHWnd(), IDC_PATH_FIELD, ptszPath);
  1420. delete [] ptszPath;
  1421. }
  1422. return S_OK;
  1423. }