#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; }