//+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 2000 // // File: cpuiele.cpp // // This module contains the following classes: // // CCplUiElement // CCplUiCommand // CCplUiCommandOnPidl // // CCplUiElement is an implementation of IUIElement. This provides // the necessary display information for use in the shell's webview // implementation. The class also implements ICpUiElementInfo which // is similar to IUIElement but provides the display information in // a more 'final' form than a "," format. // The ICpUiElementInfo interface is used internally by the Control Panel // implementation. // // CCplUiCommand is an implementation of IUICommand. As with IUIElement, // this provides the necessary functions for communicating with webview // as a 'command' object (i.e. selectable 'link'). Also as with the // previous class, CCplUiCommand implements an internal version of // the public interface. ICplUiCommand provides two things: // 1. A method to invoke a context menu. // 2. An invocation method that accepts a site pointer. This site // pointer is passed along to an 'action' object that may need // access to the shell browser to perform it's function. It // obtains access to the shell browser through this site ptr. // // CCplUiCommandOnPidl is another implementation of IUICommand that // wraps a shell item ID list. It is used to represent the CPL // applet items in a category view. // //-------------------------------------------------------------------------- #include "shellprv.h" #include "cpviewp.h" #include "cpguids.h" #include "cpuiele.h" #include "cputil.h" #include "contextmenu.h" #include "prop.h" namespace CPL { //----------------------------------------------------------------------------- // CCplUiElement //----------------------------------------------------------------------------- class CCplUiElement : public IUIElement, public ICpUiElementInfo { public: // // IUnknown // STDMETHOD(QueryInterface)(REFIID riid, void **ppv); STDMETHOD_(ULONG, AddRef)(void); STDMETHOD_(ULONG, Release)(void); // // IUIElement (used by shell webview) // STDMETHOD(get_Name)(IShellItemArray *psiItemArray, LPWSTR *ppszName); STDMETHOD(get_Icon)(IShellItemArray *psiItemArray, LPWSTR *ppszIcon); STDMETHOD(get_Tooltip)(IShellItemArray *psiItemArray, LPWSTR *ppszInfotip); // // ICpUiElementInfo (used internally by Control Panel) // STDMETHOD(LoadIcon)(eCPIMGSIZE eSize, HICON *phIcon); STDMETHOD(LoadName)(LPWSTR *ppszName); STDMETHOD(LoadTooltip)(LPWSTR *ppszTooltip); static HRESULT CreateInstance(LPCWSTR pszName, LPCWSTR pszInfotip, LPCWSTR pszIcon, REFIID riid, void **ppvOut); protected: CCplUiElement(LPCWSTR pszName, LPCWSTR pszInfotip, LPCWSTR pszIcon); CCplUiElement(void); virtual CCplUiElement::~CCplUiElement(void); private: LONG m_cRef; LPCWSTR m_pszName; LPCWSTR m_pszInfotip; LPCWSTR m_pszIcon; HRESULT _GetResourceString(LPCWSTR pszItem, LPWSTR *ppsz); HRESULT _GetIconResource(LPWSTR *ppsz); HRESULT _GetNameResource(LPWSTR *ppsz); HRESULT _GetInfotipResource(LPWSTR *ppsz); }; CCplUiElement::CCplUiElement( LPCWSTR pszName, LPCWSTR pszInfotip, // NULL == No Info Tip LPCWSTR pszIcon ) : m_cRef(1), m_pszName(pszName), m_pszInfotip(pszInfotip), m_pszIcon(pszIcon) { ASSERT(IS_INTRESOURCE(m_pszName) || !IsBadStringPtr(m_pszName, UINT_PTR(-1))); ASSERT((NULL == pszInfotip) || IS_INTRESOURCE(m_pszInfotip) || !IsBadStringPtr(m_pszInfotip, UINT_PTR(-1))); ASSERT(IS_INTRESOURCE(m_pszIcon) || !IsBadStringPtr(m_pszIcon, UINT_PTR(-1))); } CCplUiElement::CCplUiElement( void ) : m_cRef(1), m_pszName(NULL), m_pszInfotip(NULL), m_pszIcon(NULL) { TraceMsg(TF_LIFE, "CCplUiElement::CCplUiElement, this = 0x%x", this); } CCplUiElement::~CCplUiElement( void ) { TraceMsg(TF_LIFE, "CCplUiElement::~CCplUiElement, this = 0x%x", this); // // Note that the member string pointers contain either a resource ID // or a pointer to constant memory. // Therefore, we do not try to free them. // } HRESULT CCplUiElement::CreateInstance( // [static] LPCWSTR pszName, LPCWSTR pszInfotip, LPCWSTR pszIcon, REFIID riid, void **ppvOut ) { ASSERT(NULL != ppvOut); ASSERT(!IsBadWritePtr(ppvOut, sizeof(*ppvOut))); *ppvOut = NULL; HRESULT hr = E_OUTOFMEMORY; CCplUiElement *pe = new CCplUiElement(pszName, pszInfotip, pszIcon); if (NULL != pe) { hr = pe->QueryInterface(riid, ppvOut); pe->Release(); } return THR(hr); } STDMETHODIMP CCplUiElement::QueryInterface( REFIID riid, void **ppv ) { ASSERT(NULL != ppv); ASSERT(!IsBadWritePtr(ppv, sizeof(*ppv))); static const QITAB qit[] = { QITABENT(CCplUiElement, IUIElement), QITABENT(CCplUiElement, ICpUiElementInfo), { 0 }, }; HRESULT hr = QISearch(this, qit, riid, ppv); return E_NOINTERFACE == hr ? hr : THR(hr); } STDMETHODIMP_(ULONG) CCplUiElement::AddRef( void ) { return InterlockedIncrement(&m_cRef); } STDMETHODIMP_(ULONG) CCplUiElement::Release( void ) { ASSERT( 0 != m_cRef ); ULONG cRef = InterlockedDecrement(&m_cRef); if ( 0 == cRef ) { delete this; } return cRef; } STDMETHODIMP CCplUiElement::get_Name( IShellItemArray *psiItemArray, LPWSTR *ppszName ) { UNREFERENCED_PARAMETER(psiItemArray); HRESULT hr = LoadName(ppszName); return THR(hr); } STDMETHODIMP CCplUiElement::get_Icon( IShellItemArray *psiItemArray, LPWSTR *ppszIcon ) { UNREFERENCED_PARAMETER(psiItemArray); HRESULT hr = _GetIconResource(ppszIcon); return THR(hr); } STDMETHODIMP CCplUiElement::get_Tooltip( IShellItemArray *psiItemArray, LPWSTR *ppszInfotip ) { UNREFERENCED_PARAMETER(psiItemArray); HRESULT hr = THR(LoadTooltip(ppszInfotip)); if (S_FALSE == hr) { // // Tooltips are optional but we need to return a failure // code to tell webview that we don't have one. // hr = E_FAIL; } return hr; } STDMETHODIMP CCplUiElement::LoadIcon( eCPIMGSIZE eSize, HICON *phIcon ) { *phIcon = NULL; LPWSTR pszResource; HRESULT hr = _GetIconResource(&pszResource); if (SUCCEEDED(hr)) { hr = CPL::LoadIconFromResource(pszResource, eSize, phIcon); CoTaskMemFree(pszResource); } return THR(hr); } STDMETHODIMP CCplUiElement::LoadName( LPWSTR *ppszName ) { LPWSTR pszResource; HRESULT hr = _GetNameResource(&pszResource); if (SUCCEEDED(hr)) { hr = CPL::LoadStringFromResource(pszResource, ppszName); CoTaskMemFree(pszResource); } return THR(hr); } STDMETHODIMP CCplUiElement::LoadTooltip( LPWSTR *ppszTooltip ) { LPWSTR pszResource; HRESULT hr = _GetInfotipResource(&pszResource); if (S_OK == hr) { hr = CPL::LoadStringFromResource(pszResource, ppszTooltip); CoTaskMemFree(pszResource); } return THR(hr); } HRESULT CCplUiElement::_GetIconResource( LPWSTR *ppsz ) { HRESULT hr = _GetResourceString(m_pszIcon, ppsz); return THR(hr); } HRESULT CCplUiElement::_GetNameResource( LPWSTR *ppsz ) { HRESULT hr = _GetResourceString(m_pszName, ppsz); return THR(hr); } // // Returns S_FALSE if tooltip text is not provided. // Tooltips are optional. For example, the "learn about" // tasks in Control Panel's web view pane do not have tooltip // text. // HRESULT CCplUiElement::_GetInfotipResource( LPWSTR *ppsz ) { HRESULT hr = S_FALSE; if (NULL != m_pszInfotip) { hr = _GetResourceString(m_pszInfotip, ppsz); } return THR(hr); } // // On successful return, caller must free returned string using // CoTaskMemFree. // HRESULT CCplUiElement::_GetResourceString( LPCWSTR pszItem, LPWSTR *ppsz ) { ASSERT(NULL != ppsz); ASSERT(!IsBadWritePtr(ppsz, sizeof(*ppsz))); *ppsz = NULL; HRESULT hr = E_FAIL; if (IS_INTRESOURCE(pszItem)) { // // pszItem is a resource identifier integer. Create a resource // ID string ",<-i>" for the resource. // WCHAR szModule[MAX_PATH]; if (GetModuleFileNameW(HINST_THISDLL, szModule, ARRAYSIZE(szModule))) { const size_t cchResource = lstrlenW(szModule) + 15; *ppsz = (LPWSTR)CoTaskMemAlloc(cchResource * sizeof(WCHAR)); if (NULL != *ppsz) { // // Precede the resource ID with a minus sign so that it will be // treated as a resource ID and not an index. // hr = StringCchPrintfW(*ppsz, cchResource, L"%s,-%u", szModule, PtrToUint(pszItem)); } else { hr = E_OUTOFMEMORY; } } else { hr = ResultFromLastError(); } } else { // // pszItem is a text string. Assume it's in the form of // ",<-i>". Simply duplicate it. // ASSERT(!IsBadStringPtr(pszItem, UINT_PTR(-1))); hr = SHStrDup(pszItem, ppsz); } return THR(hr); } //----------------------------------------------------------------------------- // CCplUiCommand //----------------------------------------------------------------------------- class CCplUiCommand : public CObjectWithSite, public CCplUiElement, public IUICommand, public ICpUiCommand { public: // // IUnknown // STDMETHOD(QueryInterface)(REFIID riid, void **ppv); STDMETHOD_(ULONG, AddRef)(void) { return CCplUiElement::AddRef(); } STDMETHOD_(ULONG, Release)(void) { return CCplUiElement::Release(); } // // IUICommand // STDMETHOD(get_Name)(IShellItemArray *psiItemArray, LPWSTR *ppszName) { return CCplUiElement::get_Name(psiItemArray, ppszName); } STDMETHOD(get_Icon)(IShellItemArray *psiItemArray, LPWSTR *ppszIcon) { return CCplUiElement::get_Icon(psiItemArray, ppszIcon); } STDMETHOD(get_Tooltip)(IShellItemArray *psiItemArray, LPWSTR *ppszInfotip) { return CCplUiElement::get_Tooltip(psiItemArray, ppszInfotip); } STDMETHOD(get_CanonicalName)(GUID *pguidCommandName); STDMETHOD(get_State)(IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE *puisState); STDMETHOD(Invoke)(IShellItemArray *psiItemArray, IBindCtx *pbc); // // ICpUiCommand // STDMETHOD(InvokeContextMenu)(HWND hwndParent, const POINT *ppt); STDMETHOD(Invoke)(HWND hwndParent, IUnknown *punkSite); STDMETHOD(GetDataObject)(IDataObject **ppdtobj); // // ICpUiElementInfo // STDMETHOD(LoadIcon)(eCPIMGSIZE eSize, HICON *phIcon) { return CCplUiElement::LoadIcon(eSize, phIcon); } STDMETHOD(LoadName)(LPWSTR *ppszName) { return CCplUiElement::LoadName(ppszName); } STDMETHOD(LoadTooltip)(LPWSTR *ppszTooltip) { return CCplUiElement::LoadTooltip(ppszTooltip); } static HRESULT CreateInstance(LPCWSTR pszName, LPCWSTR pszInfotip, LPCWSTR pszIcon, const IAction *pAction, REFIID riid, void **ppvOut); protected: CCplUiCommand(LPCWSTR pszName, LPCWSTR pszInfotip, LPCWSTR pszIcon, const IAction *pAction); CCplUiCommand(void); ~CCplUiCommand(void); private: const IAction *m_pAction; HRESULT _IsCommandRestricted(void); }; CCplUiCommand::CCplUiCommand( void ) : m_pAction(NULL) { TraceMsg(TF_LIFE, "CCplUiCommand::CCplUiCommand, this = 0x%x", this); } CCplUiCommand::CCplUiCommand( LPCWSTR pszName, LPCWSTR pszInfotip, LPCWSTR pszIcon, const IAction *pAction ) : CCplUiElement(pszName, pszInfotip, pszIcon), m_pAction(pAction) { TraceMsg(TF_LIFE, "CCplUiCommand::CCplUiCommand, this = 0x%x", this); } CCplUiCommand::~CCplUiCommand( void ) { TraceMsg(TF_LIFE, "CCplUiCommand::~CCplUiCommand, this = 0x%x", this); // // Note that m_pAction is a pointer to a const object. // Therefore, we don't try to free it. // } HRESULT CCplUiCommand::CreateInstance( // [static] LPCWSTR pszName, LPCWSTR pszInfotip, LPCWSTR pszIcon, const IAction *pAction, REFIID riid, void **ppvOut ) { ASSERT(NULL != ppvOut); ASSERT(!IsBadWritePtr(ppvOut, sizeof(*ppvOut))); *ppvOut = NULL; HRESULT hr = E_OUTOFMEMORY; CCplUiCommand *pc = new CCplUiCommand(pszName, pszInfotip, pszIcon, pAction); if (NULL != pc) { hr = pc->QueryInterface(riid, ppvOut); pc->Release(); } return THR(hr); } STDMETHODIMP CCplUiCommand::QueryInterface( REFIID riid, void **ppv ) { ASSERT(NULL != ppv); ASSERT(!IsBadWritePtr(ppv, sizeof(*ppv))); static const QITAB qit[] = { QITABENT(CCplUiCommand, IUICommand), QITABENT(CCplUiCommand, ICpUiElementInfo), QITABENT(CCplUiCommand, ICpUiCommand), QITABENT(CCplUiCommand, IObjectWithSite), QITABENTMULTI(CCplUiCommand, IUIElement, IUICommand), { 0 }, }; HRESULT hr = QISearch(this, qit, riid, ppv); return E_NOINTERFACE == hr ? hr : THR(hr); } STDMETHODIMP CCplUiCommand::get_CanonicalName( GUID *pguidCommandName ) { UNREFERENCED_PARAMETER(pguidCommandName); // // This function is unimplemented. It is in IUICommand to // support generic functionality in the shell. This functionality // is not applicable to the use of IUICommand in the Control // Panel. // return E_NOTIMPL; } STDMETHODIMP CCplUiCommand::get_State( IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE *puisState ) { ASSERT(NULL != m_pAction); ASSERT(NULL != puisState); ASSERT(!IsBadWritePtr(puisState, sizeof(*puisState))); UNREFERENCED_PARAMETER(psiItemArray); *puisState = UIS_DISABLED; // default; // // If an action is restricted, we hide it's corresponding // UI element in the user interface. // HRESULT hr = _IsCommandRestricted(); if (SUCCEEDED(hr)) { switch(hr) { case S_OK: *puisState = UIS_HIDDEN; break; case S_FALSE: *puisState = UIS_ENABLED; default: break; } // // Don't propagate S_FALSE to caller. // hr = S_OK; } return THR(hr); } // // IUICommand::Invoke // This version is called by webview when the user selects an // item from a webview menu. // STDMETHODIMP CCplUiCommand::Invoke( IShellItemArray *psiItemArray, IBindCtx *pbc ) { DBG_ENTER(FTF_CPANEL, "CCplUiCommand::Invoke"); ASSERT(NULL != m_pAction); UNREFERENCED_PARAMETER(psiItemArray); UNREFERENCED_PARAMETER(pbc); HRESULT hr = m_pAction->Execute(NULL, _punkSite); DBG_EXIT_HRES(FTF_CPANEL, "CCplUiCommand::Invoke", hr); return THR(hr); } // // ICpUiCommand::Invoke // This version is called by CLinkElement::_OnSelected when // the user selects either a category task or a category item // in the category choice view. // STDMETHODIMP CCplUiCommand::Invoke( HWND hwndParent, IUnknown *punkSite ) { ASSERT(NULL != m_pAction); HRESULT hr = m_pAction->Execute(hwndParent, punkSite); return THR(hr); } STDMETHODIMP CCplUiCommand::InvokeContextMenu( HWND hwndParent, const POINT *ppt ) { // // Only commands on pidls provide a context menu. // UNREFERENCED_PARAMETER(hwndParent); UNREFERENCED_PARAMETER(ppt); return E_NOTIMPL; } STDMETHODIMP CCplUiCommand::GetDataObject( IDataObject **ppdtobj ) { // // Simple UI commands don't provide a data object. // return E_NOTIMPL; } // // Returns: // S_OK = Command is restricted. // S_FALSE = Command is not restricted. // HRESULT CCplUiCommand::_IsCommandRestricted( void ) { // // The ICplNamespace ptr is passed to IsRestricted in case the restriction // code needs to inspect contents of the namespace. The "Other Cpl Options" // link command uses this to determine if the "OTHER" category contains any // CPL applets or not. If it contains no applets, the link is hidden (restricted). // ICplNamespace *pns; HRESULT hr = IUnknown_QueryService(_punkSite, SID_SControlPanelView, IID_ICplNamespace, (void **)&pns); if (SUCCEEDED(hr)) { hr = m_pAction->IsRestricted(pns); pns->Release(); } return THR(hr); } //----------------------------------------------------------------------------- // CCplUiCommandOnPidl //----------------------------------------------------------------------------- class CCplUiCommandOnPidl : public CObjectWithSite, public IUICommand, public ICpUiCommand, public ICpUiElementInfo, public IDataObject { public: ~CCplUiCommandOnPidl(void); // // IUnknown // STDMETHOD(QueryInterface)(REFIID riid, void **ppv); STDMETHOD_(ULONG, AddRef)(void); STDMETHOD_(ULONG, Release)(void); // // IUICommand // STDMETHOD(get_Name)(IShellItemArray *psiItemArray, LPWSTR *ppszName); STDMETHOD(get_Icon)(IShellItemArray *psiItemArray, LPWSTR *ppszIcon); STDMETHOD(get_Tooltip)(IShellItemArray *psiItemArray, LPWSTR *ppszInfotip); STDMETHOD(get_CanonicalName)(GUID *pguidCommandName); STDMETHOD(get_State)(IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE *puisState); STDMETHOD(Invoke)(IShellItemArray *psiItemArray, IBindCtx *pbc); // // ICpUiCommand // STDMETHOD(InvokeContextMenu)(HWND hwndParent, const POINT *ppt); STDMETHOD(Invoke)(HWND hwndParent, IUnknown *punkSite); STDMETHOD(GetDataObject)(IDataObject **ppdtobj); // // ICpUiElementInfo // STDMETHOD(LoadIcon)(eCPIMGSIZE eSize, HICON *phIcon); STDMETHOD(LoadName)(LPWSTR *ppszName); STDMETHOD(LoadTooltip)(LPWSTR *ppszTooltip); // // IDataObject // STDMETHOD(GetData)(FORMATETC *pFmtEtc, STGMEDIUM *pstm); STDMETHOD(GetDataHere)(FORMATETC *pFmtEtc, STGMEDIUM *pstm); STDMETHOD(QueryGetData)(FORMATETC *pFmtEtc); STDMETHOD(GetCanonicalFormatEtc)(FORMATETC *pFmtEtcIn, FORMATETC *pFmtEtcOut); STDMETHOD(SetData)(FORMATETC *pFmtEtc, STGMEDIUM *pstm, BOOL fRelease); STDMETHOD(EnumFormatEtc)(DWORD dwDirection, LPENUMFORMATETC *ppEnum); STDMETHOD(DAdvise)(FORMATETC *pFmtEtc, DWORD grfAdv, LPADVISESINK pAdvSink, DWORD *pdwConnection); STDMETHOD(DUnadvise)(DWORD dwConnection); STDMETHOD(EnumDAdvise)(LPENUMSTATDATA *ppEnum); static HRESULT CreateInstance(LPCITEMIDLIST pidl, REFIID riid, void **ppvOut); private: LONG m_cRef; IShellFolder *m_psf; // Cached Control Panel IShellFolder ptr. LPITEMIDLIST m_pidl; // Assumed to be relative to Control Panel. IDataObject *m_pdtobj; CCplUiCommandOnPidl(void); HRESULT _GetControlPanelFolder(IShellFolder **ppsf); HRESULT _Initialize(LPCITEMIDLIST pidl); HRESULT _GetName(LPWSTR *ppszName); HRESULT _GetInfotip(LPWSTR *ppszInfotip); HRESULT _GetIconResource(LPWSTR *ppszIcon); HRESULT _Invoke(HWND hwndParent, IUnknown *punkSite); HRESULT _GetDataObject(IDataObject **ppdtobj); }; CCplUiCommandOnPidl::CCplUiCommandOnPidl( void ) : m_cRef(1), m_psf(NULL), m_pidl(NULL), m_pdtobj(NULL) { TraceMsg(TF_LIFE, "CCplUiCommandOnPidl::CCplUiCommandOnPidl, this = 0x%x", this); } CCplUiCommandOnPidl::~CCplUiCommandOnPidl( void ) { TraceMsg(TF_LIFE, "CCplUiCommandOnPidl::~CCplUiCommandOnPidl, this = 0x%x", this); ATOMICRELEASE(m_psf); ATOMICRELEASE(m_pdtobj); if (NULL != m_pidl) { ILFree(m_pidl); } } HRESULT CCplUiCommandOnPidl::CreateInstance( // [static] LPCITEMIDLIST pidl, REFIID riid, void **ppvOut ) { ASSERT(NULL != ppvOut); ASSERT(!IsBadWritePtr(ppvOut, sizeof(*ppvOut))); ASSERT(NULL != pidl); *ppvOut = NULL; HRESULT hr = E_OUTOFMEMORY; CCplUiCommandOnPidl *pc = new CCplUiCommandOnPidl(); if (NULL != pc) { hr = pc->_Initialize(pidl); if (SUCCEEDED(hr)) { hr = pc->QueryInterface(riid, ppvOut); } pc->Release(); } return THR(hr); } STDMETHODIMP CCplUiCommandOnPidl::QueryInterface( REFIID riid, void **ppv ) { ASSERT(NULL != ppv); ASSERT(!IsBadWritePtr(ppv, sizeof(*ppv))); static const QITAB qit[] = { QITABENT(CCplUiCommandOnPidl, IUICommand), QITABENT(CCplUiCommandOnPidl, ICpUiCommand), QITABENT(CCplUiCommandOnPidl, ICpUiElementInfo), QITABENT(CCplUiCommandOnPidl, IObjectWithSite), QITABENT(CCplUiCommandOnPidl, IDataObject), QITABENTMULTI(CCplUiCommandOnPidl, IUIElement, IUICommand), { 0 }, }; HRESULT hr = QISearch(this, qit, riid, ppv); return E_NOINTERFACE == hr ? hr : THR(hr); } STDMETHODIMP_(ULONG) CCplUiCommandOnPidl::AddRef( void ) { return InterlockedIncrement(&m_cRef); } STDMETHODIMP_(ULONG) CCplUiCommandOnPidl::Release( void ) { ASSERT( 0 != m_cRef ); ULONG cRef = InterlockedDecrement(&m_cRef); if ( 0 == cRef ) { delete this; } return cRef; } STDMETHODIMP CCplUiCommandOnPidl::get_Name( IShellItemArray *psiItemArray, LPWSTR *ppszName ) { UNREFERENCED_PARAMETER(psiItemArray); HRESULT hr = _GetName(ppszName); return THR(hr); } STDMETHODIMP CCplUiCommandOnPidl::get_Icon( IShellItemArray *psiItemArray, LPWSTR *ppszIcon ) { UNREFERENCED_PARAMETER(psiItemArray); HRESULT hr = _GetIconResource(ppszIcon); return THR(hr); } STDMETHODIMP CCplUiCommandOnPidl::get_Tooltip( IShellItemArray *psiItemArray, LPWSTR *ppszInfotip ) { UNREFERENCED_PARAMETER(psiItemArray); HRESULT hr = _GetInfotip(ppszInfotip); return THR(hr); } STDMETHODIMP CCplUiCommandOnPidl::get_CanonicalName( GUID *pguidCommandName ) { UNREFERENCED_PARAMETER(pguidCommandName); return E_NOTIMPL; } STDMETHODIMP CCplUiCommandOnPidl::get_State( IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE *puisState ) { ASSERT(NULL != puisState); ASSERT(!IsBadWritePtr(puisState, sizeof(*puisState))); UNREFERENCED_PARAMETER(psiItemArray); UNREFERENCED_PARAMETER(fOkToBeSlow); HRESULT hr = S_OK; *puisState = UIS_ENABLED; // default; // // We do not handle restrictions on CPL applets in the same // sense as other 'tasks' in this architecture. // CPL applets are restricted by the Control Panel folder's // item enumerator. If the folder enumerates a CPL applet // then we assume it's valid to present that applet in the // UI. // return THR(hr); } STDMETHODIMP CCplUiCommandOnPidl::Invoke( IShellItemArray *psiItemArray, IBindCtx *pbc ) { DBG_ENTER(FTF_CPANEL, "CCplUiCommandOnPidl::Invoke"); UNREFERENCED_PARAMETER(psiItemArray); UNREFERENCED_PARAMETER(pbc); HRESULT hr = _Invoke(NULL, NULL); DBG_EXIT_HRES(FTF_CPANEL, "CCplUiCommandOnPidl::Invoke", hr); return THR(hr); } // // ICpUiCommand::Invoke // STDMETHODIMP CCplUiCommandOnPidl::Invoke( HWND hwndParent, IUnknown *punkSite ) { DBG_ENTER(FTF_CPANEL, "CCplUiCommandOnPidl::Invoke"); UNREFERENCED_PARAMETER(punkSite); HRESULT hr = _Invoke(hwndParent, punkSite); DBG_EXIT_HRES(FTF_CPANEL, "CCplUiCommandOnPidl::Invoke", hr); return THR(hr); } HRESULT CCplUiCommandOnPidl::_Invoke( HWND hwndParent, IUnknown *punkSite ) { DBG_ENTER(FTF_CPANEL, "CCplUiCommandOnPidl::_Invoke"); UNREFERENCED_PARAMETER(hwndParent); LPITEMIDLIST pidlCpanel; HRESULT hr = SHGetSpecialFolderLocation(NULL, CSIDL_CONTROLS, &pidlCpanel); if (SUCCEEDED(hr)) { LPITEMIDLIST pidl = ILCombine(pidlCpanel, m_pidl); if (FAILED(hr)) { hr = E_OUTOFMEMORY; } else { bool bItemIsBrowsable = false; IUnknown *punkSiteToRelease = NULL; if (NULL == punkSite) { // // No site provided. Let's use our site. // ASSERT(NULL != _punkSite); (punkSite = punkSiteToRelease = _punkSite)->AddRef(); } if (NULL != punkSite) { // // If we have a site pointer, try to browse the object in-place // if it is indeed browsable. // WCHAR szName[MAX_PATH]; ULONG rgfAttrs = SFGAO_BROWSABLE | SFGAO_FOLDER; hr = SHGetNameAndFlags(pidl, SHGDN_FORPARSING, szName, ARRAYSIZE(szName), &rgfAttrs); if (SUCCEEDED(hr)) { if ((SFGAO_BROWSABLE | SFGAO_FOLDER) & rgfAttrs) { // // Browse the object in-place. This is the path taken // by things like the "Printers" folder, "Scheduled Tasks" etc. // bItemIsBrowsable = true; IShellBrowser *psb; hr = CPL::ShellBrowserFromSite(punkSite, &psb); if (SUCCEEDED(hr)) { hr = CPL::BrowseIDListInPlace(pidl, psb); psb->Release(); } } } } if (NULL == punkSite || !bItemIsBrowsable) { // // Either we don't have a site ptr (can't get to the browser) // or the item is not browsable. Simply execute it. // This is the path taken by conventional CPL applets like // Mouse, Power Options, Display etc. // SHELLEXECUTEINFOW sei = { sizeof(sei), // cbSize; SEE_MASK_INVOKEIDLIST, // fMask NULL, // hwnd NULL, // lpVerb NULL, // lpFile NULL, // lpParameters NULL, // lpDirectory SW_SHOWNORMAL, // nShow 0, // hInstApp pidl, // lpIDList NULL, // lpClass NULL, // hkeyClass 0, // dwHotKey NULL, // hIcon NULL // hProcess }; if (!ShellExecuteExW(&sei)) { hr = ResultFromLastError(); } } ATOMICRELEASE(punkSiteToRelease); ILFree(pidl); } ILFree(pidlCpanel); } DBG_EXIT_HRES(FTF_CPANEL, "CCplUiCommandOnPidl::_Invoke", hr); return THR(hr); } HRESULT CCplUiCommandOnPidl::InvokeContextMenu( HWND hwndParent, const POINT *ppt ) { DBG_ENTER(FTF_CPANEL, "CCplUiCommandOnPidl::InvokeContextMenu"); ASSERT(NULL != ppt); ASSERT(NULL == hwndParent || IsWindow(hwndParent)); // // First build a full pidl to the item. // LPITEMIDLIST pidlCpanel; HRESULT hr = SHGetSpecialFolderLocation(hwndParent, CSIDL_CONTROLS, &pidlCpanel); if (SUCCEEDED(hr)) { LPITEMIDLIST pidlFull = ILCombine(pidlCpanel, m_pidl); if (NULL == pidlFull) { hr = E_OUTOFMEMORY; } else { // // Get the item's context menu interface from the shell. // IContextMenu *pcm; hr = SHGetUIObjectFromFullPIDL(pidlFull, hwndParent, IID_PPV_ARG(IContextMenu, &pcm)); if (SUCCEEDED(hr)) { ASSERT(NULL != _punkSite); IContextMenu *pcmNoDelete; hr = Create_ContextMenuWithoutVerbs(pcm, L"cut;delete", IID_PPV_ARG(IContextMenu, &pcmNoDelete)); if (SUCCEEDED(hr)) { hr = IUnknown_DoContextMenuPopup(_punkSite, pcmNoDelete, CMF_NORMAL, *ppt); pcmNoDelete->Release(); } pcm->Release(); } else { TraceMsg(TF_ERROR, "Shell item does not provide a context menu"); } ILFree(pidlFull); } ILFree(pidlCpanel); } DBG_EXIT_HRES(FTF_CPANEL, "CCplUiCommandOnPidl::InvokeContextMenu", hr); return THR(hr); } STDMETHODIMP CCplUiCommandOnPidl::GetDataObject( IDataObject **ppdtobj ) { return _GetDataObject(ppdtobj); } STDMETHODIMP CCplUiCommandOnPidl::LoadIcon( eCPIMGSIZE eSize, HICON *phIcon ) { IShellFolder *psf; HRESULT hr = CPL::GetControlPanelFolder(&psf); if (SUCCEEDED(hr)) { hr = CPL::ExtractIconFromPidl(psf, m_pidl, eSize, phIcon); psf->Release(); } return THR(hr); } STDMETHODIMP CCplUiCommandOnPidl::LoadName( LPWSTR *ppszName ) { HRESULT hr = _GetName(ppszName); return THR(hr); } STDMETHODIMP CCplUiCommandOnPidl::LoadTooltip( LPWSTR *ppszTooltip ) { HRESULT hr = _GetInfotip(ppszTooltip); return THR(hr); } HRESULT CCplUiCommandOnPidl::_Initialize( LPCITEMIDLIST pidl ) { ASSERT(NULL == m_pidl); ASSERT(NULL != pidl); HRESULT hr = E_OUTOFMEMORY; m_pidl = ILClone(pidl); if (NULL != m_pidl) { hr = S_OK; } return THR(hr); } HRESULT CCplUiCommandOnPidl::_GetControlPanelFolder( IShellFolder **ppsf ) { ASSERT(NULL != ppsf); ASSERT(!IsBadWritePtr(ppsf, sizeof(*ppsf))); HRESULT hr = S_OK; if (NULL == m_psf) { hr = CPL::GetControlPanelFolder(&m_psf); } *ppsf = m_psf; if (NULL != *ppsf) { (*ppsf)->AddRef(); } return THR(hr); } HRESULT CCplUiCommandOnPidl::_GetName( LPWSTR *ppszName ) { ASSERT(NULL != m_pidl); ASSERT(NULL != ppszName); ASSERT(!IsBadWritePtr(ppszName, sizeof(*ppszName))); *ppszName = NULL; IShellFolder *psf; HRESULT hr = _GetControlPanelFolder(&psf); if (SUCCEEDED(hr)) { STRRET strret; hr = psf->GetDisplayNameOf(m_pidl, SHGDN_INFOLDER, &strret); if (SUCCEEDED(hr)) { hr = StrRetToStrW(&strret, m_pidl, ppszName); } psf->Release(); } return THR(hr); } HRESULT CCplUiCommandOnPidl::_GetInfotip( LPWSTR *ppszInfotip ) { ASSERT(NULL != ppszInfotip); ASSERT(!IsBadWritePtr(ppszInfotip, sizeof(*ppszInfotip))); ASSERT(NULL != m_pidl); *ppszInfotip = NULL; IShellFolder *psf; HRESULT hr = _GetControlPanelFolder(&psf); if (SUCCEEDED(hr)) { IShellFolder2 *psf2; psf->QueryInterface(IID_PPV_ARG(IShellFolder2, &psf2)); if (SUCCEEDED(hr)) { TCHAR szBuf[256]; hr = GetStringProperty(psf2, m_pidl, &SCID_Comment, szBuf, ARRAYSIZE(szBuf)); if (SUCCEEDED(hr)) { hr = SHStrDup(szBuf, ppszInfotip); } psf2->Release(); } psf->Release(); } return THR(hr); } HRESULT CCplUiCommandOnPidl::_GetIconResource( LPWSTR *ppszIcon ) { ASSERT(NULL != ppszIcon); ASSERT(!IsBadWritePtr(ppszIcon, sizeof(*ppszIcon))); ASSERT(NULL != m_pidl); LPWSTR pszIconPath = NULL; IShellFolder *psf; HRESULT hr = _GetControlPanelFolder(&psf); if (SUCCEEDED(hr)) { IExtractIconW* pxi; hr = psf->GetUIObjectOf(NULL, 1, (LPCITEMIDLIST *)&m_pidl, IID_PPV_ARG_NULL(IExtractIconW, &pxi)); if (SUCCEEDED(hr)) { WCHAR szPath[MAX_PATH]; int iIndex; UINT wFlags = 0; hr = pxi->GetIconLocation(GIL_FORSHELL, szPath, ARRAYSIZE(szPath), &iIndex, &wFlags); if (SUCCEEDED(hr)) { const size_t cchIconPath = lstrlenW(szPath) + 15; pszIconPath = (LPWSTR)SHAlloc(cchIconPath * sizeof(WCHAR)); if (pszIconPath) { hr = StringCchPrintfW(pszIconPath, cchIconPath, L"%s,%d", szPath, iIndex); } else { hr = E_OUTOFMEMORY; } } pxi->Release(); } psf->Release(); } *ppszIcon = pszIconPath; return THR(hr); } HRESULT CCplUiCommandOnPidl::_GetDataObject( IDataObject **ppdtobj ) { ASSERT(NULL != ppdtobj); ASSERT(!IsBadWritePtr(ppdtobj, sizeof(*ppdtobj))); HRESULT hr = S_OK; if (NULL == m_pdtobj) { IShellFolder *psf; hr = _GetControlPanelFolder(&psf); if (SUCCEEDED(hr)) { hr = THR(psf->GetUIObjectOf(NULL, 1, (LPCITEMIDLIST *)&m_pidl, IID_PPV_ARG_NULL(IDataObject, &m_pdtobj))); psf->Release(); } } if (SUCCEEDED(hr)) { ASSERT(NULL != m_pdtobj); (*ppdtobj = m_pdtobj)->AddRef(); } return THR(hr); } STDMETHODIMP CCplUiCommandOnPidl::GetData( FORMATETC *pFmtEtc, STGMEDIUM *pstm ) { IDataObject *pdtobj; HRESULT hr = _GetDataObject(&pdtobj); if (SUCCEEDED(hr)) { hr = pdtobj->GetData(pFmtEtc, pstm); pdtobj->Release(); } return THR(hr); } STDMETHODIMP CCplUiCommandOnPidl::GetDataHere( FORMATETC *pFmtEtc, STGMEDIUM *pstm ) { IDataObject *pdtobj; HRESULT hr = _GetDataObject(&pdtobj); if (SUCCEEDED(hr)) { hr = pdtobj->GetDataHere(pFmtEtc, pstm); pdtobj->Release(); } return THR(hr); } STDMETHODIMP CCplUiCommandOnPidl::QueryGetData( FORMATETC *pFmtEtc ) { IDataObject *pdtobj; HRESULT hr = _GetDataObject(&pdtobj); if (SUCCEEDED(hr)) { hr = pdtobj->QueryGetData(pFmtEtc); pdtobj->Release(); } return THR(hr); } STDMETHODIMP CCplUiCommandOnPidl::GetCanonicalFormatEtc( FORMATETC *pFmtEtcIn, FORMATETC *pFmtEtcOut ) { IDataObject *pdtobj; HRESULT hr = _GetDataObject(&pdtobj); if (SUCCEEDED(hr)) { hr = pdtobj->GetCanonicalFormatEtc(pFmtEtcIn, pFmtEtcOut); pdtobj->Release(); } return THR(hr); } STDMETHODIMP CCplUiCommandOnPidl::SetData( FORMATETC *pFmtEtc, STGMEDIUM *pstm, BOOL fRelease ) { IDataObject *pdtobj; HRESULT hr = _GetDataObject(&pdtobj); if (SUCCEEDED(hr)) { hr = pdtobj->SetData(pFmtEtc, pstm, fRelease); pdtobj->Release(); } return THR(hr); } STDMETHODIMP CCplUiCommandOnPidl::EnumFormatEtc( DWORD dwDirection, LPENUMFORMATETC *ppEnum ) { IDataObject *pdtobj; HRESULT hr = _GetDataObject(&pdtobj); if (SUCCEEDED(hr)) { hr = pdtobj->EnumFormatEtc(dwDirection, ppEnum); pdtobj->Release(); } return THR(hr); } STDMETHODIMP CCplUiCommandOnPidl::DAdvise( FORMATETC *pFmtEtc, DWORD grfAdv, LPADVISESINK pAdvSink, DWORD *pdwConnection ) { IDataObject *pdtobj; HRESULT hr = _GetDataObject(&pdtobj); if (SUCCEEDED(hr)) { hr = pdtobj->DAdvise(pFmtEtc, grfAdv, pAdvSink, pdwConnection); pdtobj->Release(); } return THR(hr); } STDMETHODIMP CCplUiCommandOnPidl::DUnadvise( DWORD dwConnection ) { IDataObject *pdtobj; HRESULT hr = _GetDataObject(&pdtobj); if (SUCCEEDED(hr)) { hr = pdtobj->DUnadvise(dwConnection); pdtobj->Release(); } return THR(hr); } STDMETHODIMP CCplUiCommandOnPidl::EnumDAdvise( LPENUMSTATDATA *ppEnum ) { IDataObject *pdtobj; HRESULT hr = _GetDataObject(&pdtobj); if (SUCCEEDED(hr)) { hr = pdtobj->EnumDAdvise(ppEnum); pdtobj->Release(); } return THR(hr); } //----------------------------------------------------------------------------- // Public instance generators. //----------------------------------------------------------------------------- HRESULT Create_CplUiElement( LPCWSTR pszName, LPCWSTR pszInfotip, LPCWSTR pszIcon, REFIID riid, void **ppvOut ) { ASSERT(NULL != ppvOut); ASSERT(!IsBadWritePtr(ppvOut, sizeof(*ppvOut))); return CCplUiElement::CreateInstance(pszName, pszInfotip, pszIcon, riid, ppvOut); } HRESULT Create_CplUiCommand( LPCWSTR pszName, LPCWSTR pszInfotip, LPCWSTR pszIcon, const IAction *pAction, REFIID riid, void **ppvOut ) { ASSERT(NULL != ppvOut); ASSERT(!IsBadWritePtr(ppvOut, sizeof(*ppvOut))); return CCplUiCommand::CreateInstance(pszName, pszInfotip, pszIcon, pAction, riid, ppvOut); } HRESULT Create_CplUiCommandOnPidl( LPCITEMIDLIST pidl, REFIID riid, void **ppvOut ) { ASSERT(NULL != ppvOut); ASSERT(!IsBadWritePtr(ppvOut, sizeof(*ppvOut))); ASSERT(NULL != pidl); HRESULT hr = CCplUiCommandOnPidl::CreateInstance(pidl, riid, ppvOut); return THR(hr); } } // namespace CPL