|
|
//+-------------------------------------------------------------------------
//
// 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 <uxtheme.h>
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<IUnknown *>(*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<CLinkElement *>(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; }
|