Source code of Windows XP (NT5)
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.

382 lines
12 KiB

  1. #include "shellprv.h"
  2. #pragma hdrstop
  3. #include "basefvcb.h"
  4. #include "mergfldr.h"
  5. #include "enumidlist.h"
  6. #include "ids.h"
  7. #include "cdburn.h"
  8. #include "contextmenu.h"
  9. #include "datautil.h"
  10. STDAPI CCDBurnFolder_CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv);
  11. class CCDBurnFolder;
  12. HRESULT CCDBurnFolder_CreateSFVCB(CCDBurnFolder* pcdsf, IShellFolderViewCB** ppsfvcb);
  13. class CCDBurnFolder : public CMergedFolder
  14. {
  15. public:
  16. // IUnknown
  17. STDMETHOD (QueryInterface)(REFIID riid, void **ppv) { return CMergedFolder::QueryInterface(riid,ppv); }
  18. STDMETHOD_(ULONG, AddRef)() { return CMergedFolder::AddRef(); }
  19. STDMETHOD_(ULONG, Release)() { return CMergedFolder::Release(); }
  20. // IShellFolder
  21. STDMETHOD(CreateViewObject)(HWND hwndOwner, REFIID riid, void **ppvOut);
  22. // IItemNameLimits
  23. STDMETHOD(GetValidCharacters)(LPWSTR *ppwszValidChars, LPWSTR *ppwszInvalidChars);
  24. STDMETHOD(GetMaxLength)(LPCWSTR pszName, int *piMaxNameLen);
  25. protected:
  26. CCDBurnFolder(CMergedFolder *pmfParent) : CMergedFolder(pmfParent, CLSID_CDBurnFolder) {};
  27. friend HRESULT CCDBurnFolder_CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv);
  28. virtual HRESULT _CreateWithCLSID(CLSID clsid, CMergedFolder **ppmf);
  29. virtual BOOL _ShouldSuspend(REFGUID rguid);
  30. private:
  31. HRESULT _CreateContextMenu(IContextMenu **ppcm);
  32. };
  33. STDAPI CCDBurnFolder_CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv)
  34. {
  35. // class factory enforces non-aggregation for us
  36. HRESULT hr = E_OUTOFMEMORY;
  37. CCDBurnFolder *p = new CCDBurnFolder(NULL);
  38. if (p)
  39. {
  40. hr = p->QueryInterface(riid, ppv);
  41. p->Release();
  42. }
  43. return hr;
  44. }
  45. HRESULT CCDBurnFolder::_CreateContextMenu(IContextMenu **ppcm)
  46. {
  47. IShellExtInit *psei;
  48. HRESULT hr = CoCreateInstance(CLSID_CDBurn, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IShellExtInit, &psei));
  49. if (SUCCEEDED(hr))
  50. {
  51. IDataObject *pdo;
  52. hr = SHGetUIObjectOf(_pidl, NULL, IID_PPV_ARG(IDataObject, &pdo));
  53. if (SUCCEEDED(hr))
  54. {
  55. hr = psei->Initialize(NULL, pdo, NULL);
  56. if (SUCCEEDED(hr))
  57. {
  58. hr = psei->QueryInterface(IID_PPV_ARG(IContextMenu, ppcm));
  59. }
  60. pdo->Release();
  61. }
  62. psei->Release();
  63. }
  64. return hr;
  65. }
  66. STDMETHODIMP CCDBurnFolder::CreateViewObject(HWND hwnd, REFIID riid, void **ppv)
  67. {
  68. HRESULT hr;
  69. if (IsEqualIID(riid, IID_IShellView))
  70. {
  71. IShellFolderViewCB* psfvcb;
  72. hr = CCDBurnFolder_CreateSFVCB(this, &psfvcb);
  73. if (SUCCEEDED(hr))
  74. {
  75. SFV_CREATE csfv = {0};
  76. csfv.cbSize = sizeof(csfv);
  77. csfv.pshf = SAFECAST(this, IAugmentedShellFolder2*);
  78. csfv.psfvcb = psfvcb;
  79. hr = SHCreateShellFolderView(&csfv, (IShellView **)ppv);
  80. psfvcb->Release();
  81. }
  82. }
  83. else if (IsEqualIID(riid, IID_IContextMenu))
  84. {
  85. IContextMenu *pcmBase;
  86. hr = CMergedFolder::CreateViewObject(hwnd, IID_PPV_ARG(IContextMenu, &pcmBase));
  87. if (SUCCEEDED(hr))
  88. {
  89. IContextMenu *pcmCD;
  90. hr = _CreateContextMenu(&pcmCD);
  91. if (SUCCEEDED(hr))
  92. {
  93. IContextMenu* rgpcm[] = { pcmCD, pcmBase };
  94. hr = Create_ContextMenuOnContextMenuArray(rgpcm, ARRAYSIZE(rgpcm), riid, ppv);
  95. pcmCD->Release();
  96. }
  97. pcmBase->Release();
  98. }
  99. }
  100. else
  101. {
  102. hr = CMergedFolder::CreateViewObject(hwnd, riid, ppv);
  103. }
  104. return hr;
  105. }
  106. // IItemNameLimits
  107. HRESULT CCDBurnFolder::GetValidCharacters(LPWSTR *ppwszValidChars, LPWSTR *ppwszInvalidChars)
  108. {
  109. *ppwszValidChars = NULL;
  110. return SHStrDup(INVALID_JOLIETNAME_CHARS, ppwszInvalidChars);
  111. }
  112. HRESULT CCDBurnFolder::GetMaxLength(LPCWSTR pszName, int *piMaxNameLen)
  113. {
  114. *piMaxNameLen = 64;
  115. return S_OK;
  116. }
  117. HRESULT CCDBurnFolder::_CreateWithCLSID(CLSID clsid, CMergedFolder **ppmf)
  118. {
  119. *ppmf = new CCDBurnFolder(this);
  120. return *ppmf ? S_OK : E_OUTOFMEMORY;
  121. }
  122. HRESULT _CDGetState(DWORD *pdwCaps, BOOL *pfUDF, BOOL *pfInStaging, BOOL *pfOnMedia)
  123. {
  124. ICDBurnPriv *pcdbp;
  125. HRESULT hr = SHCoCreateInstance(NULL, &CLSID_CDBurn, NULL, IID_PPV_ARG(ICDBurnPriv, &pcdbp));
  126. if (SUCCEEDED(hr))
  127. {
  128. hr = pcdbp->GetMediaCapabilities(pdwCaps, pfUDF);
  129. if (SUCCEEDED(hr))
  130. {
  131. hr = pcdbp->GetContentState(pfInStaging, pfOnMedia);
  132. }
  133. pcdbp->Release();
  134. }
  135. return hr;
  136. }
  137. BOOL CCDBurnFolder::_ShouldSuspend(REFGUID rguid)
  138. {
  139. BOOL fShouldSuspend = FALSE;
  140. if (IsEqualGUID(rguid, CLSID_StagingFolder))
  141. {
  142. // this gets called a lot, short circuit the cocreate and go direct to the data.
  143. CDBurn_GetUDFState(&fShouldSuspend);
  144. }
  145. return fShouldSuspend;
  146. }
  147. class CCDBurnFolderViewCB : public CMergedFolderViewCB
  148. {
  149. public:
  150. STDMETHODIMP RealMessage(UINT uMsg, WPARAM wParam, LPARAM lParam);
  151. // IUnknown
  152. STDMETHODIMP QueryInterface(REFIID riid, void **ppv) { return CMergedFolderViewCB::QueryInterface(riid,ppv); }
  153. STDMETHODIMP_(ULONG) AddRef(void) { return CMergedFolderViewCB::AddRef(); }
  154. STDMETHODIMP_(ULONG) Release(void) { return CMergedFolderViewCB::Release(); }
  155. private:
  156. CCDBurnFolderViewCB(CCDBurnFolder* pcdsf);
  157. ~CCDBurnFolderViewCB();
  158. friend HRESULT CCDBurnFolder_CreateSFVCB(CCDBurnFolder* pcdsf, IShellFolderViewCB** ppsfvcb);
  159. CCDBurnFolder* _pcdsf;
  160. HRESULT OnGetWebViewLayout(DWORD pv, UINT uViewMode, SFVM_WEBVIEW_LAYOUT_DATA* pData);
  161. HRESULT OnGetWebViewContent(DWORD pv, SFVM_WEBVIEW_CONTENT_DATA* pData);
  162. HRESULT OnGetWebViewTasks(DWORD pv, SFVM_WEBVIEW_TASKSECTION_DATA* pTasks);
  163. HRESULT OnGetWorkingDir(DWORD pv, UINT cch, PWSTR pszDir);
  164. public:
  165. // Web View Task implementations
  166. static HRESULT _CanBurn(IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState);
  167. static HRESULT _CanClear(IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState);
  168. static HRESULT _CanErase(IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState);
  169. static HRESULT _OnCDBurn(IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc);
  170. static HRESULT _OnCDClearStaging(IUnknown* pv,IShellItemArray *psiItemArray, IBindCtx *pbc);
  171. static HRESULT _OnCDErase(IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc);
  172. };
  173. CCDBurnFolderViewCB::CCDBurnFolderViewCB(CCDBurnFolder* pcdsf) : CMergedFolderViewCB((CMergedFolder*)pcdsf)
  174. {
  175. _pcdsf = pcdsf;
  176. _pcdsf->AddRef();
  177. }
  178. CCDBurnFolderViewCB::~CCDBurnFolderViewCB()
  179. {
  180. _pcdsf->Release();
  181. }
  182. HRESULT CCDBurnFolder_CreateSFVCB(CCDBurnFolder* pcdsf, IShellFolderViewCB** ppsfvcb)
  183. {
  184. HRESULT hr;
  185. CCDBurnFolderViewCB* p = new CCDBurnFolderViewCB(pcdsf);
  186. if (p)
  187. {
  188. *ppsfvcb = SAFECAST(p, IShellFolderViewCB*);
  189. hr = S_OK;
  190. }
  191. else
  192. {
  193. *ppsfvcb = NULL;
  194. hr = E_OUTOFMEMORY;
  195. }
  196. return hr;
  197. }
  198. STDMETHODIMP CCDBurnFolderViewCB::RealMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
  199. {
  200. switch (uMsg)
  201. {
  202. HANDLE_MSG(0, SFVM_GETWEBVIEWLAYOUT, OnGetWebViewLayout);
  203. HANDLE_MSG(0, SFVM_GETWEBVIEWCONTENT, OnGetWebViewContent);
  204. HANDLE_MSG(0, SFVM_GETWEBVIEWTASKS, OnGetWebViewTasks);
  205. HANDLE_MSG(0, SFVM_GETWORKINGDIR, OnGetWorkingDir);
  206. default:
  207. return CMergedFolderViewCB::RealMessage(uMsg, wParam, lParam);
  208. }
  209. return S_OK;
  210. }
  211. HRESULT CCDBurnFolderViewCB::OnGetWebViewLayout(DWORD pv, UINT uViewMode, SFVM_WEBVIEW_LAYOUT_DATA* pData)
  212. {
  213. ZeroMemory(pData, sizeof(*pData));
  214. pData->dwLayout = SFVMWVL_NORMAL | SFVMWVL_FILES;
  215. return S_OK;
  216. }
  217. HRESULT CCDBurnFolderViewCB::_CanBurn(IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState)
  218. {
  219. *puisState = UIS_DISABLED;
  220. BOOL fUDF;
  221. if (SUCCEEDED(_CDGetState(NULL, &fUDF, NULL, NULL)))
  222. {
  223. // UDF is the only thing we check for now, we allow burn wizard to kick off without media or files
  224. if (!fUDF)
  225. {
  226. *puisState = UIS_ENABLED;
  227. }
  228. }
  229. return S_OK;
  230. }
  231. HRESULT CCDBurnFolderViewCB::_CanClear(IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState)
  232. {
  233. *puisState = UIS_DISABLED;
  234. BOOL fInStaging, fUDF;
  235. if (SUCCEEDED(_CDGetState(NULL, &fUDF, &fInStaging, NULL)))
  236. {
  237. if (fInStaging && !fUDF)
  238. {
  239. *puisState = UIS_ENABLED;
  240. }
  241. }
  242. return S_OK;
  243. }
  244. HRESULT CCDBurnFolderViewCB::_CanErase(IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState)
  245. {
  246. *puisState = UIS_DISABLED;
  247. DWORD dwCaps;
  248. BOOL fOnMedia, fUDF;
  249. if (SUCCEEDED(_CDGetState(&dwCaps, &fUDF, NULL, &fOnMedia)))
  250. {
  251. if ((dwCaps & HWDMC_CDREWRITABLE) && (fOnMedia || fUDF))
  252. {
  253. *puisState = UIS_ENABLED;
  254. }
  255. }
  256. return S_OK;
  257. }
  258. HRESULT _InvokeVerbOnCDBurn(HWND hwnd, LPCSTR pszVerb)
  259. {
  260. IContextMenu *pcm;
  261. HRESULT hr = CoCreateInstance(CLSID_CDBurn, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IContextMenu, &pcm));
  262. if (SUCCEEDED(hr))
  263. {
  264. hr = SHInvokeCommandOnContextMenu(hwnd, NULL, pcm, 0, pszVerb);
  265. pcm->Release();
  266. }
  267. return hr;
  268. }
  269. HRESULT CCDBurnFolderViewCB::_OnCDBurn(IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc)
  270. {
  271. CCDBurnFolderViewCB* pThis = (CCDBurnFolderViewCB*)(void*)pv;
  272. return _InvokeVerbOnCDBurn(pThis->_hwndMain, "burn");
  273. }
  274. HRESULT CCDBurnFolderViewCB::_OnCDClearStaging(IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc)
  275. {
  276. CCDBurnFolderViewCB* pThis = (CCDBurnFolderViewCB*)(void*)pv;
  277. return _InvokeVerbOnCDBurn(pThis->_hwndMain, "cleanup");
  278. }
  279. HRESULT CCDBurnFolderViewCB::_OnCDErase(IUnknown* pv,IShellItemArray *psiItemArray, IBindCtx *pbc)
  280. {
  281. CCDBurnFolderViewCB* pThis = (CCDBurnFolderViewCB*)(void*)pv;
  282. return _InvokeVerbOnCDBurn(pThis->_hwndMain, "erase");
  283. }
  284. const WVTASKITEM c_CDBurnTaskHeader = WVTI_HEADER(L"shell32.dll", IDS_HEADER_CDBURN, IDS_HEADER_CDBURN_TT);
  285. const WVTASKITEM c_CDBurnTaskList[] =
  286. {
  287. WVTI_ENTRY_ALL(CLSID_NULL, L"shell32.dll", IDS_TASK_BURNCD, IDS_TASK_BURNCD_TT, IDI_TASK_BURNCD, CCDBurnFolderViewCB::_CanBurn, CCDBurnFolderViewCB::_OnCDBurn),
  288. WVTI_ENTRY_ALL(CLSID_NULL, L"shell32.dll", IDS_TASK_CLEARBURNAREA, IDS_TASK_CLEARBURNAREA_TT, IDI_TASK_CLEARBURNAREA, CCDBurnFolderViewCB::_CanClear, CCDBurnFolderViewCB::_OnCDClearStaging),
  289. WVTI_ENTRY_ALL(CLSID_NULL, L"shell32.dll", IDS_TASK_ERASECDFILES, IDS_TASK_ERASECDFILES_TT, IDI_TASK_ERASECDFILES, CCDBurnFolderViewCB::_CanErase, CCDBurnFolderViewCB::_OnCDErase),
  290. };
  291. HRESULT CCDBurnFolderViewCB::OnGetWebViewContent(DWORD pv, SFVM_WEBVIEW_CONTENT_DATA* pData)
  292. {
  293. ZeroMemory(pData, sizeof(*pData));
  294. Create_IUIElement(&c_CDBurnTaskHeader, &(pData->pSpecialTaskHeader));
  295. return S_OK;
  296. }
  297. HRESULT CCDBurnFolderViewCB::OnGetWebViewTasks(DWORD pv, SFVM_WEBVIEW_TASKSECTION_DATA* pTasks)
  298. {
  299. ZeroMemory(pTasks, sizeof(*pTasks));
  300. pTasks->dwUpdateFlags = SFVMWVTSDF_CONTENTSCHANGE;
  301. Create_IEnumUICommand((IUnknown*)(void*)this, c_CDBurnTaskList, ARRAYSIZE(c_CDBurnTaskList), &pTasks->penumSpecialTasks);
  302. return S_OK;
  303. }
  304. HRESULT CCDBurnFolderViewCB::OnGetWorkingDir(DWORD pv, UINT cch, PWSTR pszDir)
  305. {
  306. HRESULT hr = E_FAIL;
  307. DWORD dwNSId;
  308. GUID guid;
  309. IShellFolder *psf;
  310. BOOL fDone = FALSE;
  311. for (DWORD dwIndex = 0;
  312. !fDone && SUCCEEDED(_pmf->EnumNameSpace(dwIndex, &dwNSId)) && SUCCEEDED(_pmf->QueryNameSpace(dwNSId, &guid, &psf));
  313. dwIndex++)
  314. {
  315. if (IsEqualGUID(guid, CLSID_CDBurn))
  316. {
  317. LPITEMIDLIST pidl;
  318. hr = SHGetIDListFromUnk(psf, &pidl);
  319. if (SUCCEEDED(hr))
  320. {
  321. WCHAR sz[MAX_PATH];
  322. hr = SHGetPathFromIDList(pidl, sz) ? S_OK : E_FAIL;
  323. if (SUCCEEDED(hr))
  324. {
  325. lstrcpyn(pszDir, sz, cch);
  326. }
  327. ILFree(pidl);
  328. }
  329. fDone = TRUE;
  330. }
  331. psf->Release();
  332. }
  333. return hr;
  334. }