664 lines
18 KiB
C++
664 lines
18 KiB
C++
|
#include "shellprv.h"
|
||
|
#include "enumuicommand.h"
|
||
|
#include "datautil.h"
|
||
|
|
||
|
|
||
|
HRESULT CWVTASKITEM::_get_String(const WVTASKITEM* pTask,
|
||
|
DWORD dwIndex,
|
||
|
LPWSTR * ppsz,
|
||
|
DWORD cchMin,
|
||
|
BOOL bIsIcon)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
DWORD cchIcon = (unsigned)(lstrlen(pTask->pszDllName) + 9); // 9 = comma + minus + 2*65535 + \0
|
||
|
DWORD cch = bIsIcon
|
||
|
? cchIcon // "DLL,-0" string format required for loading icons from DLL resource
|
||
|
: max(cchIcon + 1, cchMin); // "@DLL,-0" string format required for loading strings from DLL resource
|
||
|
LPWSTR psz = (LPWSTR)CoTaskMemAlloc(cch * sizeof(WCHAR));
|
||
|
if (psz)
|
||
|
{
|
||
|
if (bIsIcon)
|
||
|
{
|
||
|
wnsprintf(psz, cch, L"%s,-%u", pTask->pszDllName, dwIndex);
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
wnsprintf(psz, cch, L"@%s,-%u", pTask->pszDllName, dwIndex);
|
||
|
hr = SHLoadIndirectString(psz, psz, cch, NULL);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
}
|
||
|
*ppsz = psz;
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
#define SS_UNKNOWN 0
|
||
|
#define SS_NOTSUPPORTED 1
|
||
|
#define SS_NONE 2
|
||
|
#define SS_FILE 3
|
||
|
#define SS_FOLDER 4
|
||
|
#define SS_MULTI 5
|
||
|
DWORD CWVTASKITEM::_GetSelectionState(const WVTASKITEM* pTask, IShellItemArray *psiItemArray)
|
||
|
{
|
||
|
DWORD dwSelectionState;
|
||
|
|
||
|
DWORD cItems = 0;
|
||
|
|
||
|
if (psiItemArray)
|
||
|
{
|
||
|
if (FAILED(psiItemArray->GetCount(&cItems)))
|
||
|
{
|
||
|
cItems = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
switch (cItems)
|
||
|
{
|
||
|
case 0:
|
||
|
dwSelectionState = SS_NONE;
|
||
|
break;
|
||
|
case 1:
|
||
|
{
|
||
|
DWORD dwAttribs = 0;
|
||
|
|
||
|
if (psiItemArray)
|
||
|
{
|
||
|
if (FAILED(psiItemArray->GetAttributes(SIATTRIBFLAGS_AND, SFGAO_FOLDER|SFGAO_STREAM,&dwAttribs)))
|
||
|
{
|
||
|
dwAttribs = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
switch (dwAttribs)
|
||
|
{
|
||
|
case SFGAO_FOLDER:
|
||
|
dwSelectionState = SS_FOLDER;
|
||
|
break;
|
||
|
case SFGAO_FOLDER|SFGAO_STREAM:
|
||
|
// zip and cab files are the only things that get here.
|
||
|
// we'll call them files unless somebody has a better idea
|
||
|
// (SS_MULTI has plurality that sounds funny).
|
||
|
// fall through
|
||
|
default:
|
||
|
dwSelectionState = SS_FILE;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
dwSelectionState = SS_MULTI;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if ((SS_NONE == dwSelectionState && 0 == pTask->dwTitleIndexNoSelection) ||
|
||
|
(SS_FILE == dwSelectionState && 0 == pTask->dwTitleIndexFileSelected) ||
|
||
|
(SS_FOLDER == dwSelectionState && 0 == pTask->dwTitleIndexFolderSelected) ||
|
||
|
(SS_MULTI == dwSelectionState && 0 == pTask->dwTitleIndexMultiSelected))
|
||
|
{
|
||
|
dwSelectionState = SS_NOTSUPPORTED;
|
||
|
}
|
||
|
|
||
|
return dwSelectionState;
|
||
|
}
|
||
|
|
||
|
HRESULT CWVTASKITEM::get_Name(const WVTASKITEM* pTask, IShellItemArray *psiItemArray, LPWSTR *ppszName)
|
||
|
{
|
||
|
DWORD dwSelState = _GetSelectionState(pTask, psiItemArray);
|
||
|
switch (dwSelState)
|
||
|
{
|
||
|
case SS_NONE: return _get_String(pTask, pTask->dwTitleIndexNoSelection, ppszName, MAX_PATH, FALSE);
|
||
|
case SS_FILE: return _get_String(pTask, pTask->dwTitleIndexFileSelected, ppszName, MAX_PATH, FALSE);
|
||
|
case SS_FOLDER: return _get_String(pTask, pTask->dwTitleIndexFolderSelected, ppszName, MAX_PATH, FALSE);
|
||
|
case SS_MULTI: return _get_String(pTask, pTask->dwTitleIndexMultiSelected, ppszName, MAX_PATH, FALSE);
|
||
|
}
|
||
|
*ppszName = NULL;
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
HRESULT CWVTASKITEM::get_Icon(const WVTASKITEM* pTask, IShellItemArray *psiItemArray, LPWSTR *ppszIcon)
|
||
|
{
|
||
|
return _get_String(pTask, pTask->dwIconIndex, ppszIcon, 0, TRUE);
|
||
|
}
|
||
|
HRESULT CWVTASKITEM::get_Tooltip(const WVTASKITEM* pTask, IShellItemArray *psiItemArray, LPWSTR *ppszInfotip)
|
||
|
{
|
||
|
return _get_String(pTask, pTask->dwTooltipIndex, ppszInfotip, INFOTIPSIZE, FALSE);
|
||
|
}
|
||
|
|
||
|
HRESULT CWVTASKITEM::get_CanonicalName(const WVTASKITEM* pTask, GUID* pguidCommandName)
|
||
|
{
|
||
|
*pguidCommandName = *(pTask->pguidCanonicalName);
|
||
|
return S_OK;
|
||
|
}
|
||
|
HRESULT CWVTASKITEM::get_State(const WVTASKITEM* pTask, IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
*puisState = UIS_DISABLED;
|
||
|
|
||
|
if (_GetSelectionState(pTask, psiItemArray) != SS_NOTSUPPORTED)
|
||
|
{
|
||
|
if (pTask->pfn_get_State)
|
||
|
hr = pTask->pfn_get_State(pv, psiItemArray, fOkToBeSlow, puisState);
|
||
|
else
|
||
|
*puisState = UIS_ENABLED;
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
HRESULT CWVTASKITEM::Invoke(const WVTASKITEM* pTask, IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc)
|
||
|
{
|
||
|
return pTask->pfn_Invoke(pv, psiItemArray, pbc);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
class CUIElement : public CWVTASKITEM, public IUIElement
|
||
|
{
|
||
|
public:
|
||
|
STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
|
||
|
STDMETHODIMP_(ULONG) AddRef();
|
||
|
STDMETHODIMP_(ULONG) Release();
|
||
|
// IUIElement
|
||
|
STDMETHODIMP get_Name(IShellItemArray *psiItemArray, LPWSTR *ppszName) {return CWVTASKITEM::get_Name(_pTask, psiItemArray, ppszName);}
|
||
|
STDMETHODIMP get_Icon(IShellItemArray *psiItemArray, LPWSTR *ppszIcon) {return CWVTASKITEM::get_Icon(_pTask, psiItemArray, ppszIcon);}
|
||
|
STDMETHODIMP get_Tooltip(IShellItemArray *psiItemArray, LPWSTR *ppszInfotip) {return CWVTASKITEM::get_Tooltip(_pTask, psiItemArray, ppszInfotip);}
|
||
|
|
||
|
friend HRESULT Create_IUIElement(const WVTASKITEM* pwvti, IUIElement**ppuie);
|
||
|
|
||
|
protected:
|
||
|
CUIElement(const WVTASKITEM* pTask) { _cRef = 1; _pTask=pTask; }
|
||
|
~CUIElement() {}
|
||
|
|
||
|
LONG _cRef;
|
||
|
const WVTASKITEM* _pTask;
|
||
|
};
|
||
|
|
||
|
HRESULT Create_IUIElement(const WVTASKITEM* pwvti, IUIElement**ppuie)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
if (NULL!=pwvti)
|
||
|
{
|
||
|
CUIElement* p = new CUIElement(pwvti);
|
||
|
if (p)
|
||
|
{
|
||
|
hr = p->QueryInterface(IID_PPV_ARG(IUIElement, ppuie));
|
||
|
p->Release();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
*ppuie = NULL;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TraceMsg(TF_WARNING, "Create_IUIElement: caller passed in bad pwvti.");
|
||
|
|
||
|
hr = E_INVALIDARG;
|
||
|
*ppuie = NULL;
|
||
|
}
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT CUIElement::QueryInterface(REFIID riid, void **ppv)
|
||
|
{
|
||
|
static const QITAB qit[] = {
|
||
|
QITABENT(CUIElement, IUIElement),
|
||
|
{ 0 },
|
||
|
};
|
||
|
return QISearch(this, qit, riid, ppv);
|
||
|
}
|
||
|
ULONG CUIElement::AddRef()
|
||
|
{
|
||
|
return InterlockedIncrement(&_cRef);
|
||
|
}
|
||
|
ULONG CUIElement::Release()
|
||
|
{
|
||
|
if (InterlockedDecrement(&_cRef))
|
||
|
return _cRef;
|
||
|
|
||
|
delete this;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
class CUICommand : public CUIElement, public IUICommand
|
||
|
{
|
||
|
public:
|
||
|
STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
|
||
|
STDMETHODIMP_(ULONG) AddRef() { return CUIElement::AddRef(); }
|
||
|
STDMETHODIMP_(ULONG) Release() { return CUIElement::Release(); }
|
||
|
// IUICommand
|
||
|
STDMETHODIMP get_Name(IShellItemArray *psiItemArray, LPWSTR *ppszName) { return CUIElement::get_Name(psiItemArray, ppszName); }
|
||
|
STDMETHODIMP get_Icon(IShellItemArray *psiItemArray, LPWSTR *ppszIcon) { return CUIElement::get_Icon(psiItemArray, ppszIcon); }
|
||
|
STDMETHODIMP get_Tooltip(IShellItemArray *psiItemArray, LPWSTR *ppszInfotip) { return CUIElement::get_Tooltip(psiItemArray, ppszInfotip); }
|
||
|
STDMETHODIMP get_CanonicalName(GUID* pguidCommandName) { return CWVTASKITEM::get_CanonicalName(_pTask, pguidCommandName); }
|
||
|
STDMETHODIMP get_State(IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState) { return CWVTASKITEM::get_State(_pTask, _pv, psiItemArray, fOkToBeSlow, puisState); }
|
||
|
STDMETHODIMP Invoke(IShellItemArray *psiItemArray, IBindCtx *pbc) { return CWVTASKITEM::Invoke(_pTask, _pv, psiItemArray, pbc); }
|
||
|
|
||
|
friend HRESULT Create_IUICommand(IUnknown* pv, const WVTASKITEM* pwvti, IUICommand**ppuic);
|
||
|
|
||
|
private:
|
||
|
CUICommand(IUnknown* pv, const WVTASKITEM* pTask);
|
||
|
~CUICommand();
|
||
|
|
||
|
IUnknown* _pv;
|
||
|
};
|
||
|
|
||
|
HRESULT Create_IUICommand(IUnknown* pv, const WVTASKITEM* pwvti, IUICommand**ppuic)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
if (NULL!=pwvti)
|
||
|
{
|
||
|
CUICommand* p = new CUICommand(pv, pwvti);
|
||
|
if (p)
|
||
|
{
|
||
|
hr = p->QueryInterface(IID_PPV_ARG(IUICommand, ppuic));
|
||
|
p->Release();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
*ppuic = NULL;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TraceMsg(TF_WARNING, "Create_IUICommand: caller passed in bad pwvti.");
|
||
|
|
||
|
hr = E_INVALIDARG;
|
||
|
*ppuic = NULL;
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
CUICommand::CUICommand(IUnknown* pv, const WVTASKITEM* pTask)
|
||
|
: CUIElement(pTask)
|
||
|
{
|
||
|
_pv = pv;
|
||
|
if (_pv)
|
||
|
_pv->AddRef();
|
||
|
}
|
||
|
CUICommand::~CUICommand()
|
||
|
{
|
||
|
if (_pv)
|
||
|
_pv->Release();
|
||
|
}
|
||
|
|
||
|
HRESULT CUICommand::QueryInterface(REFIID riid, void **ppv)
|
||
|
{
|
||
|
static const QITAB qit[] = {
|
||
|
QITABENT(CUICommand, IUICommand),
|
||
|
QITABENTMULTI(CUICommand, IUIElement, IUICommand),
|
||
|
{ 0 },
|
||
|
};
|
||
|
return QISearch(this, qit, riid, ppv);
|
||
|
}
|
||
|
|
||
|
|
||
|
#if 0 // { CUICommandOnPidl is currently not used, may come back for RC1
|
||
|
|
||
|
// a IUICommand wrapper around an IShellItem interface
|
||
|
//
|
||
|
class CUICommandOnPidl : public IUICommand
|
||
|
{
|
||
|
public:
|
||
|
STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
|
||
|
STDMETHODIMP_(ULONG) AddRef();
|
||
|
STDMETHODIMP_(ULONG) Release();
|
||
|
// IUICommand
|
||
|
STDMETHODIMP get_Name(IShellItemArray *psiItemArray, LPWSTR *ppszName);
|
||
|
STDMETHODIMP get_Icon(IShellItemArray *psiItemArray, LPWSTR *ppszIcon);
|
||
|
STDMETHODIMP get_Tooltip(IShellItemArray *psiItemArray, LPWSTR *ppszInfotip);
|
||
|
STDMETHODIMP get_CanonicalName(GUID* pguidCommandName);
|
||
|
STDMETHODIMP get_State(IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState);
|
||
|
STDMETHODIMP Invoke(IShellItemArray *psiItemArray, IBindCtx *pbc);
|
||
|
|
||
|
friend HRESULT Create_UICommandFromParseName(LPCWSTR pszParseName, REFGUID guidCanonicalName, HINSTANCE hinst, int idsName, int idsTip, IUICommand** ppuiCommand);
|
||
|
|
||
|
private:
|
||
|
CUICommandOnPidl() { _cRef = 1; }
|
||
|
~CUICommandOnPidl();
|
||
|
HRESULT Initialize(LPCWSTR pszParseName, REFGUID guidCanonicalName, HINSTANCE hinst, int idsName, int idsTip);
|
||
|
|
||
|
LONG _cRef;
|
||
|
|
||
|
const GUID* _pguidCanonicalName;
|
||
|
|
||
|
IShellFolder* _psf;
|
||
|
LPCITEMIDLIST _pidl;
|
||
|
LPITEMIDLIST _pidlAbsolute;
|
||
|
|
||
|
// optional hinst,idsName,idsTip to override display text for the item
|
||
|
HINSTANCE _hinst;
|
||
|
int _idsName;
|
||
|
int _idsTip;
|
||
|
};
|
||
|
|
||
|
HRESULT Create_UICommandFromParseName(LPCWSTR pszParseName, REFGUID guidCanonicalName, HINSTANCE hinst, int idsName, int idsTip, IUICommand** ppuiCommand)
|
||
|
{
|
||
|
HRESULT hr = E_OUTOFMEMORY;
|
||
|
|
||
|
*ppuiCommand = NULL;
|
||
|
|
||
|
CUICommandOnPidl* p = new CUICommandOnPidl();
|
||
|
if (p)
|
||
|
{
|
||
|
if (SUCCEEDED(p->Initialize(pszParseName, guidCanonicalName, hinst, idsName, idsTip)))
|
||
|
{
|
||
|
hr = p->QueryInterface(IID_PPV_ARG(IUICommand, ppuiCommand));
|
||
|
}
|
||
|
p->Release();
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT CUICommandOnPidl::Initialize(LPCWSTR pszParseName, REFGUID guidCanonicalName, HINSTANCE hinst, int idsName, int idsTip)
|
||
|
{
|
||
|
_pguidCanonicalName = &guidCanonicalName;
|
||
|
|
||
|
IShellFolder* psfDesktop;
|
||
|
HRESULT hr = SHGetDesktopFolder(&psfDesktop);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = psfDesktop->ParseDisplayName(NULL, NULL, (LPOLESTR)pszParseName, NULL, &_pidlAbsolute, NULL);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = SHBindToIDListParent(_pidlAbsolute, IID_PPV_ARG(IShellFolder, &_psf), &_pidl);
|
||
|
|
||
|
_hinst = hinst;
|
||
|
_idsName = idsName;
|
||
|
_idsTip = idsTip;
|
||
|
}
|
||
|
psfDesktop->Release();
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
CUICommandOnPidl::~CUICommandOnPidl()
|
||
|
{
|
||
|
if (_psf)
|
||
|
_psf->Release();
|
||
|
|
||
|
ILFree(_pidlAbsolute);
|
||
|
}
|
||
|
|
||
|
HRESULT CUICommandOnPidl::QueryInterface(REFIID riid, void **ppv)
|
||
|
{
|
||
|
static const QITAB qit[] = {
|
||
|
QITABENT(CUICommandOnPidl, IUICommand),
|
||
|
QITABENTMULTI(CUICommandOnPidl, IUIElement, IUICommand),
|
||
|
{ 0 },
|
||
|
};
|
||
|
return QISearch(this, qit, riid, ppv);
|
||
|
}
|
||
|
ULONG CUICommandOnPidl::AddRef()
|
||
|
{
|
||
|
return InterlockedIncrement(&_cRef);
|
||
|
}
|
||
|
ULONG CUICommandOnPidl::Release()
|
||
|
{
|
||
|
if (InterlockedDecrement(&_cRef))
|
||
|
return _cRef;
|
||
|
|
||
|
delete this;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
HRESULT CUICommandOnPidl::get_Name(IShellItemArray *psiItemArray, LPWSTR *ppszName)
|
||
|
{
|
||
|
if (_hinst && _idsName)
|
||
|
{
|
||
|
// TODO: load the string... but we have to fix dui to handle direct strings!
|
||
|
return DisplayNameOfAsOLESTR(_psf, _pidl, SHGDN_INFOLDER, ppszName);
|
||
|
}
|
||
|
else
|
||
|
return DisplayNameOfAsOLESTR(_psf, _pidl, SHGDN_INFOLDER, ppszName);
|
||
|
}
|
||
|
HRESULT CUICommandOnPidl::get_Icon(IShellItemArray *psiItemArray, LPWSTR *ppszIcon)
|
||
|
{
|
||
|
LPWSTR pszIconPath = NULL;
|
||
|
|
||
|
// TODO: use SHGetIconFromPIDL so we get system imagelist support
|
||
|
|
||
|
IExtractIcon* pxi;
|
||
|
HRESULT hr = _psf->GetUIObjectOf(NULL, 1, &_pidl, IID_PPV_ARG_NULL(IExtractIcon, &pxi));
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
WCHAR szPath[MAX_PATH];
|
||
|
int iIndex;
|
||
|
UINT wFlags=0;
|
||
|
|
||
|
// BUGBUG: assume the location is a proper dll,-id value...
|
||
|
hr = pxi->GetIconLocation(GIL_FORSHELL, szPath, ARRAYSIZE(szPath), &iIndex, &wFlags);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
pszIconPath = (LPWSTR)SHAlloc(sizeof(WCHAR)*(lstrlen(szPath)+1+8));
|
||
|
if (pszIconPath)
|
||
|
{
|
||
|
wsprintf(pszIconPath,L"%s,%d", szPath, iIndex);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pxi->Release();
|
||
|
}
|
||
|
|
||
|
*ppszIcon = pszIconPath;
|
||
|
return hr;
|
||
|
}
|
||
|
HRESULT CUICommandOnPidl::get_Tooltip(IShellItemArray *psiItemArray, LPWSTR *ppszInfotip)
|
||
|
{
|
||
|
*ppszInfotip = NULL;
|
||
|
|
||
|
if (_hinst && _idsName)
|
||
|
{
|
||
|
// TODO: load the string... but we have to fix dui to handle direct strings!
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
else
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
|
||
|
HRESULT CUICommandOnPidl::get_CanonicalName(GUID* pguidCommandName)
|
||
|
{
|
||
|
*pguidCommandName = *_pguidCanonicalName;
|
||
|
return S_OK;
|
||
|
}
|
||
|
HRESULT CUICommandOnPidl::get_State(IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState)
|
||
|
{
|
||
|
*puisState = UIS_ENABLED;
|
||
|
return S_OK;
|
||
|
}
|
||
|
HRESULT CUICommandOnPidl::Invoke(IIShellItemArray *psiItemArray, IBindCtx *pbc)
|
||
|
{
|
||
|
SHELLEXECUTEINFO sei = { 0 };
|
||
|
sei.cbSize = sizeof(sei);
|
||
|
sei.lpIDList = _pidlAbsolute;
|
||
|
sei.fMask = SEE_MASK_IDLIST;
|
||
|
sei.nShow = SW_SHOWNORMAL;
|
||
|
|
||
|
return ShellExecuteEx(&sei) ? S_OK : E_FAIL;
|
||
|
}
|
||
|
|
||
|
#endif // } CUICommandOnPidl may come back for RC1
|
||
|
|
||
|
|
||
|
class CEnumUICommand : public IEnumUICommand
|
||
|
{
|
||
|
public:
|
||
|
STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
|
||
|
STDMETHODIMP_(ULONG) AddRef();
|
||
|
STDMETHODIMP_(ULONG) Release();
|
||
|
// IEnumUICommand
|
||
|
STDMETHODIMP Next(ULONG celt, IUICommand** pUICommand, ULONG *pceltFetched);
|
||
|
STDMETHODIMP Skip(ULONG celt);
|
||
|
STDMETHODIMP Reset();
|
||
|
STDMETHODIMP Clone(IEnumUICommand **ppenum);
|
||
|
|
||
|
friend HRESULT Create_IEnumUICommandWithArray(IUnknown *pv, const WVTASKITEM* rgwvti, UINT cwvti, IUICommand** rguiCommand, UINT cuiCommand, IEnumUICommand**ppenum);
|
||
|
|
||
|
private:
|
||
|
CEnumUICommand(IUnknown *pv, const WVTASKITEM* rgwvti, ULONG cwvti, IUICommand** rguiCommand, UINT cuiCommand);
|
||
|
~CEnumUICommand();
|
||
|
|
||
|
LONG _cRef;
|
||
|
IUnknown* _pv;
|
||
|
const WVTASKITEM* _rgwvti;
|
||
|
ULONG _cItems;
|
||
|
IUICommand** _prguiCommand;
|
||
|
ULONG _cuiCommand;
|
||
|
ULONG _ulIndex;
|
||
|
};
|
||
|
|
||
|
HRESULT Create_IEnumUICommandWithArray(IUnknown *pv, const WVTASKITEM* rgwvti, UINT cwvti, IUICommand** rguiCommand, UINT cuiCommand, IEnumUICommand**ppenum)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
if (NULL!=rgwvti)
|
||
|
{
|
||
|
CEnumUICommand* p = new CEnumUICommand(pv, rgwvti, cwvti, rguiCommand, cuiCommand);
|
||
|
if (p)
|
||
|
{
|
||
|
hr = p->QueryInterface(IID_PPV_ARG(IEnumUICommand, ppenum));
|
||
|
p->Release();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
*ppenum = NULL;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
TraceMsg(TF_WARNING, "Create_IEnumUICommand: caller passed in bad pwvti.");
|
||
|
|
||
|
hr = E_INVALIDARG;
|
||
|
*ppenum = NULL;
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT Create_IEnumUICommand(IUnknown *pv, const WVTASKITEM* rgwvti, UINT cwvti, IEnumUICommand**ppenum)
|
||
|
{
|
||
|
return Create_IEnumUICommandWithArray(pv, rgwvti, cwvti, NULL, 0, ppenum);
|
||
|
}
|
||
|
|
||
|
CEnumUICommand::CEnumUICommand(IUnknown *pv, const WVTASKITEM* rgwvti, ULONG cwvti, IUICommand** rguiCommand, UINT cuiCommand)
|
||
|
{
|
||
|
if (pv)
|
||
|
{
|
||
|
_pv = pv;
|
||
|
_pv->AddRef();
|
||
|
}
|
||
|
|
||
|
_rgwvti = rgwvti;
|
||
|
_cItems = cwvti;
|
||
|
|
||
|
if (cuiCommand)
|
||
|
{
|
||
|
_prguiCommand = (IUICommand**)LocalAlloc(LPTR, cuiCommand*sizeof(IUICommand*));
|
||
|
if (_prguiCommand)
|
||
|
{
|
||
|
for (UINT i = 0 ; i < cuiCommand && rguiCommand[i]; i++)
|
||
|
{
|
||
|
_prguiCommand[i] = rguiCommand[i];
|
||
|
_prguiCommand[i]->AddRef();
|
||
|
}
|
||
|
_cuiCommand = i;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
_cRef = 1;
|
||
|
}
|
||
|
CEnumUICommand::~CEnumUICommand()
|
||
|
{
|
||
|
if (_pv)
|
||
|
_pv->Release();
|
||
|
|
||
|
if (_prguiCommand)
|
||
|
{
|
||
|
for (UINT i = 0 ; i < _cuiCommand ; i++)
|
||
|
_prguiCommand[i]->Release();
|
||
|
LocalFree(_prguiCommand);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
HRESULT CEnumUICommand::QueryInterface(REFIID riid, void **ppv)
|
||
|
{
|
||
|
static const QITAB qit[] = {
|
||
|
QITABENT(CEnumUICommand, IEnumUICommand),
|
||
|
{ 0 },
|
||
|
};
|
||
|
return QISearch(this, qit, riid, ppv);
|
||
|
}
|
||
|
ULONG CEnumUICommand::AddRef()
|
||
|
{
|
||
|
return InterlockedIncrement(&_cRef);
|
||
|
}
|
||
|
ULONG CEnumUICommand::Release()
|
||
|
{
|
||
|
if (InterlockedDecrement(&_cRef))
|
||
|
return _cRef;
|
||
|
|
||
|
delete this;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
HRESULT CEnumUICommand::Next(ULONG celt, IUICommand** ppUICommand, ULONG *pceltFetched)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
if (_ulIndex < _cItems)
|
||
|
{
|
||
|
hr = Create_IUICommand(_pv, &_rgwvti[_ulIndex++], ppUICommand);
|
||
|
}
|
||
|
else if (_ulIndex < _cItems + _cuiCommand)
|
||
|
{
|
||
|
*ppUICommand = _prguiCommand[_ulIndex++ - _cItems];
|
||
|
(*ppUICommand)->AddRef();
|
||
|
hr = S_OK;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*ppUICommand = NULL;
|
||
|
hr = S_FALSE;
|
||
|
}
|
||
|
|
||
|
if (pceltFetched)
|
||
|
*pceltFetched = (hr == S_OK) ? 1 : 0;
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HRESULT CEnumUICommand::Skip(ULONG celt)
|
||
|
{
|
||
|
_ulIndex = min(_cItems, _ulIndex+celt);
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
HRESULT CEnumUICommand::Reset()
|
||
|
{
|
||
|
_ulIndex = 0;
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
HRESULT CEnumUICommand::Clone(IEnumUICommand **ppenum)
|
||
|
{
|
||
|
*ppenum = NULL;
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
|