//+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 2000 // // File: cpview.cpp // // This module provides the Control Panel user interface information // to the shell through the ICplView interface. The ICplView implementation // instantiates a CCplNamespace object through which it obtains the // display information on demand. CCplView then takes that information // and either makes it available to the shell for display in the webview // left-hand pane or generates a DUI element hierarchy for display in the // right-hand pane. // // The majority of the code is associated with building Direct UI content. // //-------------------------------------------------------------------------- #include "shellprv.h" #include "cpviewp.h" #include "cpduihlp.h" #include "cpguids.h" #include "cplnkele.h" #include "cpnamespc.h" #include "cputil.h" #include "ids.h" #include "shstyle.h" #include namespace CPL { class CCplView : public CObjectWithSite, public ICplView, public IServiceProvider { public: ~CCplView(void); // // IUnknown // STDMETHOD(QueryInterface)(REFIID riid, void **ppv); STDMETHOD_(ULONG, AddRef)(void); STDMETHOD_(ULONG, Release)(void); // // ICplView // STDMETHOD(EnumClassicWebViewInfo)(DWORD dwFlags, IEnumCplWebViewInfo **ppenum); STDMETHOD(EnumCategoryChoiceWebViewInfo)(DWORD dwFlags, IEnumCplWebViewInfo **ppenum); STDMETHOD(EnumCategoryWebViewInfo)(DWORD dwFlags, eCPCAT eCategory, IEnumCplWebViewInfo **ppenum); STDMETHOD(CreateCategoryChoiceElement)(DUI::Element **ppe); STDMETHOD(CreateCategoryElement)(eCPCAT eCategory, DUI::Element **ppe); STDMETHOD(GetCategoryHelpURL)(eCPCAT eCategory, LPWSTR pszURL, UINT cchURL); STDMETHOD(RefreshIDs)(IEnumIDList *penumIDs); // // IServiceProvider // STDMETHOD(QueryService)(REFGUID guidService, REFIID riid, void **ppv); static HRESULT CreateInstance(IEnumIDList *penumIDs, IUnknown *punkSite, REFIID riid, void **ppvOut); private: LONG m_cRef; ICplNamespace *m_pns; CSafeServiceSite *m_psss; ATOM m_idDirective; ATOM m_idDirective2; ATOM m_idTitle; ATOM m_idIcon; ATOM m_idCategoryList; ATOM m_idCategoryTaskList; ATOM m_idAppletList; ATOM m_idBanner; ATOM m_idBarricadeTitle; ATOM m_idBarricadeMsg; ATOM m_idContainer; CCplView::CCplView(void); HRESULT _Initialize(IEnumIDList *penumIDs, IUnknown *punkSite); HRESULT _CreateCategoryChoiceElement(DUI::Element **ppe); HRESULT _CreateCategoryElement(ICplCategory *pCategory, DUI::Element **ppe); HRESULT _BuildCategoryBanner(ICplCategory *pCategory, DUI::Element *pePrimaryPane); HRESULT _BuildCategoryBarricade(DUI::Element *peRoot); HRESULT _BuildCategoryTaskList(DUI::Parser *pParser, ICplCategory *pCategory, DUI::Element *pePrimaryPane, int *pcTasks); HRESULT _BuildCategoryAppletList(DUI::Parser *pParser, ICplCategory *pCategory, DUI::Element *pePrimaryPane, int *pcApplets); HRESULT _CreateWatermark(DUI::Element *peRoot); HRESULT _CreateAndAddListItem(DUI::Parser *pParser, DUI::Element *peList, LPCWSTR pszItemTemplate, DUI::Value *pvSsListItem, IUICommand *puic, eCPIMGSIZE eIconSize); HRESULT _IncludeCategory(ICplCategory *pCategory) const; HRESULT _AddOrDeleteAtoms(bool bAdd); HRESULT _GetStyleModuleAndResId(HINSTANCE *phInstance, UINT *pidStyle); HRESULT _LoadUiFileFromResources(HINSTANCE hInstance, int idResource, char **ppUIFile); HRESULT _BuildUiFile(char **ppUIFile, int *piCharCount, HINSTANCE *phInstance); HRESULT _CreateUiFileParser(DUI::Parser **ppParser); eCPCAT _DisplayIndexToCategoryIndex(int iCategory) const; // // Prevent copy. // CCplView(const CCplView& rhs); CCplView& operator = (const CCplView& rhs); }; CCplView::CCplView( void ) : m_cRef(1), m_pns(NULL), m_idDirective(0), m_idDirective2(0), m_idTitle(0), m_idIcon(0), m_idCategoryList(0), m_idCategoryTaskList(0), m_idAppletList(0), m_idBanner(0), m_idBarricadeTitle(0), m_idBarricadeMsg(0), m_idContainer(0), m_psss(NULL) { TraceMsg(TF_LIFE, "CCplView::CCplView, this = 0x%x", this); } CCplView::~CCplView( void ) { TraceMsg(TF_LIFE, "CCplView::~CCplView, this = 0x%x", this); if (NULL != m_psss) { m_psss->SetProviderWeakRef(NULL); m_psss->Release(); } if (NULL != m_pns) { IUnknown_SetSite(m_pns, NULL); m_pns->Release(); } _AddOrDeleteAtoms(false); } HRESULT CCplView::CreateInstance( // [static] IEnumIDList *penumIDs, IUnknown *punkSite, REFIID riid, void **ppvOut ) { ASSERT(NULL != penumIDs); ASSERT(NULL != ppvOut); ASSERT(!IsBadWritePtr(ppvOut, sizeof(*ppvOut))); *ppvOut = NULL; HRESULT hr = E_OUTOFMEMORY; CCplView* pv = new CCplView(); if (NULL != pv) { hr = pv->_Initialize(penumIDs, punkSite); if (SUCCEEDED(hr)) { hr = pv->QueryInterface(riid, ppvOut); if (SUCCEEDED(hr)) { // // Set the site of the view to the site passed into the // instance generator. This is most likely the site of // the Control Panel folder view callback. // hr = IUnknown_SetSite(static_cast(*ppvOut), punkSite); } } pv->Release(); } return THR(hr); } STDMETHODIMP CCplView::QueryInterface( REFIID riid, void **ppv ) { ASSERT(NULL != ppv); ASSERT(!IsBadWritePtr(ppv, sizeof(*ppv))); static const QITAB qit[] = { QITABENT(CCplView, ICplView), QITABENT(CCplView, IObjectWithSite), QITABENT(CCplView, IServiceProvider), { 0 }, }; HRESULT hr = QISearch(this, qit, riid, ppv); return E_NOINTERFACE == hr ? hr : THR(hr); } STDMETHODIMP_(ULONG) CCplView::AddRef( void ) { TraceMsg(TF_LIFE, "CCplView::AddRef %d->%d", m_cRef, m_cRef+1); return InterlockedIncrement(&m_cRef); } STDMETHODIMP_(ULONG) CCplView::Release( void ) { TraceMsg(TF_LIFE, "CCplView::Release %d<-%d", m_cRef-1, m_cRef); if (InterlockedDecrement(&m_cRef)) return m_cRef; delete this; return 0; } STDMETHODIMP CCplView::QueryService( REFGUID guidService, REFIID riid, void **ppv ) { DBG_ENTER(FTF_CPANEL, "CCplView::QueryService"); HRESULT hr = E_NOINTERFACE; if (SID_SControlPanelView == guidService) { TraceMsg(TF_CPANEL, "SID_SControlPanelView service requested"); if (IID_ICplNamespace == riid) { TraceMsg(TF_CPANEL, "SID_SControlPanelView::IID_ICplNamespace requested"); ASSERT(NULL != m_pns); hr = m_pns->QueryInterface(IID_ICplNamespace, ppv); } else if (IID_ICplView == riid) { TraceMsg(TF_CPANEL, "SID_SControlPanelView::IID_ICplView requested"); ASSERT(NULL != m_pns); hr = this->QueryInterface(IID_ICplView, ppv); } } else { // // Most likely a command object requesting SID_STopLevelBrowser. // TraceMsg(TF_CPANEL, "Handing service request to view's site."); ASSERT(NULL != _punkSite); hr = IUnknown_QueryService(_punkSite, guidService, riid, ppv); } DBG_EXIT_HRES(FTF_CPANEL, "CCplView::QueryService", hr); return THR(hr); } STDMETHODIMP CCplView::EnumClassicWebViewInfo( DWORD dwFlags, IEnumCplWebViewInfo **ppenum ) { DBG_ENTER(FTF_CPANEL, "CCplView::EnumClassicWebViewInfo"); ASSERT(NULL != ppenum); ASSERT(!IsBadWritePtr(ppenum, sizeof(*ppenum))); ASSERT(NULL != m_pns); HRESULT hr = m_pns->EnumClassicWebViewInfo(dwFlags, ppenum); DBG_EXIT_HRES(FTF_CPANEL, "CCplView::EnumClassicWebViewInfo", hr); return THR(hr); } // // Returns an enumerator for webview info associated with // the category 'choice' page. // STDMETHODIMP CCplView::EnumCategoryChoiceWebViewInfo( DWORD dwFlags, IEnumCplWebViewInfo **ppenum ) { DBG_ENTER(FTF_CPANEL, "CCplView::EnumCategoryChoiceWebViewInfo"); ASSERT(NULL != ppenum); ASSERT(!IsBadWritePtr(ppenum, sizeof(*ppenum))); ASSERT(NULL != m_pns); HRESULT hr = m_pns->EnumWebViewInfo(dwFlags, ppenum); DBG_EXIT_HRES(FTF_CPANEL, "CCplView::EnumCategoryChoiceWebViewInfo", hr); return THR(hr); } // // Returns an enumerator for webview info associated with // a given category page. // STDMETHODIMP CCplView::EnumCategoryWebViewInfo( DWORD dwFlags, eCPCAT eCategory, IEnumCplWebViewInfo **ppenum ) { DBG_ENTER(FTF_CPANEL, "CCplView::EnumCategoryWebViewInfo"); ASSERT(NULL != ppenum); ASSERT(!IsBadWritePtr(ppenum, sizeof(*ppenum))); ASSERT(NULL != m_pns); ICplCategory *pCategory; HRESULT hr = m_pns->GetCategory(eCategory, &pCategory); if (SUCCEEDED(hr)) { hr = pCategory->EnumWebViewInfo(dwFlags, ppenum); ATOMICRELEASE(pCategory); } DBG_EXIT_HRES(FTF_CPANEL, "CCplView::EnumCategoryWebViewInfo", hr); return THR(hr); } // // Creates the DUI element tree for the category 'choice' // page. Returns the root of the tree. // STDMETHODIMP CCplView::CreateCategoryChoiceElement( DUI::Element **ppe ) { DBG_ENTER(FTF_CPANEL, "CCplView::CreateCategoryChoiceElement"); ASSERT(NULL != ppe); ASSERT(!IsBadWritePtr(ppe, sizeof(*ppe))); HRESULT hr = _CreateCategoryChoiceElement(ppe); DBG_EXIT_HRES(FTF_CPANEL, "CCplView::CreateCategoryChoiceElement", hr); return THR(hr); } // // Creates the DUI element tree for a given category page. // Returns the root of the tree. // STDMETHODIMP CCplView::CreateCategoryElement( eCPCAT eCategory, DUI::Element **ppe ) { DBG_ENTER(FTF_CPANEL, "CCplView::CreateCategoryElement"); TraceMsg(TF_CPANEL, "Category ID = %d", eCategory); ASSERT(NULL != ppe); ASSERT(!IsBadWritePtr(ppe, sizeof(*ppe))); ASSERT(NULL != m_pns); ICplCategory *pCategory; HRESULT hr = m_pns->GetCategory(eCategory, &pCategory); if (SUCCEEDED(hr)) { hr = _CreateCategoryElement(pCategory, ppe); ATOMICRELEASE(pCategory); } DBG_EXIT_HRES(FTF_CPANEL, "CCplView::CreateCategoryElement", hr); return THR(hr); } STDMETHODIMP CCplView::GetCategoryHelpURL( CPL::eCPCAT eCategory, LPWSTR pszURL, UINT cchURL ) { DBG_ENTER(FTF_CPANEL, "CCplView::GetCategoryHelpURL"); ASSERT(NULL != pszURL); ASSERT(!IsBadWritePtr(pszURL, cchURL * sizeof(*pszURL))); ICplCategory *pCategory; HRESULT hr = m_pns->GetCategory(eCategory, &pCategory); if (SUCCEEDED(hr)) { hr = pCategory->GetHelpURL(pszURL, cchURL); ATOMICRELEASE(pCategory); } DBG_EXIT_HRES(FTF_CPANEL, "CCplView::GetCategoryHelpURL", hr); return THR(hr); } STDMETHODIMP CCplView::RefreshIDs( IEnumIDList *penumIDs ) { DBG_ENTER(FTF_CPANEL, "CCplView::RefreshIDs"); ASSERT(NULL != m_pns); // // This will cause the namespace object to reset it's internal // list of item IDs. This results in a re-categorization of // applets such that all information returned by the namespace // will now reflect the new set of folder items. // HRESULT hr = m_pns->RefreshIDs(penumIDs); DBG_EXIT_HRES(FTF_CPANEL, "CCplView::RefreshIDs", hr); return THR(hr); } HRESULT CCplView::_Initialize( IEnumIDList *penumIDs, IUnknown *punkSite ) { ASSERT(NULL == m_pns); ASSERT(NULL != penumIDs); HRESULT hr = E_OUTOFMEMORY; // // We use this weak-reference implementation of IServiceProvider // as described by ZekeL in shell\inc\cowsite.h. A strong reference // would create a circular reference cycle between children of the // view and the view itself, preventing the view's destruction. // This weak-reference implementation is designed specifically // for this case. // ASSERT(NULL == m_psss); m_psss = new CSafeServiceSite(); if (NULL != m_psss) { hr = m_psss->SetProviderWeakRef(this); if (SUCCEEDED(hr)) { hr = CplNamespace_CreateInstance(penumIDs, CPL::IID_ICplNamespace, (void **)&m_pns); if (SUCCEEDED(hr)) { IUnknown *punkSafeSite; hr = m_psss->QueryInterface(IID_IUnknown, (void **)&punkSafeSite); if (SUCCEEDED(hr)) { // // Site the namespace object to the view. // By doing this, all command objects created by the namespace will // QueryService on the view object. If the view doesn't support // the requested service, it will query it's site. // We use this so that command objects can query the view for // IID_ICplNamespace and gather information on the namespace // if necessary. // hr = IUnknown_SetSite(m_pns, punkSafeSite); if (SUCCEEDED(hr)) { hr = _AddOrDeleteAtoms(true); } punkSafeSite->Release(); } } } } return THR(hr); } HRESULT CCplView::_AddOrDeleteAtoms( bool bAdd ) { struct CPL::ATOMINFO rgAtomInfo[] = { { L"directive", &m_idDirective }, { L"directive2", &m_idDirective2 }, { L"title", &m_idTitle }, { L"icon", &m_idIcon }, { L"categorylist", &m_idCategoryList }, { L"categorytasklist", &m_idCategoryTaskList }, { L"appletlist", &m_idAppletList }, { L"banner", &m_idBanner }, { L"barricadetitle", &m_idBarricadeTitle }, { L"barricademsg", &m_idBarricadeMsg }, { L"container", &m_idContainer } }; HRESULT hr = Dui_AddOrDeleteAtoms(rgAtomInfo, ARRAYSIZE(rgAtomInfo), bAdd); return THR(hr); } // // Creates the DUI element tree for the category 'choice' page. // Returns the root element. // HRESULT CCplView::_CreateCategoryChoiceElement( DUI::Element **ppe ) { DBG_ENTER(FTF_CPANEL, "CCplView::_CreateCategoryChoiceElement"); ASSERT(NULL != ppe); ASSERT(!IsBadWritePtr(ppe, sizeof(*ppe))); ASSERT(NULL != m_pns); DUI::Element *peRoot = NULL; DUI::Parser *pParser; HRESULT hr = _CreateUiFileParser(&pParser); if (SUCCEEDED(hr)) { hr = Dui_CreateElement(pParser, L"CategoryList", NULL, &peRoot); if (SUCCEEDED(hr)) { hr = _CreateWatermark(peRoot); if (SUCCEEDED(hr)) { CDuiValuePtr pvSsCategoryListItem; hr = Dui_GetStyleSheet(pParser, L"CategoryListItemSS", &pvSsCategoryListItem); if (SUCCEEDED(hr)) { // // Set the "Pick a category..." title. // hr = Dui_SetDescendentElementText(peRoot, L"directive", MAKEINTRESOURCEW(IDS_CP_PICKCATEGORY)); if (SUCCEEDED(hr)) { // // Build the list of categories. // DUI::Element *peCategoryList; hr = Dui_FindDescendent(peRoot, L"categorylist", &peCategoryList); if (SUCCEEDED(hr)) { for (int i = 0; SUCCEEDED(hr) && i < int(eCPCAT_NUMCATEGORIES); i++) { ICplCategory *pCategory; hr = m_pns->GetCategory(_DisplayIndexToCategoryIndex(i), &pCategory); if (SUCCEEDED(hr)) { if (S_OK == _IncludeCategory(pCategory)) { IUICommand *puic; hr = pCategory->GetUiCommand(&puic); if (SUCCEEDED(hr)) { hr = _CreateAndAddListItem(pParser, peCategoryList, L"CategoryLink", pvSsCategoryListItem, puic, eCPIMGSIZE_CATEGORY); ATOMICRELEASE(puic); } } ATOMICRELEASE(pCategory); } } } } } } } pParser->Destroy(); } *ppe = peRoot; DBG_EXIT_HRES(FTF_CPANEL, "CCplView::_CreateCategoryChoiceElement", hr); return THR(hr); } // // Creates the DUI element tree for a given category page. // Returns the root element. // HRESULT CCplView::_CreateCategoryElement( ICplCategory *pCategory, DUI::Element **ppe ) { DBG_ENTER(FTF_CPANEL, "CCplView::_CreateCategoryElement"); ASSERT(NULL != pCategory); ASSERT(NULL != ppe); ASSERT(!IsBadWritePtr(ppe, sizeof(*ppe))); ASSERT(NULL != m_pns); DUI::Element *peRoot = NULL; DUI::Parser *pParser; HRESULT hr = _CreateUiFileParser(&pParser); if (SUCCEEDED(hr)) { hr = Dui_CreateElement(pParser, L"CategoryView", NULL, &peRoot); if (SUCCEEDED(hr)) { hr = _CreateWatermark(peRoot); if (SUCCEEDED(hr)) { int cTasks = 0; int cApplets = 0; hr = _BuildCategoryBanner(pCategory, peRoot); if (SUCCEEDED(hr)) { hr = _BuildCategoryTaskList(pParser, pCategory, peRoot, &cTasks); if (SUCCEEDED(hr)) { hr = _BuildCategoryAppletList(pParser, pCategory, peRoot, &cApplets); } } if (SUCCEEDED(hr)) { if (0 == cTasks && 0 == cApplets) { // // No tasks or applets. Display a message explaining // that the content has been made unavailable by the system // administrator. // hr = _BuildCategoryBarricade(peRoot); } else { // // Delete the barricade DUI elements. They're unused. // THR(Dui_DestroyDescendentElement(peRoot, L"barricadetitle")); THR(Dui_DestroyDescendentElement(peRoot, L"barricademsg")); // // Set the text in the 'directive' text elements. // if (0 < cTasks) { // // We've displayed a list of tasks. // Set the "Pick a task..." title. // hr = Dui_SetDescendentElementText(peRoot, L"directive", MAKEINTRESOURCEW(IDS_CP_PICKTASK)); } if (SUCCEEDED(hr)) { if (0 < cApplets) { // // We've displayed a list of applets. Display one of the // following directives based on the existance of a task // list above. // // Task list? Directive // ------------- --------------------------- // Yes "or pick a Control Panel icon" // No "Pick a Control Panel icon" // UINT idsDirective2 = IDS_CP_PICKICON; if (0 < cTasks) { idsDirective2 = IDS_CP_ORPICKICON; } hr = Dui_SetDescendentElementText(peRoot, L"directive2", MAKEINTRESOURCEW(idsDirective2)); } } } } } } pParser->Destroy(); } *ppe = peRoot; DBG_EXIT_HRES(FTF_CPANEL, "CCplView::_CreateCategoryElement", hr); return THR(hr); } // // Builds the 'barricade' that is displayed when a category has no // tasks or CPL applets to show. // HRESULT CCplView::_BuildCategoryBarricade( DUI::Element *peRoot ) { DBG_ENTER(FTF_CPANEL, "CCplView::_BuildCategoryBarricade"); HRESULT hr = Dui_SetDescendentElementText(peRoot, L"barricadetitle", MAKEINTRESOURCE(IDS_CP_CATEGORY_BARRICADE_TITLE)); if (SUCCEEDED(hr)) { hr = Dui_SetDescendentElementText(peRoot, L"barricademsg", MAKEINTRESOURCE(IDS_CP_CATEGORY_BARRICADE_MSG)); } DBG_EXIT_HRES(FTF_CPANEL, "CCplView::_BuildCategoryBarricade", hr); return THR(hr); } // // Add the background watermark to the view if user is using a non-classic // theme. // HRESULT CCplView::_CreateWatermark( DUI::Element *peRoot ) { DBG_ENTER(FTF_CPANEL, "CCplView::_CreateWatermark"); ASSERT(NULL != peRoot); HINSTANCE hStyleModule; UINT idStyle; HRESULT hr = _GetStyleModuleAndResId(&hStyleModule, &idStyle); if (SUCCEEDED(hr)) { HBITMAP hWatermark = (HBITMAP) LoadImage (hStyleModule, MAKEINTRESOURCE(IDB_CPANEL_WATERMARK), IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION); if (NULL != hWatermark) { // // Set watermark only on non-classic themes. // DUI::Element *peWatermark; hr = Dui_FindDescendent(peRoot, L"watermark", &peWatermark); if (SUCCEEDED(hr)) { CDuiValuePtr ptrValue = DUI::Value::CreateGraphic(hWatermark, GRAPHIC_TransColor, 255); if (!ptrValue.IsNULL()) { hr = Dui_SetElementProperty(peWatermark, ContentProp, ptrValue); peWatermark->SetContentAlign(CA_BottomRight); } else { hr = E_OUTOFMEMORY; DeleteObject (hWatermark); } } else { DeleteObject (hWatermark); } FreeLibrary(hStyleModule); } else { // // If 'classic' theme, do nothing. // hr = S_FALSE; } } DBG_EXIT_HRES(FTF_CPANEL, "CCplView::_CreateWatermark", hr); return THR(hr); } // // Builds the banner for a category page. // HRESULT CCplView::_BuildCategoryBanner( ICplCategory *pCategory, DUI::Element *pePrimaryPane ) { DBG_ENTER(FTF_CPANEL, "CCplView::_BuildCategoryBanner"); ASSERT(NULL != pCategory); ASSERT(NULL != pePrimaryPane); IUICommand *puic; HRESULT hr = pCategory->GetUiCommand(&puic); if (SUCCEEDED(hr)) { ICpUiElementInfo *pei; hr = puic->QueryInterface(IID_ICpUiElementInfo, (void **)&pei); if (SUCCEEDED(hr)) { DUI::Element *peBanner; hr = Dui_FindDescendent(pePrimaryPane, L"banner", &peBanner); if (SUCCEEDED(hr)) { // // Create the title text. // LPWSTR pszTitle; hr = pei->LoadName(&pszTitle); if (SUCCEEDED(hr)) { hr = Dui_SetDescendentElementText(peBanner, L"title", pszTitle); CoTaskMemFree(pszTitle); } if (SUCCEEDED(hr)) { // // Create the icon. // HICON hIcon; hr = pei->LoadIcon(eCPIMGSIZE_BANNER, &hIcon); if (SUCCEEDED(hr)) { hr = Dui_SetDescendentElementIcon(peBanner, L"icon", hIcon); if (FAILED(hr)) { DestroyIcon(hIcon); } } } } ATOMICRELEASE(pei); } ATOMICRELEASE(puic); } DBG_EXIT_HRES(FTF_CPANEL, "CCplView::_BuildCategoryBanner", hr); return THR(hr); } // // Builds the list of tasks for a category page. // HRESULT CCplView::_BuildCategoryTaskList( DUI::Parser *pParser, ICplCategory *pCategory, DUI::Element *pePrimaryPane, int *pcTasks ) { DBG_ENTER(FTF_CPANEL, "CCplView::_BuildCategoryTaskList"); ASSERT(NULL != pCategory); ASSERT(NULL != pePrimaryPane); ASSERT(NULL != m_pns); ASSERT(NULL != pParser); int cTasks = 0; DUI::Element *peCategoryTaskList; HRESULT hr = Dui_FindDescendent(pePrimaryPane, L"categorytasklist", &peCategoryTaskList); if (SUCCEEDED(hr)) { CDuiValuePtr pvStyleSheet; hr = Dui_GetStyleSheet(pParser, L"CategoryTaskListItemSS", &pvStyleSheet); if (SUCCEEDED(hr)) { IEnumUICommand *peuic; hr = pCategory->EnumTasks(&peuic); if (SUCCEEDED(hr)) { IUICommand *puic; while(S_OK == (hr = peuic->Next(1, &puic, NULL))) { hr = _CreateAndAddListItem(pParser, peCategoryTaskList, L"TaskLink", pvStyleSheet, puic, eCPIMGSIZE_TASK); if (SUCCEEDED(hr)) { cTasks++; } ATOMICRELEASE(puic); } ATOMICRELEASE(peuic); } } } if (NULL != pcTasks) { ASSERT(!IsBadWritePtr(pcTasks, sizeof(*pcTasks))); *pcTasks = cTasks; } DBG_EXIT_HRES(FTF_CPANEL, "CCplView::_BuildCategoryTaskList", hr); return THR(hr); } // // Builds the list of CPL applets for a category page. // HRESULT CCplView::_BuildCategoryAppletList( DUI::Parser *pParser, ICplCategory *pCategory, DUI::Element *pePrimaryPane, int *pcApplets ) { DBG_ENTER(FTF_CPANEL, "CCplView::_BuildCategoryAppletList"); ASSERT(NULL != pCategory); ASSERT(NULL != pePrimaryPane); ASSERT(NULL != pParser); int cApplets = 0; DUI::Element *peAppletList; HRESULT hr = Dui_FindDescendent(pePrimaryPane, L"appletlist", &peAppletList); if (SUCCEEDED(hr)) { CDuiValuePtr pvStyleSheet; hr = Dui_GetStyleSheet(pParser, L"CategoryTaskListItemSS", &pvStyleSheet); if (SUCCEEDED(hr)) { IEnumUICommand *peuicApplets; hr = pCategory->EnumCplApplets(&peuicApplets); if (SUCCEEDED(hr)) { IUICommand *puicApplet; while(S_OK == (hr = peuicApplets->Next(1, &puicApplet, NULL))) { hr = _CreateAndAddListItem(pParser, peAppletList, L"AppletLink", pvStyleSheet, puicApplet, eCPIMGSIZE_APPLET); if (SUCCEEDED(hr)) { cApplets++; } ATOMICRELEASE(puicApplet); } ATOMICRELEASE(peuicApplets); } } } if (NULL != pcApplets) { ASSERT(!IsBadWritePtr(pcApplets, sizeof(*pcApplets))); *pcApplets = cApplets; } DBG_EXIT_HRES(FTF_CPANEL, "CCplView::_BuildCategoryAppletList", hr); return THR(hr); } // // Helper for adding link element to the view. // HRESULT CCplView::_CreateAndAddListItem( DUI::Parser *pParser, DUI::Element *peList, // List inserting into. LPCWSTR pszItemTemplate, // Name of template in UI file. DUI::Value *pvSsListItem, // Style sheet for new list item IUICommand *puic, // The new item's link object. eCPIMGSIZE eIconSize // Desired size of item icon. ) { DBG_ENTER(FTF_CPANEL, "CCplView::_CreateAndAddListItem"); ASSERT(NULL != pParser); ASSERT(NULL != peList); ASSERT(NULL != pvSsListItem); ASSERT(NULL != puic); ASSERT(NULL != pszItemTemplate); DUI::Element *peListItem; HRESULT hr = Dui_CreateElement(pParser, pszItemTemplate, NULL, &peListItem); if (SUCCEEDED(hr)) { if (NULL != pvSsListItem) { hr = Dui_SetElementStyleSheet(peListItem, pvSsListItem); } if (SUCCEEDED(hr)) { ASSERTMSG(peListItem->GetClassInfo() == CLinkElement::Class, "CCplView::_CreateAndAddListItem didn't get a CLinkElement::Class object (%s)", peListItem->GetClassInfo()->GetName()); CLinkElement *pLinkEle = static_cast(peListItem); hr = pLinkEle->Initialize(puic, eIconSize); if (SUCCEEDED(hr)) { if (SUCCEEDED(hr)) { hr = peList->Add(peListItem); if (SUCCEEDED(hr)) { peListItem = NULL; } } } if (NULL != peListItem) { peListItem->Destroy(); } } } DBG_EXIT_HRES(FTF_CPANEL, "CCplView::_CreateAndAddListItem", hr); return THR(hr); } // // Determine if a given category item should be shown in the UI. // // Returns: // S_OK - Include the item. // S_FALSE - Do not include the item. // Error - Cannot determine. // HRESULT CCplView::_IncludeCategory( ICplCategory *pCategory ) const { HRESULT hr = S_OK; // Assume it's included. // // If a category link invokes a restricted operation, // hide it from the UI. // IUICommand *puic; hr = pCategory->GetUiCommand(&puic); if (SUCCEEDED(hr)) { UISTATE uis; hr = puic->get_State(NULL, TRUE, &uis); if (SUCCEEDED(hr)) { if (UIS_HIDDEN == uis) { hr = S_FALSE; } } ATOMICRELEASE(puic); } return THR(hr); } // // Map a category display index to a category index in the // namespace. Categories in the namespace are ordered to match up // with the various category IDs. The view may be (and is) ordered // differently and is subject to change based on usability feedback. // eCPCAT CCplView::_DisplayIndexToCategoryIndex( int iCategory ) const { // // This array determins the order the categories are displayed // in the category selection view. To change the display order, // simply reorder these entries. // static const eCPCAT rgMap[] = { // Position in DUI grid control eCPCAT_APPEARANCE, // Row 0, Col 0 eCPCAT_HARDWARE, // Row 0, Col 1 eCPCAT_NETWORK, // Row 1, Col 0 eCPCAT_ACCOUNTS, // Row 1, Col 1 eCPCAT_ARP, // Row 2, Col 0 eCPCAT_REGIONAL, // Row 2, Col 1 eCPCAT_SOUND, // Row 3, Col 0 eCPCAT_ACCESSIBILITY, // Row 3, Col 1 eCPCAT_PERFMAINT, // Row 4, Col 0 eCPCAT_OTHER // Row 4, Col 1 }; ASSERT(ARRAYSIZE(rgMap) == eCPCAT_NUMCATEGORIES); ASSERT(iCategory >= 0 && iCategory < ARRAYSIZE(rgMap)); return rgMap[iCategory]; } HRESULT CCplView::_CreateUiFileParser( DUI::Parser **ppParser ) { DBG_ENTER(FTF_CPANEL, "CCplView::_CreateUiFileParser"); ASSERT(NULL != ppParser); ASSERT(!IsBadWritePtr(ppParser, sizeof(*ppParser))); char *pszUiFile; int cchUiFile; HINSTANCE hInstance; // Instance containing resources referenced in UI file. HRESULT hr = _BuildUiFile(&pszUiFile, &cchUiFile, &hInstance); if (SUCCEEDED(hr)) { hr = Dui_CreateParser(pszUiFile, cchUiFile, hInstance, ppParser); LocalFree(pszUiFile); if (HINST_THISDLL != hInstance) { ASSERT(NULL != hInstance); FreeLibrary(hInstance); } } DBG_EXIT(FTF_CPANEL, "CCplView::_CreateUiFileParser"); return THR(hr); } // // Builds the UI file for this view from the // appropriate base template + style sheet // // pUIFile receives a pointer to the ui file in memory // piCharCount receives the size of the file // HRESULT CCplView::_BuildUiFile( char **ppUIFile, int *piCharCount, HINSTANCE *phInstance ) { DBG_ENTER(FTF_CPANEL, "CCplView::_BuildUiFile"); ASSERT(NULL != ppUIFile); ASSERT(!IsBadWritePtr(ppUIFile, sizeof(*ppUIFile))); ASSERT(NULL != phInstance); ASSERT(!IsBadWritePtr(phInstance, sizeof(*phInstance))); *phInstance = NULL; // // Load the 'structure' UI file // char *pStructure; HRESULT hr = _LoadUiFileFromResources(HINST_THISDLL, IDR_DUI_CPVIEW, &pStructure); if (SUCCEEDED(hr)) { HINSTANCE hStyleModule; UINT idStyle; hr = _GetStyleModuleAndResId(&hStyleModule, &idStyle); if (SUCCEEDED(hr)) { // // Load the style sheet. First, check if the current theme has a style sheet, // if not, use the default style sheet in the resources. // char *pStyle; hr = _LoadUiFileFromResources(hStyleModule, idStyle, &pStyle); if (SUCCEEDED(hr)) { const int cbStyle = lstrlenA(pStyle); const int cbStructure = lstrlenA(pStructure); char *pResult = (char *)LocalAlloc(LPTR, cbStyle + cbStructure + 1); if (pResult) { // // Put the resouces together (style + structure) // CopyMemory(pResult, pStyle, cbStyle); CopyMemory(pResult + cbStyle, pStructure, cbStructure); ASSERT(cbStructure + cbStyle == lstrlenA(pResult)); *ppUIFile = pResult; // // This count is ANSI chars so we can use byte counts // directly. // *piCharCount = cbStructure + cbStyle; *phInstance = hStyleModule; // // Indicate that HINSTANCE is being returned to caller. // hStyleModule = NULL; } else { hr = E_OUTOFMEMORY; } LocalFree(pStyle); } if (NULL != hStyleModule && HINST_THISDLL != hStyleModule) { // // Something failed. Need to free style module // if it's not shell32.dll. // FreeLibrary(hStyleModule); } } LocalFree(pStructure); } DBG_EXIT_HRES(FTF_CPANEL, "CCplView::_BuildUiFile", hr); return THR(hr); } HRESULT CCplView::_GetStyleModuleAndResId( HINSTANCE *phInstance, UINT *pidStyle ) { DBG_ENTER(FTF_CPANEL, "CCplView::_GetStyleModuleAndResId"); ASSERT(NULL != phInstance); ASSERT(!IsBadWritePtr(phInstance, sizeof(*phInstance))); ASSERT(NULL != pidStyle); ASSERT(!IsBadWritePtr(pidStyle, sizeof(*pidStyle))); HRESULT hr = S_OK; *phInstance = NULL; HINSTANCE hThemeModule = SHGetShellStyleHInstance(); if (NULL != hThemeModule) { *pidStyle = IDR_DUI_CPSTYLE; *phInstance = hThemeModule; } else { TraceMsg(TF_CPANEL, "Error %d loading theme file", GetLastError()); hr = ResultFromLastError(); } DBG_EXIT_HRES(FTF_CPANEL, "CCplView::_GetStyleModuleAndResId", hr); return THR(hr); } // // Loads the requested UI file from a module's resources. // // iID - UI file id // pUIFile - receives a pointer to the UI file // HRESULT CCplView::_LoadUiFileFromResources( HINSTANCE hInstance, int idResource, char **ppUIFile ) { DBG_ENTER(FTF_CPANEL, "CCplView::_LoadUiFileFromResources"); ASSERT(NULL != ppUIFile); ASSERT(!IsBadWritePtr(ppUIFile, sizeof(*ppUIFile))); HRESULT hr = E_FAIL; *ppUIFile = NULL; HRSRC hFile = FindResourceW(hInstance, MAKEINTRESOURCEW(idResource), L"UIFILE"); if (hFile) { HGLOBAL hResource = LoadResource(hInstance, hFile); if (hResource) { char *pFile = (char *)LockResource(hResource); if (pFile) { DWORD dwSize = SizeofResource(hInstance, hFile); // // Include one extra byte for a terminating nul character. // We're loading text and want it to be nul-terminated. // *ppUIFile = (char *)LocalAlloc(LPTR, dwSize + 1); if (NULL != *ppUIFile) { CopyMemory(*ppUIFile, pFile, dwSize); hr = S_OK; } else { hr = E_OUTOFMEMORY; } } else { hr = ResultFromLastError(); } } else { hr = ResultFromLastError(); } } else { hr = ResultFromLastError(); } DBG_EXIT_HRES(FTF_CPANEL, "CCplView::_LoadUiFileFromResources", hr); return THR(hr); } HRESULT CPL::CplView_CreateInstance( IEnumIDList *penumIDs, IUnknown *punkSite, REFIID riid, void **ppvOut ) { HRESULT hr = CCplView::CreateInstance(penumIDs, punkSite, riid, ppvOut); return THR(hr); } HRESULT CplView_GetCategoryTitle( eCPCAT eCategory, LPWSTR pszTitle, UINT cchTitle ) { ASSERT(NULL != pszTitle); ASSERT(!IsBadWritePtr(pszTitle, cchTitle * sizeof(*pszTitle))); // // These must remain in the same order as the eCPCAT_XXXXX enumeration. // static const UINT rgid[] = { IDS_CPCAT_OTHERCPLS_TITLE, IDS_CPCAT_APPEARANCE_TITLE, IDS_CPCAT_HARDWARE_TITLE, IDS_CPCAT_NETWORK_TITLE, IDS_CPCAT_SOUNDS_TITLE, IDS_CPCAT_PERFMAINT_TITLE, IDS_CPCAT_REGIONAL_TITLE, IDS_CPCAT_ACCESSIBILITY_TITLE, IDS_CPCAT_ARP_TITLE, IDS_CPCAT_ACCOUNTS_TITLE }; HRESULT hr = S_OK; ASSERT(eCategory >= 0 && eCategory < eCPCAT_NUMCATEGORIES); if (0 == LoadString(HINST_THISDLL, rgid[int(eCategory)], pszTitle, cchTitle)) { hr = ResultFromLastError(); } return THR(hr); } } // namespace CPL HRESULT InitializeCPClasses() { HRESULT hr; hr = CPL::CLinkElement::Register(); if (FAILED(hr)) goto Failure; return S_OK; Failure: return hr; }