383 lines
12 KiB
C++
383 lines
12 KiB
C++
#include "shellprv.h"
|
|
#pragma hdrstop
|
|
#include "basefvcb.h"
|
|
#include "mergfldr.h"
|
|
#include "enumidlist.h"
|
|
#include "ids.h"
|
|
#include "cdburn.h"
|
|
#include "contextmenu.h"
|
|
#include "datautil.h"
|
|
|
|
STDAPI CCDBurnFolder_CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv);
|
|
|
|
class CCDBurnFolder;
|
|
HRESULT CCDBurnFolder_CreateSFVCB(CCDBurnFolder* pcdsf, IShellFolderViewCB** ppsfvcb);
|
|
|
|
class CCDBurnFolder : public CMergedFolder
|
|
{
|
|
public:
|
|
// IUnknown
|
|
STDMETHOD (QueryInterface)(REFIID riid, void **ppv) { return CMergedFolder::QueryInterface(riid,ppv); }
|
|
STDMETHOD_(ULONG, AddRef)() { return CMergedFolder::AddRef(); }
|
|
STDMETHOD_(ULONG, Release)() { return CMergedFolder::Release(); }
|
|
|
|
// IShellFolder
|
|
STDMETHOD(CreateViewObject)(HWND hwndOwner, REFIID riid, void **ppvOut);
|
|
|
|
// IItemNameLimits
|
|
STDMETHOD(GetValidCharacters)(LPWSTR *ppwszValidChars, LPWSTR *ppwszInvalidChars);
|
|
STDMETHOD(GetMaxLength)(LPCWSTR pszName, int *piMaxNameLen);
|
|
|
|
protected:
|
|
CCDBurnFolder(CMergedFolder *pmfParent) : CMergedFolder(pmfParent, CLSID_CDBurnFolder) {};
|
|
friend HRESULT CCDBurnFolder_CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv);
|
|
virtual HRESULT _CreateWithCLSID(CLSID clsid, CMergedFolder **ppmf);
|
|
virtual BOOL _ShouldSuspend(REFGUID rguid);
|
|
|
|
private:
|
|
HRESULT _CreateContextMenu(IContextMenu **ppcm);
|
|
};
|
|
|
|
|
|
STDAPI CCDBurnFolder_CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv)
|
|
{
|
|
// class factory enforces non-aggregation for us
|
|
HRESULT hr = E_OUTOFMEMORY;
|
|
CCDBurnFolder *p = new CCDBurnFolder(NULL);
|
|
if (p)
|
|
{
|
|
hr = p->QueryInterface(riid, ppv);
|
|
p->Release();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CCDBurnFolder::_CreateContextMenu(IContextMenu **ppcm)
|
|
{
|
|
IShellExtInit *psei;
|
|
HRESULT hr = CoCreateInstance(CLSID_CDBurn, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IShellExtInit, &psei));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
IDataObject *pdo;
|
|
hr = SHGetUIObjectOf(_pidl, NULL, IID_PPV_ARG(IDataObject, &pdo));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = psei->Initialize(NULL, pdo, NULL);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = psei->QueryInterface(IID_PPV_ARG(IContextMenu, ppcm));
|
|
}
|
|
pdo->Release();
|
|
}
|
|
psei->Release();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CCDBurnFolder::CreateViewObject(HWND hwnd, REFIID riid, void **ppv)
|
|
{
|
|
HRESULT hr;
|
|
|
|
if (IsEqualIID(riid, IID_IShellView))
|
|
{
|
|
IShellFolderViewCB* psfvcb;
|
|
hr = CCDBurnFolder_CreateSFVCB(this, &psfvcb);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
SFV_CREATE csfv = {0};
|
|
csfv.cbSize = sizeof(csfv);
|
|
csfv.pshf = SAFECAST(this, IAugmentedShellFolder2*);
|
|
csfv.psfvcb = psfvcb;
|
|
|
|
hr = SHCreateShellFolderView(&csfv, (IShellView **)ppv);
|
|
|
|
psfvcb->Release();
|
|
}
|
|
}
|
|
else if (IsEqualIID(riid, IID_IContextMenu))
|
|
{
|
|
IContextMenu *pcmBase;
|
|
hr = CMergedFolder::CreateViewObject(hwnd, IID_PPV_ARG(IContextMenu, &pcmBase));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
IContextMenu *pcmCD;
|
|
hr = _CreateContextMenu(&pcmCD);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
IContextMenu* rgpcm[] = { pcmCD, pcmBase };
|
|
hr = Create_ContextMenuOnContextMenuArray(rgpcm, ARRAYSIZE(rgpcm), riid, ppv);
|
|
pcmCD->Release();
|
|
}
|
|
pcmBase->Release();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = CMergedFolder::CreateViewObject(hwnd, riid, ppv);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
// IItemNameLimits
|
|
|
|
HRESULT CCDBurnFolder::GetValidCharacters(LPWSTR *ppwszValidChars, LPWSTR *ppwszInvalidChars)
|
|
{
|
|
*ppwszValidChars = NULL;
|
|
return SHStrDup(INVALID_JOLIETNAME_CHARS, ppwszInvalidChars);
|
|
}
|
|
|
|
HRESULT CCDBurnFolder::GetMaxLength(LPCWSTR pszName, int *piMaxNameLen)
|
|
{
|
|
*piMaxNameLen = 64;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CCDBurnFolder::_CreateWithCLSID(CLSID clsid, CMergedFolder **ppmf)
|
|
{
|
|
*ppmf = new CCDBurnFolder(this);
|
|
return *ppmf ? S_OK : E_OUTOFMEMORY;
|
|
}
|
|
|
|
HRESULT _CDGetState(DWORD *pdwCaps, BOOL *pfUDF, BOOL *pfInStaging, BOOL *pfOnMedia)
|
|
{
|
|
ICDBurnPriv *pcdbp;
|
|
HRESULT hr = SHCoCreateInstance(NULL, &CLSID_CDBurn, NULL, IID_PPV_ARG(ICDBurnPriv, &pcdbp));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pcdbp->GetMediaCapabilities(pdwCaps, pfUDF);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pcdbp->GetContentState(pfInStaging, pfOnMedia);
|
|
}
|
|
pcdbp->Release();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
BOOL CCDBurnFolder::_ShouldSuspend(REFGUID rguid)
|
|
{
|
|
BOOL fShouldSuspend = FALSE;
|
|
if (IsEqualGUID(rguid, CLSID_StagingFolder))
|
|
{
|
|
// this gets called a lot, short circuit the cocreate and go direct to the data.
|
|
CDBurn_GetUDFState(&fShouldSuspend);
|
|
}
|
|
return fShouldSuspend;
|
|
}
|
|
|
|
class CCDBurnFolderViewCB : public CMergedFolderViewCB
|
|
{
|
|
public:
|
|
STDMETHODIMP RealMessage(UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
|
|
// IUnknown
|
|
STDMETHODIMP QueryInterface(REFIID riid, void **ppv) { return CMergedFolderViewCB::QueryInterface(riid,ppv); }
|
|
STDMETHODIMP_(ULONG) AddRef(void) { return CMergedFolderViewCB::AddRef(); }
|
|
STDMETHODIMP_(ULONG) Release(void) { return CMergedFolderViewCB::Release(); }
|
|
|
|
private:
|
|
CCDBurnFolderViewCB(CCDBurnFolder* pcdsf);
|
|
~CCDBurnFolderViewCB();
|
|
friend HRESULT CCDBurnFolder_CreateSFVCB(CCDBurnFolder* pcdsf, IShellFolderViewCB** ppsfvcb);
|
|
|
|
CCDBurnFolder* _pcdsf;
|
|
|
|
HRESULT OnGetWebViewLayout(DWORD pv, UINT uViewMode, SFVM_WEBVIEW_LAYOUT_DATA* pData);
|
|
HRESULT OnGetWebViewContent(DWORD pv, SFVM_WEBVIEW_CONTENT_DATA* pData);
|
|
HRESULT OnGetWebViewTasks(DWORD pv, SFVM_WEBVIEW_TASKSECTION_DATA* pTasks);
|
|
HRESULT OnGetWorkingDir(DWORD pv, UINT cch, PWSTR pszDir);
|
|
|
|
public:
|
|
// Web View Task implementations
|
|
static HRESULT _CanBurn(IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState);
|
|
static HRESULT _CanClear(IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState);
|
|
static HRESULT _CanErase(IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState);
|
|
|
|
static HRESULT _OnCDBurn(IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc);
|
|
static HRESULT _OnCDClearStaging(IUnknown* pv,IShellItemArray *psiItemArray, IBindCtx *pbc);
|
|
static HRESULT _OnCDErase(IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc);
|
|
};
|
|
|
|
CCDBurnFolderViewCB::CCDBurnFolderViewCB(CCDBurnFolder* pcdsf) : CMergedFolderViewCB((CMergedFolder*)pcdsf)
|
|
{
|
|
_pcdsf = pcdsf;
|
|
_pcdsf->AddRef();
|
|
}
|
|
|
|
CCDBurnFolderViewCB::~CCDBurnFolderViewCB()
|
|
{
|
|
_pcdsf->Release();
|
|
}
|
|
|
|
HRESULT CCDBurnFolder_CreateSFVCB(CCDBurnFolder* pcdsf, IShellFolderViewCB** ppsfvcb)
|
|
{
|
|
HRESULT hr;
|
|
CCDBurnFolderViewCB* p = new CCDBurnFolderViewCB(pcdsf);
|
|
if (p)
|
|
{
|
|
*ppsfvcb = SAFECAST(p, IShellFolderViewCB*);
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
*ppsfvcb = NULL;
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
STDMETHODIMP CCDBurnFolderViewCB::RealMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch (uMsg)
|
|
{
|
|
HANDLE_MSG(0, SFVM_GETWEBVIEWLAYOUT, OnGetWebViewLayout);
|
|
HANDLE_MSG(0, SFVM_GETWEBVIEWCONTENT, OnGetWebViewContent);
|
|
HANDLE_MSG(0, SFVM_GETWEBVIEWTASKS, OnGetWebViewTasks);
|
|
HANDLE_MSG(0, SFVM_GETWORKINGDIR, OnGetWorkingDir);
|
|
|
|
default:
|
|
return CMergedFolderViewCB::RealMessage(uMsg, wParam, lParam);
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CCDBurnFolderViewCB::OnGetWebViewLayout(DWORD pv, UINT uViewMode, SFVM_WEBVIEW_LAYOUT_DATA* pData)
|
|
{
|
|
ZeroMemory(pData, sizeof(*pData));
|
|
pData->dwLayout = SFVMWVL_NORMAL | SFVMWVL_FILES;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CCDBurnFolderViewCB::_CanBurn(IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState)
|
|
{
|
|
*puisState = UIS_DISABLED;
|
|
|
|
BOOL fUDF;
|
|
if (SUCCEEDED(_CDGetState(NULL, &fUDF, NULL, NULL)))
|
|
{
|
|
// UDF is the only thing we check for now, we allow burn wizard to kick off without media or files
|
|
if (!fUDF)
|
|
{
|
|
*puisState = UIS_ENABLED;
|
|
}
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CCDBurnFolderViewCB::_CanClear(IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState)
|
|
{
|
|
*puisState = UIS_DISABLED;
|
|
|
|
BOOL fInStaging, fUDF;
|
|
if (SUCCEEDED(_CDGetState(NULL, &fUDF, &fInStaging, NULL)))
|
|
{
|
|
if (fInStaging && !fUDF)
|
|
{
|
|
*puisState = UIS_ENABLED;
|
|
}
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CCDBurnFolderViewCB::_CanErase(IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState)
|
|
{
|
|
*puisState = UIS_DISABLED;
|
|
|
|
DWORD dwCaps;
|
|
BOOL fOnMedia, fUDF;
|
|
if (SUCCEEDED(_CDGetState(&dwCaps, &fUDF, NULL, &fOnMedia)))
|
|
{
|
|
if ((dwCaps & HWDMC_CDREWRITABLE) && (fOnMedia || fUDF))
|
|
{
|
|
*puisState = UIS_ENABLED;
|
|
}
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT _InvokeVerbOnCDBurn(HWND hwnd, LPCSTR pszVerb)
|
|
{
|
|
IContextMenu *pcm;
|
|
HRESULT hr = CoCreateInstance(CLSID_CDBurn, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IContextMenu, &pcm));
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = SHInvokeCommandOnContextMenu(hwnd, NULL, pcm, 0, pszVerb);
|
|
pcm->Release();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CCDBurnFolderViewCB::_OnCDBurn(IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc)
|
|
{
|
|
CCDBurnFolderViewCB* pThis = (CCDBurnFolderViewCB*)(void*)pv;
|
|
return _InvokeVerbOnCDBurn(pThis->_hwndMain, "burn");
|
|
}
|
|
HRESULT CCDBurnFolderViewCB::_OnCDClearStaging(IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc)
|
|
{
|
|
CCDBurnFolderViewCB* pThis = (CCDBurnFolderViewCB*)(void*)pv;
|
|
return _InvokeVerbOnCDBurn(pThis->_hwndMain, "cleanup");
|
|
}
|
|
HRESULT CCDBurnFolderViewCB::_OnCDErase(IUnknown* pv,IShellItemArray *psiItemArray, IBindCtx *pbc)
|
|
{
|
|
CCDBurnFolderViewCB* pThis = (CCDBurnFolderViewCB*)(void*)pv;
|
|
return _InvokeVerbOnCDBurn(pThis->_hwndMain, "erase");
|
|
}
|
|
|
|
const WVTASKITEM c_CDBurnTaskHeader = WVTI_HEADER(L"shell32.dll", IDS_HEADER_CDBURN, IDS_HEADER_CDBURN_TT);
|
|
const WVTASKITEM c_CDBurnTaskList[] =
|
|
{
|
|
WVTI_ENTRY_ALL(CLSID_NULL, L"shell32.dll", IDS_TASK_BURNCD, IDS_TASK_BURNCD_TT, IDI_TASK_BURNCD, CCDBurnFolderViewCB::_CanBurn, CCDBurnFolderViewCB::_OnCDBurn),
|
|
WVTI_ENTRY_ALL(CLSID_NULL, L"shell32.dll", IDS_TASK_CLEARBURNAREA, IDS_TASK_CLEARBURNAREA_TT, IDI_TASK_CLEARBURNAREA, CCDBurnFolderViewCB::_CanClear, CCDBurnFolderViewCB::_OnCDClearStaging),
|
|
WVTI_ENTRY_ALL(CLSID_NULL, L"shell32.dll", IDS_TASK_ERASECDFILES, IDS_TASK_ERASECDFILES_TT, IDI_TASK_ERASECDFILES, CCDBurnFolderViewCB::_CanErase, CCDBurnFolderViewCB::_OnCDErase),
|
|
};
|
|
|
|
HRESULT CCDBurnFolderViewCB::OnGetWebViewContent(DWORD pv, SFVM_WEBVIEW_CONTENT_DATA* pData)
|
|
{
|
|
ZeroMemory(pData, sizeof(*pData));
|
|
Create_IUIElement(&c_CDBurnTaskHeader, &(pData->pSpecialTaskHeader));
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CCDBurnFolderViewCB::OnGetWebViewTasks(DWORD pv, SFVM_WEBVIEW_TASKSECTION_DATA* pTasks)
|
|
{
|
|
ZeroMemory(pTasks, sizeof(*pTasks));
|
|
pTasks->dwUpdateFlags = SFVMWVTSDF_CONTENTSCHANGE;
|
|
Create_IEnumUICommand((IUnknown*)(void*)this, c_CDBurnTaskList, ARRAYSIZE(c_CDBurnTaskList), &pTasks->penumSpecialTasks);
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CCDBurnFolderViewCB::OnGetWorkingDir(DWORD pv, UINT cch, PWSTR pszDir)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
DWORD dwNSId;
|
|
GUID guid;
|
|
IShellFolder *psf;
|
|
BOOL fDone = FALSE;
|
|
for (DWORD dwIndex = 0;
|
|
!fDone && SUCCEEDED(_pmf->EnumNameSpace(dwIndex, &dwNSId)) && SUCCEEDED(_pmf->QueryNameSpace(dwNSId, &guid, &psf));
|
|
dwIndex++)
|
|
{
|
|
if (IsEqualGUID(guid, CLSID_CDBurn))
|
|
{
|
|
LPITEMIDLIST pidl;
|
|
hr = SHGetIDListFromUnk(psf, &pidl);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
WCHAR sz[MAX_PATH];
|
|
hr = SHGetPathFromIDList(pidl, sz) ? S_OK : E_FAIL;
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
lstrcpyn(pszDir, sz, cch);
|
|
}
|
|
ILFree(pidl);
|
|
}
|
|
fDone = TRUE;
|
|
}
|
|
psf->Release();
|
|
}
|
|
return hr;
|
|
}
|