Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

479 lines
14 KiB

#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)
{
hr = StringCchPrintf(psz, cch, L"%s,-%u", pTask->pszDllName, dwIndex);
}
else
{
hr = StringCchPrintf(psz, cch, L"@%s,-%u", pTask->pszDllName, dwIndex);
if (SUCCEEDED(hr))
{
hr = SHLoadIndirectString(psz, psz, cch, NULL);
}
}
if (FAILED(hr))
{
CoTaskMemFree(psz);
psz = 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()
{
ASSERT( 0 != _cRef );
ULONG cRef = InterlockedDecrement(&_cRef);
if ( 0 == cRef )
{
delete this;
}
return cRef;
}
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);
}
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()
{
ASSERT( 0 != _cRef );
ULONG cRef = InterlockedDecrement(&_cRef);
if ( 0 == cRef )
{
delete this;
}
return cRef;
}
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;
}