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.

1417 lines
42 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 2000
  6. //
  7. // File: cpview.cpp
  8. //
  9. // This module provides the Control Panel user interface information
  10. // to the shell through the ICplView interface. The ICplView implementation
  11. // instantiates a CCplNamespace object through which it obtains the
  12. // display information on demand. CCplView then takes that information
  13. // and either makes it available to the shell for display in the webview
  14. // left-hand pane or generates a DUI element hierarchy for display in the
  15. // right-hand pane.
  16. //
  17. // The majority of the code is associated with building Direct UI content.
  18. //
  19. //--------------------------------------------------------------------------
  20. #include "shellprv.h"
  21. #include "cpviewp.h"
  22. #include "cpduihlp.h"
  23. #include "cpguids.h"
  24. #include "cplnkele.h"
  25. #include "cpnamespc.h"
  26. #include "cputil.h"
  27. #include "ids.h"
  28. #include "shstyle.h"
  29. #include <uxtheme.h>
  30. namespace CPL {
  31. class CCplView : public CObjectWithSite,
  32. public ICplView,
  33. public IServiceProvider
  34. {
  35. public:
  36. ~CCplView(void);
  37. //
  38. // IUnknown
  39. //
  40. STDMETHOD(QueryInterface)(REFIID riid, void **ppv);
  41. STDMETHOD_(ULONG, AddRef)(void);
  42. STDMETHOD_(ULONG, Release)(void);
  43. //
  44. // ICplView
  45. //
  46. STDMETHOD(EnumClassicWebViewInfo)(DWORD dwFlags, IEnumCplWebViewInfo **ppenum);
  47. STDMETHOD(EnumCategoryChoiceWebViewInfo)(DWORD dwFlags, IEnumCplWebViewInfo **ppenum);
  48. STDMETHOD(EnumCategoryWebViewInfo)(DWORD dwFlags, eCPCAT eCategory, IEnumCplWebViewInfo **ppenum);
  49. STDMETHOD(CreateCategoryChoiceElement)(DUI::Element **ppe);
  50. STDMETHOD(CreateCategoryElement)(eCPCAT eCategory, DUI::Element **ppe);
  51. STDMETHOD(GetCategoryHelpURL)(eCPCAT eCategory, LPWSTR pszURL, UINT cchURL);
  52. STDMETHOD(RefreshIDs)(IEnumIDList *penumIDs);
  53. //
  54. // IServiceProvider
  55. //
  56. STDMETHOD(QueryService)(REFGUID guidService, REFIID riid, void **ppv);
  57. static HRESULT CreateInstance(IEnumIDList *penumIDs, IUnknown *punkSite, REFIID riid, void **ppvOut);
  58. private:
  59. LONG m_cRef;
  60. ICplNamespace *m_pns;
  61. CSafeServiceSite *m_psss;
  62. ATOM m_idDirective;
  63. ATOM m_idDirective2;
  64. ATOM m_idTitle;
  65. ATOM m_idIcon;
  66. ATOM m_idCategoryList;
  67. ATOM m_idCategoryTaskList;
  68. ATOM m_idAppletList;
  69. ATOM m_idBanner;
  70. ATOM m_idBarricadeTitle;
  71. ATOM m_idBarricadeMsg;
  72. ATOM m_idContainer;
  73. CCplView::CCplView(void);
  74. HRESULT _Initialize(IEnumIDList *penumIDs, IUnknown *punkSite);
  75. HRESULT _CreateCategoryChoiceElement(DUI::Element **ppe);
  76. HRESULT _CreateCategoryElement(ICplCategory *pCategory, DUI::Element **ppe);
  77. HRESULT _BuildCategoryBanner(ICplCategory *pCategory, DUI::Element *pePrimaryPane);
  78. HRESULT _BuildCategoryBarricade(DUI::Element *peRoot);
  79. HRESULT _BuildCategoryTaskList(DUI::Parser *pParser, ICplCategory *pCategory, DUI::Element *pePrimaryPane, int *pcTasks);
  80. HRESULT _BuildCategoryAppletList(DUI::Parser *pParser, ICplCategory *pCategory, DUI::Element *pePrimaryPane, int *pcApplets);
  81. HRESULT _CreateWatermark(DUI::Element *peRoot);
  82. HRESULT _CreateAndAddListItem(DUI::Parser *pParser, DUI::Element *peList, LPCWSTR pszItemTemplate, DUI::Value *pvSsListItem, IUICommand *puic, eCPIMGSIZE eIconSize);
  83. HRESULT _IncludeCategory(ICplCategory *pCategory) const;
  84. HRESULT _AddOrDeleteAtoms(bool bAdd);
  85. HRESULT _GetStyleModuleAndResId(HINSTANCE *phInstance, UINT *pidStyle);
  86. HRESULT _LoadUiFileFromResources(HINSTANCE hInstance, int idResource, char **ppUIFile);
  87. HRESULT _BuildUiFile(char **ppUIFile, int *piCharCount, HINSTANCE *phInstance);
  88. HRESULT _CreateUiFileParser(DUI::Parser **ppParser);
  89. eCPCAT _DisplayIndexToCategoryIndex(int iCategory) const;
  90. //
  91. // Prevent copy.
  92. //
  93. CCplView(const CCplView& rhs);
  94. CCplView& operator = (const CCplView& rhs);
  95. };
  96. CCplView::CCplView(
  97. void
  98. ) : m_cRef(1),
  99. m_pns(NULL),
  100. m_idDirective(0),
  101. m_idDirective2(0),
  102. m_idTitle(0),
  103. m_idIcon(0),
  104. m_idCategoryList(0),
  105. m_idCategoryTaskList(0),
  106. m_idAppletList(0),
  107. m_idBanner(0),
  108. m_idBarricadeTitle(0),
  109. m_idBarricadeMsg(0),
  110. m_idContainer(0),
  111. m_psss(NULL)
  112. {
  113. TraceMsg(TF_LIFE, "CCplView::CCplView, this = 0x%x", this);
  114. }
  115. CCplView::~CCplView(
  116. void
  117. )
  118. {
  119. TraceMsg(TF_LIFE, "CCplView::~CCplView, this = 0x%x", this);
  120. if (NULL != m_psss)
  121. {
  122. m_psss->SetProviderWeakRef(NULL);
  123. m_psss->Release();
  124. }
  125. if (NULL != m_pns)
  126. {
  127. IUnknown_SetSite(m_pns, NULL);
  128. m_pns->Release();
  129. }
  130. _AddOrDeleteAtoms(false);
  131. }
  132. HRESULT
  133. CCplView::CreateInstance( // [static]
  134. IEnumIDList *penumIDs,
  135. IUnknown *punkSite,
  136. REFIID riid,
  137. void **ppvOut
  138. )
  139. {
  140. ASSERT(NULL != penumIDs);
  141. ASSERT(NULL != ppvOut);
  142. ASSERT(!IsBadWritePtr(ppvOut, sizeof(*ppvOut)));
  143. *ppvOut = NULL;
  144. HRESULT hr = E_OUTOFMEMORY;
  145. CCplView* pv = new CCplView();
  146. if (NULL != pv)
  147. {
  148. hr = pv->_Initialize(penumIDs, punkSite);
  149. if (SUCCEEDED(hr))
  150. {
  151. hr = pv->QueryInterface(riid, ppvOut);
  152. if (SUCCEEDED(hr))
  153. {
  154. //
  155. // Set the site of the view to the site passed into the
  156. // instance generator. This is most likely the site of
  157. // the Control Panel folder view callback.
  158. //
  159. hr = IUnknown_SetSite(static_cast<IUnknown *>(*ppvOut), punkSite);
  160. }
  161. }
  162. pv->Release();
  163. }
  164. return THR(hr);
  165. }
  166. STDMETHODIMP
  167. CCplView::QueryInterface(
  168. REFIID riid,
  169. void **ppv
  170. )
  171. {
  172. ASSERT(NULL != ppv);
  173. ASSERT(!IsBadWritePtr(ppv, sizeof(*ppv)));
  174. static const QITAB qit[] = {
  175. QITABENT(CCplView, ICplView),
  176. QITABENT(CCplView, IObjectWithSite),
  177. QITABENT(CCplView, IServiceProvider),
  178. { 0 },
  179. };
  180. HRESULT hr = QISearch(this, qit, riid, ppv);
  181. return E_NOINTERFACE == hr ? hr : THR(hr);
  182. }
  183. STDMETHODIMP_(ULONG)
  184. CCplView::AddRef(
  185. void
  186. )
  187. {
  188. ULONG cRef = InterlockedIncrement(&m_cRef);
  189. TraceMsg(TF_LIFE, "CCplView::AddRef %d->%d", cRef - 1, cRef);
  190. return cRef;
  191. }
  192. STDMETHODIMP_(ULONG)
  193. CCplView::Release(
  194. void
  195. )
  196. {
  197. ASSERT( 0 != m_cRef );
  198. ULONG cRef = InterlockedDecrement(&m_cRef);
  199. TraceMsg(TF_LIFE, "CCplView::Release %d<-%d", cRef, cRef+1);
  200. if ( 0 == cRef )
  201. {
  202. delete this;
  203. }
  204. return cRef;
  205. }
  206. STDMETHODIMP
  207. CCplView::QueryService(
  208. REFGUID guidService,
  209. REFIID riid,
  210. void **ppv
  211. )
  212. {
  213. DBG_ENTER(FTF_CPANEL, "CCplView::QueryService");
  214. HRESULT hr = E_NOINTERFACE;
  215. if (SID_SControlPanelView == guidService)
  216. {
  217. TraceMsg(TF_CPANEL, "SID_SControlPanelView service requested");
  218. if (IID_ICplNamespace == riid)
  219. {
  220. TraceMsg(TF_CPANEL, "SID_SControlPanelView::IID_ICplNamespace requested");
  221. ASSERT(NULL != m_pns);
  222. hr = m_pns->QueryInterface(IID_ICplNamespace, ppv);
  223. }
  224. else if (IID_ICplView == riid)
  225. {
  226. TraceMsg(TF_CPANEL, "SID_SControlPanelView::IID_ICplView requested");
  227. ASSERT(NULL != m_pns);
  228. hr = this->QueryInterface(IID_ICplView, ppv);
  229. }
  230. }
  231. else
  232. {
  233. //
  234. // Most likely a command object requesting SID_STopLevelBrowser.
  235. //
  236. TraceMsg(TF_CPANEL, "Handing service request to view's site.");
  237. ASSERT(NULL != _punkSite);
  238. hr = IUnknown_QueryService(_punkSite, guidService, riid, ppv);
  239. }
  240. DBG_EXIT_HRES(FTF_CPANEL, "CCplView::QueryService", hr);
  241. return THR(hr);
  242. }
  243. STDMETHODIMP
  244. CCplView::EnumClassicWebViewInfo(
  245. DWORD dwFlags,
  246. IEnumCplWebViewInfo **ppenum
  247. )
  248. {
  249. DBG_ENTER(FTF_CPANEL, "CCplView::EnumClassicWebViewInfo");
  250. ASSERT(NULL != ppenum);
  251. ASSERT(!IsBadWritePtr(ppenum, sizeof(*ppenum)));
  252. ASSERT(NULL != m_pns);
  253. HRESULT hr = m_pns->EnumClassicWebViewInfo(dwFlags, ppenum);
  254. DBG_EXIT_HRES(FTF_CPANEL, "CCplView::EnumClassicWebViewInfo", hr);
  255. return THR(hr);
  256. }
  257. //
  258. // Returns an enumerator for webview info associated with
  259. // the category 'choice' page.
  260. //
  261. STDMETHODIMP
  262. CCplView::EnumCategoryChoiceWebViewInfo(
  263. DWORD dwFlags,
  264. IEnumCplWebViewInfo **ppenum
  265. )
  266. {
  267. DBG_ENTER(FTF_CPANEL, "CCplView::EnumCategoryChoiceWebViewInfo");
  268. ASSERT(NULL != ppenum);
  269. ASSERT(!IsBadWritePtr(ppenum, sizeof(*ppenum)));
  270. ASSERT(NULL != m_pns);
  271. HRESULT hr = m_pns->EnumWebViewInfo(dwFlags, ppenum);
  272. DBG_EXIT_HRES(FTF_CPANEL, "CCplView::EnumCategoryChoiceWebViewInfo", hr);
  273. return THR(hr);
  274. }
  275. //
  276. // Returns an enumerator for webview info associated with
  277. // a given category page.
  278. //
  279. STDMETHODIMP
  280. CCplView::EnumCategoryWebViewInfo(
  281. DWORD dwFlags,
  282. eCPCAT eCategory,
  283. IEnumCplWebViewInfo **ppenum
  284. )
  285. {
  286. DBG_ENTER(FTF_CPANEL, "CCplView::EnumCategoryWebViewInfo");
  287. ASSERT(NULL != ppenum);
  288. ASSERT(!IsBadWritePtr(ppenum, sizeof(*ppenum)));
  289. ASSERT(NULL != m_pns);
  290. ICplCategory *pCategory;
  291. HRESULT hr = m_pns->GetCategory(eCategory, &pCategory);
  292. if (SUCCEEDED(hr))
  293. {
  294. hr = pCategory->EnumWebViewInfo(dwFlags, ppenum);
  295. ATOMICRELEASE(pCategory);
  296. }
  297. DBG_EXIT_HRES(FTF_CPANEL, "CCplView::EnumCategoryWebViewInfo", hr);
  298. return THR(hr);
  299. }
  300. //
  301. // Creates the DUI element tree for the category 'choice'
  302. // page. Returns the root of the tree.
  303. //
  304. STDMETHODIMP
  305. CCplView::CreateCategoryChoiceElement(
  306. DUI::Element **ppe
  307. )
  308. {
  309. DBG_ENTER(FTF_CPANEL, "CCplView::CreateCategoryChoiceElement");
  310. ASSERT(NULL != ppe);
  311. ASSERT(!IsBadWritePtr(ppe, sizeof(*ppe)));
  312. HRESULT hr = _CreateCategoryChoiceElement(ppe);
  313. DBG_EXIT_HRES(FTF_CPANEL, "CCplView::CreateCategoryChoiceElement", hr);
  314. return THR(hr);
  315. }
  316. //
  317. // Creates the DUI element tree for a given category page.
  318. // Returns the root of the tree.
  319. //
  320. STDMETHODIMP
  321. CCplView::CreateCategoryElement(
  322. eCPCAT eCategory,
  323. DUI::Element **ppe
  324. )
  325. {
  326. DBG_ENTER(FTF_CPANEL, "CCplView::CreateCategoryElement");
  327. TraceMsg(TF_CPANEL, "Category ID = %d", eCategory);
  328. ASSERT(NULL != ppe);
  329. ASSERT(!IsBadWritePtr(ppe, sizeof(*ppe)));
  330. ASSERT(NULL != m_pns);
  331. ICplCategory *pCategory;
  332. HRESULT hr = m_pns->GetCategory(eCategory, &pCategory);
  333. if (SUCCEEDED(hr))
  334. {
  335. hr = _CreateCategoryElement(pCategory, ppe);
  336. ATOMICRELEASE(pCategory);
  337. }
  338. DBG_EXIT_HRES(FTF_CPANEL, "CCplView::CreateCategoryElement", hr);
  339. return THR(hr);
  340. }
  341. STDMETHODIMP
  342. CCplView::GetCategoryHelpURL(
  343. CPL::eCPCAT eCategory,
  344. LPWSTR pszURL,
  345. UINT cchURL
  346. )
  347. {
  348. DBG_ENTER(FTF_CPANEL, "CCplView::GetCategoryHelpURL");
  349. ASSERT(NULL != pszURL);
  350. ASSERT(!IsBadWritePtr(pszURL, cchURL * sizeof(*pszURL)));
  351. ICplCategory *pCategory;
  352. HRESULT hr = m_pns->GetCategory(eCategory, &pCategory);
  353. if (SUCCEEDED(hr))
  354. {
  355. hr = pCategory->GetHelpURL(pszURL, cchURL);
  356. ATOMICRELEASE(pCategory);
  357. }
  358. DBG_EXIT_HRES(FTF_CPANEL, "CCplView::GetCategoryHelpURL", hr);
  359. return THR(hr);
  360. }
  361. STDMETHODIMP
  362. CCplView::RefreshIDs(
  363. IEnumIDList *penumIDs
  364. )
  365. {
  366. DBG_ENTER(FTF_CPANEL, "CCplView::RefreshIDs");
  367. ASSERT(NULL != m_pns);
  368. //
  369. // This will cause the namespace object to reset it's internal
  370. // list of item IDs. This results in a re-categorization of
  371. // applets such that all information returned by the namespace
  372. // will now reflect the new set of folder items.
  373. //
  374. HRESULT hr = m_pns->RefreshIDs(penumIDs);
  375. DBG_EXIT_HRES(FTF_CPANEL, "CCplView::RefreshIDs", hr);
  376. return THR(hr);
  377. }
  378. HRESULT
  379. CCplView::_Initialize(
  380. IEnumIDList *penumIDs,
  381. IUnknown *punkSite
  382. )
  383. {
  384. ASSERT(NULL == m_pns);
  385. ASSERT(NULL != penumIDs);
  386. HRESULT hr = E_OUTOFMEMORY;
  387. //
  388. // We use this weak-reference implementation of IServiceProvider
  389. // as described by ZekeL in shell\inc\cowsite.h. A strong reference
  390. // would create a circular reference cycle between children of the
  391. // view and the view itself, preventing the view's destruction.
  392. // This weak-reference implementation is designed specifically
  393. // for this case.
  394. //
  395. ASSERT(NULL == m_psss);
  396. m_psss = new CSafeServiceSite();
  397. if (NULL != m_psss)
  398. {
  399. hr = m_psss->SetProviderWeakRef(this);
  400. if (SUCCEEDED(hr))
  401. {
  402. hr = CplNamespace_CreateInstance(penumIDs, CPL::IID_ICplNamespace, (void **)&m_pns);
  403. if (SUCCEEDED(hr))
  404. {
  405. IUnknown *punkSafeSite;
  406. hr = m_psss->QueryInterface(IID_IUnknown, (void **)&punkSafeSite);
  407. if (SUCCEEDED(hr))
  408. {
  409. //
  410. // Site the namespace object to the view.
  411. // By doing this, all command objects created by the namespace will
  412. // QueryService on the view object. If the view doesn't support
  413. // the requested service, it will query it's site.
  414. // We use this so that command objects can query the view for
  415. // IID_ICplNamespace and gather information on the namespace
  416. // if necessary.
  417. //
  418. hr = IUnknown_SetSite(m_pns, punkSafeSite);
  419. if (SUCCEEDED(hr))
  420. {
  421. hr = _AddOrDeleteAtoms(true);
  422. }
  423. punkSafeSite->Release();
  424. }
  425. }
  426. }
  427. }
  428. return THR(hr);
  429. }
  430. HRESULT
  431. CCplView::_AddOrDeleteAtoms(
  432. bool bAdd
  433. )
  434. {
  435. struct CPL::ATOMINFO rgAtomInfo[] = {
  436. { L"directive", &m_idDirective },
  437. { L"directive2", &m_idDirective2 },
  438. { L"title", &m_idTitle },
  439. { L"icon", &m_idIcon },
  440. { L"categorylist", &m_idCategoryList },
  441. { L"categorytasklist", &m_idCategoryTaskList },
  442. { L"appletlist", &m_idAppletList },
  443. { L"banner", &m_idBanner },
  444. { L"barricadetitle", &m_idBarricadeTitle },
  445. { L"barricademsg", &m_idBarricadeMsg },
  446. { L"container", &m_idContainer }
  447. };
  448. HRESULT hr = Dui_AddOrDeleteAtoms(rgAtomInfo, ARRAYSIZE(rgAtomInfo), bAdd);
  449. return THR(hr);
  450. }
  451. //
  452. // Creates the DUI element tree for the category 'choice' page.
  453. // Returns the root element.
  454. //
  455. HRESULT
  456. CCplView::_CreateCategoryChoiceElement(
  457. DUI::Element **ppe
  458. )
  459. {
  460. DBG_ENTER(FTF_CPANEL, "CCplView::_CreateCategoryChoiceElement");
  461. ASSERT(NULL != ppe);
  462. ASSERT(!IsBadWritePtr(ppe, sizeof(*ppe)));
  463. ASSERT(NULL != m_pns);
  464. DUI::Element *peRoot = NULL;
  465. DUI::Parser *pParser;
  466. HRESULT hr = _CreateUiFileParser(&pParser);
  467. if (SUCCEEDED(hr))
  468. {
  469. hr = Dui_CreateElement(pParser, L"CategoryList", NULL, &peRoot);
  470. if (SUCCEEDED(hr))
  471. {
  472. hr = _CreateWatermark(peRoot);
  473. if (SUCCEEDED(hr))
  474. {
  475. CDuiValuePtr pvSsCategoryListItem;
  476. hr = Dui_GetStyleSheet(pParser, L"CategoryListItemSS", &pvSsCategoryListItem);
  477. if (SUCCEEDED(hr))
  478. {
  479. //
  480. // Set the "Pick a category..." title.
  481. //
  482. hr = Dui_SetDescendentElementText(peRoot,
  483. L"directive",
  484. MAKEINTRESOURCEW(IDS_CP_PICKCATEGORY));
  485. if (SUCCEEDED(hr))
  486. {
  487. //
  488. // Build the list of categories.
  489. //
  490. DUI::Element *peCategoryList;
  491. hr = Dui_FindDescendent(peRoot, L"categorylist", &peCategoryList);
  492. if (SUCCEEDED(hr))
  493. {
  494. for (int i = 0; SUCCEEDED(hr) && i < int(eCPCAT_NUMCATEGORIES); i++)
  495. {
  496. ICplCategory *pCategory;
  497. hr = m_pns->GetCategory(_DisplayIndexToCategoryIndex(i), &pCategory);
  498. if (SUCCEEDED(hr))
  499. {
  500. if (S_OK == _IncludeCategory(pCategory))
  501. {
  502. IUICommand *puic;
  503. hr = pCategory->GetUiCommand(&puic);
  504. if (SUCCEEDED(hr))
  505. {
  506. hr = _CreateAndAddListItem(pParser,
  507. peCategoryList,
  508. L"CategoryLink",
  509. pvSsCategoryListItem,
  510. puic,
  511. eCPIMGSIZE_CATEGORY);
  512. ATOMICRELEASE(puic);
  513. }
  514. }
  515. ATOMICRELEASE(pCategory);
  516. }
  517. }
  518. }
  519. }
  520. }
  521. }
  522. }
  523. pParser->Destroy();
  524. }
  525. *ppe = peRoot;
  526. DBG_EXIT_HRES(FTF_CPANEL, "CCplView::_CreateCategoryChoiceElement", hr);
  527. return THR(hr);
  528. }
  529. //
  530. // Creates the DUI element tree for a given category page.
  531. // Returns the root element.
  532. //
  533. HRESULT
  534. CCplView::_CreateCategoryElement(
  535. ICplCategory *pCategory,
  536. DUI::Element **ppe
  537. )
  538. {
  539. DBG_ENTER(FTF_CPANEL, "CCplView::_CreateCategoryElement");
  540. ASSERT(NULL != pCategory);
  541. ASSERT(NULL != ppe);
  542. ASSERT(!IsBadWritePtr(ppe, sizeof(*ppe)));
  543. ASSERT(NULL != m_pns);
  544. DUI::Element *peRoot = NULL;
  545. DUI::Parser *pParser;
  546. HRESULT hr = _CreateUiFileParser(&pParser);
  547. if (SUCCEEDED(hr))
  548. {
  549. hr = Dui_CreateElement(pParser, L"CategoryView", NULL, &peRoot);
  550. if (SUCCEEDED(hr))
  551. {
  552. hr = _CreateWatermark(peRoot);
  553. if (SUCCEEDED(hr))
  554. {
  555. int cTasks = 0;
  556. int cApplets = 0;
  557. hr = _BuildCategoryBanner(pCategory, peRoot);
  558. if (SUCCEEDED(hr))
  559. {
  560. hr = _BuildCategoryTaskList(pParser, pCategory, peRoot, &cTasks);
  561. if (SUCCEEDED(hr))
  562. {
  563. hr = _BuildCategoryAppletList(pParser, pCategory, peRoot, &cApplets);
  564. }
  565. }
  566. if (SUCCEEDED(hr))
  567. {
  568. if (0 == cTasks && 0 == cApplets)
  569. {
  570. //
  571. // No tasks or applets. Display a message explaining
  572. // that the content has been made unavailable by the system
  573. // administrator.
  574. //
  575. hr = _BuildCategoryBarricade(peRoot);
  576. }
  577. else
  578. {
  579. //
  580. // Delete the barricade DUI elements. They're unused.
  581. //
  582. THR(Dui_DestroyDescendentElement(peRoot, L"barricadetitle"));
  583. THR(Dui_DestroyDescendentElement(peRoot, L"barricademsg"));
  584. //
  585. // Set the text in the 'directive' text elements.
  586. //
  587. if (0 < cTasks)
  588. {
  589. //
  590. // We've displayed a list of tasks.
  591. // Set the "Pick a task..." title.
  592. //
  593. hr = Dui_SetDescendentElementText(peRoot,
  594. L"directive",
  595. MAKEINTRESOURCEW(IDS_CP_PICKTASK));
  596. }
  597. if (SUCCEEDED(hr))
  598. {
  599. if (0 < cApplets)
  600. {
  601. //
  602. // We've displayed a list of applets. Display one of the
  603. // following directives based on the existance of a task
  604. // list above.
  605. //
  606. // Task list? Directive
  607. // ------------- ---------------------------
  608. // Yes "or pick a Control Panel icon"
  609. // No "Pick a Control Panel icon"
  610. //
  611. UINT idsDirective2 = IDS_CP_PICKICON;
  612. if (0 < cTasks)
  613. {
  614. idsDirective2 = IDS_CP_ORPICKICON;
  615. }
  616. hr = Dui_SetDescendentElementText(peRoot,
  617. L"directive2",
  618. MAKEINTRESOURCEW(idsDirective2));
  619. }
  620. }
  621. }
  622. }
  623. }
  624. }
  625. pParser->Destroy();
  626. }
  627. *ppe = peRoot;
  628. DBG_EXIT_HRES(FTF_CPANEL, "CCplView::_CreateCategoryElement", hr);
  629. return THR(hr);
  630. }
  631. //
  632. // Builds the 'barricade' that is displayed when a category has no
  633. // tasks or CPL applets to show.
  634. //
  635. HRESULT
  636. CCplView::_BuildCategoryBarricade(
  637. DUI::Element *peRoot
  638. )
  639. {
  640. DBG_ENTER(FTF_CPANEL, "CCplView::_BuildCategoryBarricade");
  641. HRESULT hr = Dui_SetDescendentElementText(peRoot,
  642. L"barricadetitle",
  643. MAKEINTRESOURCE(IDS_CP_CATEGORY_BARRICADE_TITLE));
  644. if (SUCCEEDED(hr))
  645. {
  646. hr = Dui_SetDescendentElementText(peRoot,
  647. L"barricademsg",
  648. MAKEINTRESOURCE(IDS_CP_CATEGORY_BARRICADE_MSG));
  649. }
  650. DBG_EXIT_HRES(FTF_CPANEL, "CCplView::_BuildCategoryBarricade", hr);
  651. return THR(hr);
  652. }
  653. //
  654. // Add the background watermark to the view if user is using a non-classic
  655. // theme.
  656. //
  657. HRESULT
  658. CCplView::_CreateWatermark(
  659. DUI::Element *peRoot
  660. )
  661. {
  662. DBG_ENTER(FTF_CPANEL, "CCplView::_CreateWatermark");
  663. ASSERT(NULL != peRoot);
  664. HINSTANCE hStyleModule;
  665. UINT idStyle;
  666. HRESULT hr = _GetStyleModuleAndResId(&hStyleModule, &idStyle);
  667. if (SUCCEEDED(hr))
  668. {
  669. HBITMAP hWatermark = (HBITMAP) LoadImage (hStyleModule, MAKEINTRESOURCE(IDB_CPANEL_WATERMARK),
  670. IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
  671. if (NULL != hWatermark)
  672. {
  673. //
  674. // Set watermark only on non-classic themes.
  675. //
  676. DUI::Element *peWatermark;
  677. hr = Dui_FindDescendent(peRoot, L"watermark", &peWatermark);
  678. if (SUCCEEDED(hr))
  679. {
  680. CDuiValuePtr ptrValue = DUI::Value::CreateGraphic(hWatermark,
  681. GRAPHIC_TransColor,
  682. 255);
  683. if (!ptrValue.IsNULL())
  684. {
  685. hr = Dui_SetElementProperty(peWatermark, ContentProp, ptrValue);
  686. peWatermark->SetContentAlign(CA_BottomRight);
  687. }
  688. else
  689. {
  690. hr = E_OUTOFMEMORY;
  691. DeleteObject (hWatermark);
  692. }
  693. }
  694. else
  695. {
  696. DeleteObject (hWatermark);
  697. }
  698. FreeLibrary(hStyleModule);
  699. }
  700. else
  701. {
  702. //
  703. // If 'classic' theme, do nothing.
  704. //
  705. hr = S_FALSE;
  706. }
  707. }
  708. DBG_EXIT_HRES(FTF_CPANEL, "CCplView::_CreateWatermark", hr);
  709. return THR(hr);
  710. }
  711. //
  712. // Builds the banner for a category page.
  713. //
  714. HRESULT
  715. CCplView::_BuildCategoryBanner(
  716. ICplCategory *pCategory,
  717. DUI::Element *pePrimaryPane
  718. )
  719. {
  720. DBG_ENTER(FTF_CPANEL, "CCplView::_BuildCategoryBanner");
  721. ASSERT(NULL != pCategory);
  722. ASSERT(NULL != pePrimaryPane);
  723. IUICommand *puic;
  724. HRESULT hr = pCategory->GetUiCommand(&puic);
  725. if (SUCCEEDED(hr))
  726. {
  727. ICpUiElementInfo *pei;
  728. hr = puic->QueryInterface(IID_ICpUiElementInfo, (void **)&pei);
  729. if (SUCCEEDED(hr))
  730. {
  731. DUI::Element *peBanner;
  732. hr = Dui_FindDescendent(pePrimaryPane, L"banner", &peBanner);
  733. if (SUCCEEDED(hr))
  734. {
  735. //
  736. // Create the title text.
  737. //
  738. LPWSTR pszTitle;
  739. hr = pei->LoadName(&pszTitle);
  740. if (SUCCEEDED(hr))
  741. {
  742. hr = Dui_SetDescendentElementText(peBanner, L"title", pszTitle);
  743. CoTaskMemFree(pszTitle);
  744. }
  745. if (SUCCEEDED(hr))
  746. {
  747. //
  748. // Create the icon.
  749. //
  750. HICON hIcon;
  751. hr = pei->LoadIcon(eCPIMGSIZE_BANNER, &hIcon);
  752. if (SUCCEEDED(hr))
  753. {
  754. hr = Dui_SetDescendentElementIcon(peBanner, L"icon", hIcon);
  755. if (FAILED(hr))
  756. {
  757. DestroyIcon(hIcon);
  758. }
  759. }
  760. }
  761. }
  762. ATOMICRELEASE(pei);
  763. }
  764. ATOMICRELEASE(puic);
  765. }
  766. DBG_EXIT_HRES(FTF_CPANEL, "CCplView::_BuildCategoryBanner", hr);
  767. return THR(hr);
  768. }
  769. //
  770. // Builds the list of tasks for a category page.
  771. //
  772. HRESULT
  773. CCplView::_BuildCategoryTaskList(
  774. DUI::Parser *pParser,
  775. ICplCategory *pCategory,
  776. DUI::Element *pePrimaryPane,
  777. int *pcTasks
  778. )
  779. {
  780. DBG_ENTER(FTF_CPANEL, "CCplView::_BuildCategoryTaskList");
  781. ASSERT(NULL != pCategory);
  782. ASSERT(NULL != pePrimaryPane);
  783. ASSERT(NULL != m_pns);
  784. ASSERT(NULL != pParser);
  785. int cTasks = 0;
  786. DUI::Element *peCategoryTaskList;
  787. HRESULT hr = Dui_FindDescendent(pePrimaryPane, L"categorytasklist", &peCategoryTaskList);
  788. if (SUCCEEDED(hr))
  789. {
  790. CDuiValuePtr pvStyleSheet;
  791. hr = Dui_GetStyleSheet(pParser, L"CategoryTaskListItemSS", &pvStyleSheet);
  792. if (SUCCEEDED(hr))
  793. {
  794. IEnumUICommand *peuic;
  795. hr = pCategory->EnumTasks(&peuic);
  796. if (SUCCEEDED(hr))
  797. {
  798. IUICommand *puic;
  799. while(S_OK == (hr = peuic->Next(1, &puic, NULL)))
  800. {
  801. hr = _CreateAndAddListItem(pParser,
  802. peCategoryTaskList,
  803. L"TaskLink",
  804. pvStyleSheet,
  805. puic,
  806. eCPIMGSIZE_TASK);
  807. if (SUCCEEDED(hr))
  808. {
  809. cTasks++;
  810. }
  811. ATOMICRELEASE(puic);
  812. }
  813. ATOMICRELEASE(peuic);
  814. }
  815. }
  816. }
  817. if (NULL != pcTasks)
  818. {
  819. ASSERT(!IsBadWritePtr(pcTasks, sizeof(*pcTasks)));
  820. *pcTasks = cTasks;
  821. }
  822. DBG_EXIT_HRES(FTF_CPANEL, "CCplView::_BuildCategoryTaskList", hr);
  823. return THR(hr);
  824. }
  825. //
  826. // Builds the list of CPL applets for a category page.
  827. //
  828. HRESULT
  829. CCplView::_BuildCategoryAppletList(
  830. DUI::Parser *pParser,
  831. ICplCategory *pCategory,
  832. DUI::Element *pePrimaryPane,
  833. int *pcApplets
  834. )
  835. {
  836. DBG_ENTER(FTF_CPANEL, "CCplView::_BuildCategoryAppletList");
  837. ASSERT(NULL != pCategory);
  838. ASSERT(NULL != pePrimaryPane);
  839. ASSERT(NULL != pParser);
  840. int cApplets = 0;
  841. DUI::Element *peAppletList;
  842. HRESULT hr = Dui_FindDescendent(pePrimaryPane, L"appletlist", &peAppletList);
  843. if (SUCCEEDED(hr))
  844. {
  845. CDuiValuePtr pvStyleSheet;
  846. hr = Dui_GetStyleSheet(pParser, L"CategoryTaskListItemSS", &pvStyleSheet);
  847. if (SUCCEEDED(hr))
  848. {
  849. IEnumUICommand *peuicApplets;
  850. hr = pCategory->EnumCplApplets(&peuicApplets);
  851. if (SUCCEEDED(hr))
  852. {
  853. IUICommand *puicApplet;
  854. while(S_OK == (hr = peuicApplets->Next(1, &puicApplet, NULL)))
  855. {
  856. hr = _CreateAndAddListItem(pParser,
  857. peAppletList,
  858. L"AppletLink",
  859. pvStyleSheet,
  860. puicApplet,
  861. eCPIMGSIZE_APPLET);
  862. if (SUCCEEDED(hr))
  863. {
  864. cApplets++;
  865. }
  866. ATOMICRELEASE(puicApplet);
  867. }
  868. ATOMICRELEASE(peuicApplets);
  869. }
  870. }
  871. }
  872. if (NULL != pcApplets)
  873. {
  874. ASSERT(!IsBadWritePtr(pcApplets, sizeof(*pcApplets)));
  875. *pcApplets = cApplets;
  876. }
  877. DBG_EXIT_HRES(FTF_CPANEL, "CCplView::_BuildCategoryAppletList", hr);
  878. return THR(hr);
  879. }
  880. //
  881. // Helper for adding link element to the view.
  882. //
  883. HRESULT
  884. CCplView::_CreateAndAddListItem(
  885. DUI::Parser *pParser,
  886. DUI::Element *peList, // List inserting into.
  887. LPCWSTR pszItemTemplate, // Name of template in UI file.
  888. DUI::Value *pvSsListItem, // Style sheet for new list item
  889. IUICommand *puic, // The new item's link object.
  890. eCPIMGSIZE eIconSize // Desired size of item icon.
  891. )
  892. {
  893. DBG_ENTER(FTF_CPANEL, "CCplView::_CreateAndAddListItem");
  894. ASSERT(NULL != pParser);
  895. ASSERT(NULL != peList);
  896. ASSERT(NULL != pvSsListItem);
  897. ASSERT(NULL != puic);
  898. ASSERT(NULL != pszItemTemplate);
  899. DUI::Element *peListItem;
  900. HRESULT hr = Dui_CreateElement(pParser, pszItemTemplate, NULL, &peListItem);
  901. if (SUCCEEDED(hr))
  902. {
  903. if (NULL != pvSsListItem)
  904. {
  905. hr = Dui_SetElementStyleSheet(peListItem, pvSsListItem);
  906. }
  907. if (SUCCEEDED(hr))
  908. {
  909. ASSERTMSG(peListItem->GetClassInfo() == CLinkElement::Class, "CCplView::_CreateAndAddListItem didn't get a CLinkElement::Class object (%s)", peListItem->GetClassInfo()->GetName());
  910. CLinkElement *pLinkEle = static_cast<CLinkElement *>(peListItem);
  911. hr = pLinkEle->Initialize(puic, eIconSize);
  912. if (SUCCEEDED(hr))
  913. {
  914. if (SUCCEEDED(hr))
  915. {
  916. hr = peList->Add(peListItem);
  917. if (SUCCEEDED(hr))
  918. {
  919. peListItem = NULL;
  920. }
  921. }
  922. }
  923. if (NULL != peListItem)
  924. {
  925. peListItem->Destroy();
  926. }
  927. }
  928. }
  929. DBG_EXIT_HRES(FTF_CPANEL, "CCplView::_CreateAndAddListItem", hr);
  930. return THR(hr);
  931. }
  932. //
  933. // Determine if a given category item should be shown in the UI.
  934. //
  935. // Returns:
  936. // S_OK - Include the item.
  937. // S_FALSE - Do not include the item.
  938. // Error - Cannot determine.
  939. //
  940. HRESULT
  941. CCplView::_IncludeCategory(
  942. ICplCategory *pCategory
  943. ) const
  944. {
  945. HRESULT hr = S_OK; // Assume it's included.
  946. //
  947. // If a category link invokes a restricted operation,
  948. // hide it from the UI.
  949. //
  950. IUICommand *puic;
  951. hr = pCategory->GetUiCommand(&puic);
  952. if (SUCCEEDED(hr))
  953. {
  954. UISTATE uis;
  955. hr = puic->get_State(NULL, TRUE, &uis);
  956. if (SUCCEEDED(hr))
  957. {
  958. if (UIS_HIDDEN == uis)
  959. {
  960. hr = S_FALSE;
  961. }
  962. }
  963. ATOMICRELEASE(puic);
  964. }
  965. return THR(hr);
  966. }
  967. //
  968. // Map a category display index to a category index in the
  969. // namespace. Categories in the namespace are ordered to match up
  970. // with the various category IDs. The view may be (and is) ordered
  971. // differently and is subject to change based on usability feedback.
  972. //
  973. eCPCAT
  974. CCplView::_DisplayIndexToCategoryIndex(
  975. int iCategory
  976. ) const
  977. {
  978. //
  979. // This array determins the order the categories are displayed
  980. // in the category selection view. To change the display order,
  981. // simply reorder these entries.
  982. //
  983. static const eCPCAT rgMap[] = { // Position in DUI grid control
  984. eCPCAT_APPEARANCE, // Row 0, Col 0
  985. eCPCAT_HARDWARE, // Row 0, Col 1
  986. eCPCAT_NETWORK, // Row 1, Col 0
  987. eCPCAT_ACCOUNTS, // Row 1, Col 1
  988. eCPCAT_ARP, // Row 2, Col 0
  989. eCPCAT_REGIONAL, // Row 2, Col 1
  990. eCPCAT_SOUND, // Row 3, Col 0
  991. eCPCAT_ACCESSIBILITY, // Row 3, Col 1
  992. eCPCAT_PERFMAINT, // Row 4, Col 0
  993. eCPCAT_OTHER // Row 4, Col 1
  994. };
  995. ASSERT(ARRAYSIZE(rgMap) == eCPCAT_NUMCATEGORIES);
  996. ASSERT(iCategory >= 0 && iCategory < ARRAYSIZE(rgMap));
  997. return rgMap[iCategory];
  998. }
  999. HRESULT
  1000. CCplView::_CreateUiFileParser(
  1001. DUI::Parser **ppParser
  1002. )
  1003. {
  1004. DBG_ENTER(FTF_CPANEL, "CCplView::_CreateUiFileParser");
  1005. ASSERT(NULL != ppParser);
  1006. ASSERT(!IsBadWritePtr(ppParser, sizeof(*ppParser)));
  1007. char *pszUiFile;
  1008. int cchUiFile;
  1009. HINSTANCE hInstance; // Instance containing resources referenced in UI file.
  1010. HRESULT hr = _BuildUiFile(&pszUiFile, &cchUiFile, &hInstance);
  1011. if (SUCCEEDED(hr))
  1012. {
  1013. hr = Dui_CreateParser(pszUiFile, cchUiFile, hInstance, ppParser);
  1014. LocalFree(pszUiFile);
  1015. if (HINST_THISDLL != hInstance)
  1016. {
  1017. ASSERT(NULL != hInstance);
  1018. FreeLibrary(hInstance);
  1019. }
  1020. }
  1021. DBG_EXIT(FTF_CPANEL, "CCplView::_CreateUiFileParser");
  1022. return THR(hr);
  1023. }
  1024. //
  1025. // Builds the UI file for this view from the
  1026. // appropriate base template + style sheet
  1027. //
  1028. // pUIFile receives a pointer to the ui file in memory
  1029. // piCharCount receives the size of the file
  1030. //
  1031. HRESULT
  1032. CCplView::_BuildUiFile(
  1033. char **ppUIFile,
  1034. int *piCharCount,
  1035. HINSTANCE *phInstance
  1036. )
  1037. {
  1038. DBG_ENTER(FTF_CPANEL, "CCplView::_BuildUiFile");
  1039. ASSERT(NULL != ppUIFile);
  1040. ASSERT(!IsBadWritePtr(ppUIFile, sizeof(*ppUIFile)));
  1041. ASSERT(NULL != phInstance);
  1042. ASSERT(!IsBadWritePtr(phInstance, sizeof(*phInstance)));
  1043. *phInstance = NULL;
  1044. //
  1045. // Load the 'structure' UI file
  1046. //
  1047. char *pStructure;
  1048. HRESULT hr = _LoadUiFileFromResources(HINST_THISDLL, IDR_DUI_CPVIEW, &pStructure);
  1049. if (SUCCEEDED(hr))
  1050. {
  1051. HINSTANCE hStyleModule;
  1052. UINT idStyle;
  1053. hr = _GetStyleModuleAndResId(&hStyleModule, &idStyle);
  1054. if (SUCCEEDED(hr))
  1055. {
  1056. //
  1057. // Load the style sheet. First, check if the current theme has a style sheet,
  1058. // if not, use the default style sheet in the resources.
  1059. //
  1060. char *pStyle;
  1061. hr = _LoadUiFileFromResources(hStyleModule, idStyle, &pStyle);
  1062. if (SUCCEEDED(hr))
  1063. {
  1064. const int cbStyle = lstrlenA(pStyle);
  1065. const int cbStructure = lstrlenA(pStructure);
  1066. char *pResult = (char *)LocalAlloc(LPTR, cbStyle + cbStructure + 1);
  1067. if (pResult)
  1068. {
  1069. //
  1070. // Put the resouces together (style + structure)
  1071. //
  1072. CopyMemory(pResult, pStyle, cbStyle);
  1073. CopyMemory(pResult + cbStyle, pStructure, cbStructure);
  1074. ASSERT(cbStructure + cbStyle == lstrlenA(pResult));
  1075. *ppUIFile = pResult;
  1076. //
  1077. // This count is ANSI chars so we can use byte counts
  1078. // directly.
  1079. //
  1080. *piCharCount = cbStructure + cbStyle;
  1081. *phInstance = hStyleModule;
  1082. //
  1083. // Indicate that HINSTANCE is being returned to caller.
  1084. //
  1085. hStyleModule = NULL;
  1086. }
  1087. else
  1088. {
  1089. hr = E_OUTOFMEMORY;
  1090. }
  1091. LocalFree(pStyle);
  1092. }
  1093. if (NULL != hStyleModule && HINST_THISDLL != hStyleModule)
  1094. {
  1095. //
  1096. // Something failed. Need to free style module
  1097. // if it's not shell32.dll.
  1098. //
  1099. FreeLibrary(hStyleModule);
  1100. }
  1101. }
  1102. LocalFree(pStructure);
  1103. }
  1104. DBG_EXIT_HRES(FTF_CPANEL, "CCplView::_BuildUiFile", hr);
  1105. return THR(hr);
  1106. }
  1107. HRESULT
  1108. CCplView::_GetStyleModuleAndResId(
  1109. HINSTANCE *phInstance,
  1110. UINT *pidStyle
  1111. )
  1112. {
  1113. DBG_ENTER(FTF_CPANEL, "CCplView::_GetStyleModuleAndResId");
  1114. ASSERT(NULL != phInstance);
  1115. ASSERT(!IsBadWritePtr(phInstance, sizeof(*phInstance)));
  1116. ASSERT(NULL != pidStyle);
  1117. ASSERT(!IsBadWritePtr(pidStyle, sizeof(*pidStyle)));
  1118. HRESULT hr = S_OK;
  1119. *phInstance = NULL;
  1120. HINSTANCE hThemeModule = SHGetShellStyleHInstance();
  1121. if (NULL != hThemeModule)
  1122. {
  1123. *pidStyle = IDR_DUI_CPSTYLE;
  1124. *phInstance = hThemeModule;
  1125. }
  1126. else
  1127. {
  1128. TraceMsg(TF_CPANEL, "Error %d loading theme file", GetLastError());
  1129. hr = ResultFromLastError();
  1130. }
  1131. DBG_EXIT_HRES(FTF_CPANEL, "CCplView::_GetStyleModuleAndResId", hr);
  1132. return THR(hr);
  1133. }
  1134. //
  1135. // Loads the requested UI file from a module's resources.
  1136. //
  1137. // iID - UI file id
  1138. // pUIFile - receives a pointer to the UI file
  1139. //
  1140. HRESULT
  1141. CCplView::_LoadUiFileFromResources(
  1142. HINSTANCE hInstance,
  1143. int idResource,
  1144. char **ppUIFile
  1145. )
  1146. {
  1147. DBG_ENTER(FTF_CPANEL, "CCplView::_LoadUiFileFromResources");
  1148. ASSERT(NULL != ppUIFile);
  1149. ASSERT(!IsBadWritePtr(ppUIFile, sizeof(*ppUIFile)));
  1150. HRESULT hr = E_FAIL;
  1151. *ppUIFile = NULL;
  1152. HRSRC hFile = FindResourceW(hInstance, MAKEINTRESOURCEW(idResource), L"UIFILE");
  1153. if (hFile)
  1154. {
  1155. HGLOBAL hResource = LoadResource(hInstance, hFile);
  1156. if (hResource)
  1157. {
  1158. char *pFile = (char *)LockResource(hResource);
  1159. if (pFile)
  1160. {
  1161. DWORD dwSize = SizeofResource(hInstance, hFile);
  1162. //
  1163. // Include one extra byte for a terminating nul character.
  1164. // We're loading text and want it to be nul-terminated.
  1165. //
  1166. *ppUIFile = (char *)LocalAlloc(LPTR, dwSize + 1);
  1167. if (NULL != *ppUIFile)
  1168. {
  1169. CopyMemory(*ppUIFile, pFile, dwSize);
  1170. hr = S_OK;
  1171. }
  1172. else
  1173. {
  1174. hr = E_OUTOFMEMORY;
  1175. }
  1176. }
  1177. else
  1178. {
  1179. hr = ResultFromLastError();
  1180. }
  1181. }
  1182. else
  1183. {
  1184. hr = ResultFromLastError();
  1185. }
  1186. }
  1187. else
  1188. {
  1189. hr = ResultFromLastError();
  1190. }
  1191. DBG_EXIT_HRES(FTF_CPANEL, "CCplView::_LoadUiFileFromResources", hr);
  1192. return THR(hr);
  1193. }
  1194. HRESULT
  1195. CPL::CplView_CreateInstance(
  1196. IEnumIDList *penumIDs,
  1197. IUnknown *punkSite,
  1198. REFIID riid,
  1199. void **ppvOut
  1200. )
  1201. {
  1202. HRESULT hr = CCplView::CreateInstance(penumIDs, punkSite, riid, ppvOut);
  1203. return THR(hr);
  1204. }
  1205. HRESULT
  1206. CplView_GetCategoryTitle(
  1207. eCPCAT eCategory,
  1208. LPWSTR pszTitle,
  1209. UINT cchTitle
  1210. )
  1211. {
  1212. ASSERT(NULL != pszTitle);
  1213. ASSERT(!IsBadWritePtr(pszTitle, cchTitle * sizeof(*pszTitle)));
  1214. //
  1215. // These must remain in the same order as the eCPCAT_XXXXX enumeration.
  1216. //
  1217. static const UINT rgid[] = {
  1218. IDS_CPCAT_OTHERCPLS_TITLE,
  1219. IDS_CPCAT_APPEARANCE_TITLE,
  1220. IDS_CPCAT_HARDWARE_TITLE,
  1221. IDS_CPCAT_NETWORK_TITLE,
  1222. IDS_CPCAT_SOUNDS_TITLE,
  1223. IDS_CPCAT_PERFMAINT_TITLE,
  1224. IDS_CPCAT_REGIONAL_TITLE,
  1225. IDS_CPCAT_ACCESSIBILITY_TITLE,
  1226. IDS_CPCAT_ARP_TITLE,
  1227. IDS_CPCAT_ACCOUNTS_TITLE
  1228. };
  1229. HRESULT hr = S_OK;
  1230. ASSERT(eCategory >= 0 && eCategory < eCPCAT_NUMCATEGORIES);
  1231. if (0 == LoadString(HINST_THISDLL, rgid[int(eCategory)], pszTitle, cchTitle))
  1232. {
  1233. hr = ResultFromLastError();
  1234. }
  1235. return THR(hr);
  1236. }
  1237. } // namespace CPL
  1238. HRESULT InitializeCPClasses()
  1239. {
  1240. HRESULT hr;
  1241. hr = CPL::CLinkElement::Register();
  1242. if (FAILED(hr))
  1243. goto Failure;
  1244. return S_OK;
  1245. Failure:
  1246. return hr;
  1247. }