Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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