[BROWSEUI]
[reactos.git] / dll / win32 / shell32 / folders / admintools.cpp
1 /*
2 * Virtual Admin Tools Folder
3 *
4 * Copyright 2008 Johannes Anderwald
5 * Copyright 2009 Andrew Hill
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 #include <precomp.h>
23
24 WINE_DEFAULT_DEBUG_CHANNEL (shell);
25
26 /*
27 This folder should not exist. It is just a file system folder...
28 */
29
30 /* List shortcuts of
31 * CSIDL_COMMON_ADMINTOOLS
32 * Note: CSIDL_ADMINTOOLS is ignored, tested with Window XP SP3+
33 */
34
35 /***********************************************************************
36 * AdminTools folder implementation
37 */
38
39 class CDesktopFolderEnumY :
40 public IEnumIDListImpl
41 {
42 private:
43 public:
44 CDesktopFolderEnumY();
45 ~CDesktopFolderEnumY();
46 HRESULT WINAPI Initialize(LPWSTR szTarget, DWORD dwFlags);
47
48 BEGIN_COM_MAP(CDesktopFolderEnumY)
49 COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList)
50 END_COM_MAP()
51 };
52
53 static const shvheader AdminToolsSFHeader[] = {
54 {IDS_SHV_COLUMN8, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15},
55 {IDS_SHV_COLUMN2, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
56 {IDS_SHV_COLUMN3, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
57 {IDS_SHV_COLUMN4, SHCOLSTATE_TYPE_DATE | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 12}
58 };
59
60 #define COLUMN_NAME 0
61 #define COLUMN_SIZE 1
62 #define COLUMN_TYPE 2
63 #define COLUMN_DATE 3
64
65 #define AdminToolsHELLVIEWCOLUMNS (4)
66
67 CDesktopFolderEnumY::CDesktopFolderEnumY()
68 {
69 }
70
71 CDesktopFolderEnumY::~CDesktopFolderEnumY()
72 {
73 }
74
75 HRESULT WINAPI CDesktopFolderEnumY::Initialize(LPWSTR szTarget, DWORD dwFlags)
76 {
77 TRACE("(%p)->(flags=0x%08x)\n", this, dwFlags);
78 /* enumerate the elements in %windir%\desktop */
79 return CreateFolderEnumList(szTarget, dwFlags);
80 }
81
82 CAdminToolsFolder::CAdminToolsFolder()
83 {
84 pclsid = NULL;
85
86 pidlRoot = NULL; /* absolute pidl */
87 szTarget = NULL;
88
89 dwAttributes = 0; /* attributes returned by GetAttributesOf FIXME: use it */
90 }
91
92 CAdminToolsFolder::~CAdminToolsFolder()
93 {
94 TRACE ("-- destroying IShellFolder(%p)\n", this);
95 if (pidlRoot)
96 SHFree(pidlRoot);
97 HeapFree(GetProcessHeap(), 0, szTarget);
98 }
99
100 HRESULT WINAPI CAdminToolsFolder::FinalConstruct()
101 {
102 szTarget = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR));
103 if (szTarget == NULL)
104 return E_OUTOFMEMORY;
105 if (!SHGetSpecialFolderPathW(NULL, szTarget, CSIDL_COMMON_ADMINTOOLS, FALSE))
106 return E_FAIL;
107
108 pidlRoot = _ILCreateAdminTools(); /* my qualified pidl */
109 if (pidlRoot == NULL)
110 return E_OUTOFMEMORY;
111 return S_OK;
112 }
113
114 /**************************************************************************
115 * CAdminToolsFolder::ParseDisplayName
116 *
117 */
118 HRESULT WINAPI CAdminToolsFolder::ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName,
119 DWORD * pchEaten, LPITEMIDLIST * ppidl, DWORD * pdwAttributes)
120 {
121 TRACE("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n",
122 this, hwndOwner, pbc, lpszDisplayName, debugstr_w(lpszDisplayName),
123 pchEaten, ppidl, pdwAttributes);
124
125 *ppidl = 0;
126 if (pchEaten)
127 *pchEaten = 0;
128
129 MessageBoxW(NULL, lpszDisplayName, L"ParseDisplayName", MB_OK);
130
131 return E_NOTIMPL;
132 }
133
134 /**************************************************************************
135 * CAdminToolsFolder::EnumObjects
136 */
137 HRESULT WINAPI CAdminToolsFolder::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList)
138 {
139 CComObject<CDesktopFolderEnumY> *theEnumerator;
140 CComPtr<IEnumIDList> result;
141 HRESULT hResult;
142
143 TRACE ("(%p)->(HWND=%p flags=0x%08x pplist=%p)\n", this, hwndOwner, dwFlags, ppEnumIDList);
144
145 if (ppEnumIDList == NULL)
146 return E_POINTER;
147 *ppEnumIDList = NULL;
148 ATLTRY (theEnumerator = new CComObject<CDesktopFolderEnumY>);
149 if (theEnumerator == NULL)
150 return E_OUTOFMEMORY;
151 hResult = theEnumerator->QueryInterface(IID_PPV_ARG(IEnumIDList, &result));
152 if (FAILED (hResult))
153 {
154 delete theEnumerator;
155 return hResult;
156 }
157 hResult = theEnumerator->Initialize (szTarget, dwFlags);
158 if (FAILED (hResult))
159 return hResult;
160 *ppEnumIDList = result.Detach ();
161
162 TRACE ("-- (%p)->(new ID List: %p)\n", this, *ppEnumIDList);
163
164 return S_OK;
165 }
166
167 /**************************************************************************
168 * CAdminToolsFolder::BindToObject
169 */
170 HRESULT WINAPI CAdminToolsFolder::BindToObject(LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
171 {
172 TRACE ("(%p)->(pidl=%p,%p,%s,%p)\n", this,
173 pidl, pbcReserved, shdebugstr_guid (&riid), ppvOut);
174
175 return SHELL32_BindToChild(pidlRoot, NULL, pidl, riid, ppvOut);
176 }
177
178 /**************************************************************************
179 * CAdminToolsFolder::BindToStorage
180 */
181 HRESULT WINAPI CAdminToolsFolder::BindToStorage(LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
182 {
183 FIXME ("(%p)->(pidl=%p,%p,%s,%p) stub\n",
184 this, pidl, pbcReserved, shdebugstr_guid (&riid), ppvOut);
185
186 *ppvOut = NULL;
187 return E_NOTIMPL;
188 }
189
190 /**************************************************************************
191 * CAdminToolsFolder::CompareIDs
192 */
193 HRESULT WINAPI CAdminToolsFolder::CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
194 {
195 int nReturn;
196
197 TRACE ("(%p)->(0x%08lx,pidl1=%p,pidl2=%p)\n", this, lParam, pidl1, pidl2);
198 nReturn = SHELL32_CompareIDs (this, lParam, pidl1, pidl2);
199 TRACE ("-- %i\n", nReturn);
200 return nReturn;
201 }
202
203 /**************************************************************************
204 * CAdminToolsFolder::CreateViewObject
205 */
206 HRESULT WINAPI CAdminToolsFolder::CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID *ppvOut)
207 {
208 CComPtr<IShellView> pShellView;
209 HRESULT hr = E_INVALIDARG;
210
211 TRACE ("(%p)->(hwnd=%p,%s,%p)\n", this,
212 hwndOwner, shdebugstr_guid (&riid), ppvOut);
213
214 if (!ppvOut)
215 return hr;
216
217 *ppvOut = NULL;
218
219 if (IsEqualIID (riid, IID_IDropTarget))
220 {
221 WARN ("IDropTarget not implemented\n");
222 hr = E_NOTIMPL;
223 }
224 else if (IsEqualIID (riid, IID_IShellView))
225 {
226 hr = IShellView_Constructor ((IShellFolder *)this, &pShellView);
227 if (pShellView)
228 hr = pShellView->QueryInterface(riid, ppvOut);
229 }
230 TRACE ("-- (%p)->(interface=%p)\n", this, ppvOut);
231 return hr;
232 }
233
234 /**************************************************************************
235 * ISF_AdminTools_fnGetAttributesOf
236 */
237 HRESULT WINAPI CAdminToolsFolder::GetAttributesOf(UINT cidl, LPCITEMIDLIST *apidl, DWORD *rgfInOut)
238 {
239 HRESULT hr = S_OK;
240 static const DWORD dwAdminToolsAttributes =
241 SFGAO_STORAGE | SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR |
242 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_FILESYSTEM;
243
244 TRACE ("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n",
245 this, cidl, apidl, rgfInOut, rgfInOut ? *rgfInOut : 0);
246
247 if (!rgfInOut)
248 return E_INVALIDARG;
249 if (cidl && !apidl)
250 return E_INVALIDARG;
251
252 if (*rgfInOut == 0)
253 *rgfInOut = ~0;
254
255 if(cidl == 0) {
256 *rgfInOut &= dwAdminToolsAttributes;
257 } else {
258 while (cidl > 0 && *apidl) {
259 pdump (*apidl);
260 if (_ILIsAdminTools(*apidl)) {
261 *rgfInOut &= dwAdminToolsAttributes;
262 } else {
263 SHELL32_GetItemAttributes (this, *apidl, rgfInOut);
264 }
265 apidl++;
266 cidl--;
267 }
268 }
269 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
270 *rgfInOut &= ~SFGAO_VALIDATE;
271
272 TRACE ("-- result=0x%08x\n", *rgfInOut);
273
274 return hr;
275 }
276
277 /**************************************************************************
278 * CAdminToolsFolder::GetUIObjectOf
279 *
280 * PARAMETERS
281 * HWND hwndOwner, //[in ] Parent window for any output
282 * UINT cidl, //[in ] array size
283 * LPCITEMIDLIST* apidl, //[in ] simple pidl array
284 * REFIID riid, //[in ] Requested Interface
285 * UINT* prgfInOut, //[ ] reserved
286 * LPVOID* ppvObject) //[out] Resulting Interface
287 *
288 */
289 HRESULT WINAPI CAdminToolsFolder::GetUIObjectOf(HWND hwndOwner, UINT cidl, LPCITEMIDLIST *apidl,
290 REFIID riid, UINT * prgfInOut, LPVOID * ppvOut)
291 {
292 LPITEMIDLIST pidl;
293 CComPtr<IUnknown> pObj;
294 HRESULT hr = E_INVALIDARG;
295
296 TRACE ("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n",
297 this, hwndOwner, cidl, apidl, shdebugstr_guid (&riid), prgfInOut, ppvOut);
298
299 if (!ppvOut)
300 return hr;
301
302 *ppvOut = NULL;
303
304 if (IsEqualIID (riid, IID_IContextMenu))
305 {
306 IContextMenu * pCm = NULL;
307 hr = CDefFolderMenu_Create2(pidlRoot, hwndOwner, cidl, apidl, static_cast<IShellFolder*>(this), NULL, 0, NULL, &pCm);
308 pObj = pCm;
309 }
310 else if (IsEqualIID (riid, IID_IDataObject) && (cidl >= 1))
311 {
312 IDataObject * pDo = NULL;
313 hr = IDataObject_Constructor(hwndOwner, pidlRoot, apidl, cidl, &pDo);
314 pObj = pDo;
315 }
316 else if (IsEqualIID (riid, IID_IExtractIconA) && (cidl == 1))
317 {
318 pidl = ILCombine (pidlRoot, apidl[0]);
319 pObj = (LPUNKNOWN) IExtractIconA_Constructor (pidl);
320 SHFree (pidl);
321 hr = S_OK;
322 }
323 else if (IsEqualIID (riid, IID_IExtractIconW) && (cidl == 1))
324 {
325 pidl = ILCombine (pidlRoot, apidl[0]);
326 pObj = (LPUNKNOWN) IExtractIconW_Constructor (pidl);
327 SHFree (pidl);
328 hr = S_OK;
329 }
330 else if (IsEqualIID (riid, IID_IDropTarget) && (cidl >= 1))
331 {
332 IDropTarget * pDt = NULL;
333 hr = this->QueryInterface(IID_PPV_ARG(IDropTarget, &pDt));
334 pObj = pDt;
335 }
336 else if ((IsEqualIID(riid, IID_IShellLinkW) ||
337 IsEqualIID(riid, IID_IShellLinkA)) && (cidl == 1))
338 {
339 pidl = ILCombine (pidlRoot, apidl[0]);
340 hr = IShellLink_ConstructFromFile(NULL, riid, pidl, reinterpret_cast<LPVOID*>(&pObj));
341 SHFree (pidl);
342 }
343 else
344 hr = E_NOINTERFACE;
345
346 if (SUCCEEDED(hr) && !pObj)
347 hr = E_OUTOFMEMORY;
348
349 *ppvOut = pObj.Detach();
350 TRACE ("(%p)->hr=0x%08x\n", this, hr);
351 return hr;
352 }
353
354 /**************************************************************************
355 * CAdminToolsFolder::GetDisplayNameOf
356 *
357 */
358 HRESULT WINAPI CAdminToolsFolder::GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD dwFlags, LPSTRRET strRet)
359 {
360 HRESULT hr = S_OK;
361 LPWSTR pszPath, pOffset;
362
363 TRACE ("(%p)->(pidl=%p,0x%08x,%p)\n", this, pidl, dwFlags, strRet);
364 pdump (pidl);
365
366 if (!strRet)
367 return E_INVALIDARG;
368
369 pszPath = (LPWSTR)CoTaskMemAlloc((MAX_PATH + 1) * sizeof(WCHAR));
370 if (!pszPath)
371 return E_OUTOFMEMORY;
372
373 ZeroMemory(pszPath, (MAX_PATH + 1) * sizeof(WCHAR));
374
375 if (!pidl->mkid.cb)
376 {
377 if ((GET_SHGDN_RELATION (dwFlags) == SHGDN_NORMAL) &&
378 (GET_SHGDN_FOR (dwFlags) & SHGDN_FORPARSING))
379 wcscpy(pszPath, szTarget);
380 else if (!HCR_GetClassNameW(CLSID_AdminFolderShortcut, pszPath, MAX_PATH))
381 hr = E_FAIL;
382 }
383 else if (_ILIsPidlSimple(pidl))
384 {
385 if ((GET_SHGDN_FOR(dwFlags) & SHGDN_FORPARSING) &&
386 (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER) &&
387 szTarget)
388 {
389 wcscpy(pszPath, szTarget);
390 pOffset = PathAddBackslashW(pszPath);
391 if (pOffset)
392 {
393 if (!_ILSimpleGetTextW(pidl, pOffset, MAX_PATH + 1 - (pOffset - pszPath)))
394 hr = E_FAIL;
395 }
396 else
397 hr = E_FAIL;
398 }
399 else
400 {
401 if (_ILSimpleGetTextW(pidl, pszPath, MAX_PATH + 1))
402 {
403 if (SHELL_FS_HideExtension(pszPath))
404 PathRemoveExtensionW(pszPath);
405 }
406 else
407 hr = E_FAIL;
408 }
409 }
410 else if (_ILIsSpecialFolder(pidl))
411 {
412 BOOL bSimplePidl = _ILIsPidlSimple(pidl);
413
414 if (bSimplePidl)
415 {
416 if (!_ILSimpleGetTextW(pidl, pszPath, MAX_PATH))
417 hr = E_FAIL;
418 }
419 else if ((dwFlags & SHGDN_FORPARSING) && !bSimplePidl)
420 {
421 int len = 0;
422
423 wcscpy(pszPath, szTarget);
424 PathAddBackslashW(pszPath);
425 len = wcslen(pszPath);
426
427 if (!SUCCEEDED(SHELL32_GetDisplayNameOfChild(this, pidl, dwFlags | SHGDN_INFOLDER, pszPath + len, MAX_PATH + 1 - len)))
428 {
429 CoTaskMemFree(pszPath);
430 return E_OUTOFMEMORY;
431 }
432
433 }
434 }
435
436 if (SUCCEEDED(hr))
437 {
438 strRet->uType = STRRET_WSTR;
439 strRet->pOleStr = pszPath;
440 TRACE ("-- (%p)->(%s,0x%08x)\n", this, debugstr_w(strRet->pOleStr), hr);
441 }
442 else
443 CoTaskMemFree(pszPath);
444
445 return hr;
446 }
447
448 /**************************************************************************
449 * CAdminToolsFolder::SetNameOf
450 * Changes the name of a file object or subfolder, possibly changing its item
451 * identifier in the process.
452 *
453 * PARAMETERS
454 * HWND hwndOwner, //[in ] Owner window for output
455 * LPCITEMIDLIST pidl, //[in ] simple pidl of item to change
456 * LPCOLESTR lpszName, //[in ] the items new display name
457 * DWORD dwFlags, //[in ] SHGNO formatting flags
458 * LPITEMIDLIST* ppidlOut) //[out] simple pidl returned
459 */
460 HRESULT WINAPI CAdminToolsFolder::SetNameOf(HWND hwndOwner, LPCITEMIDLIST pidl, /* simple pidl */
461 LPCOLESTR lpName, DWORD dwFlags, LPITEMIDLIST * pPidlOut)
462 {
463 FIXME ("(%p)->(%p,pidl=%p,%s,%lu,%p)\n", this, hwndOwner, pidl,
464 debugstr_w (lpName), dwFlags, pPidlOut);
465
466 return E_FAIL;
467 }
468
469 HRESULT WINAPI CAdminToolsFolder::GetDefaultSearchGUID(GUID *pguid)
470 {
471 FIXME ("(%p)\n", this);
472 return E_NOTIMPL;
473 }
474
475 HRESULT WINAPI CAdminToolsFolder::EnumSearches(IEnumExtraSearch ** ppenum)
476 {
477 FIXME ("(%p)\n", this);
478 return E_NOTIMPL;
479 }
480
481 HRESULT WINAPI CAdminToolsFolder::GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
482 {
483 if (pSort)
484 *pSort = 0;
485 if (pDisplay)
486 *pDisplay = 0;
487
488 return S_OK;
489 }
490 HRESULT WINAPI CAdminToolsFolder::GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags)
491 {
492 if (!pcsFlags || iColumn >= AdminToolsHELLVIEWCOLUMNS)
493 return E_INVALIDARG;
494 *pcsFlags = AdminToolsSFHeader[iColumn].pcsFlags;
495 return S_OK;
496
497 }
498
499 HRESULT WINAPI CAdminToolsFolder::GetDetailsEx (LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv)
500 {
501 FIXME ("(%p): stub\n", this);
502
503 return E_NOTIMPL;
504 }
505
506 HRESULT WINAPI CAdminToolsFolder::GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *psd)
507 {
508 WCHAR buffer[MAX_PATH] = {0};
509 HRESULT hr = E_FAIL;
510
511 TRACE("(%p)->(%p %i %p): stub\n", this, pidl, iColumn, psd);
512
513 if (iColumn >= AdminToolsHELLVIEWCOLUMNS)
514 return E_FAIL;
515
516 psd->fmt = AdminToolsSFHeader[iColumn].fmt;
517 psd->cxChar = AdminToolsSFHeader[iColumn].cxChar;
518 if (pidl == NULL)
519 {
520 psd->str.uType = STRRET_WSTR;
521 if (LoadStringW(shell32_hInstance, AdminToolsSFHeader[iColumn].colnameid, buffer, MAX_PATH))
522 hr = SHStrDupW(buffer, &psd->str.pOleStr);
523
524 return hr;
525 }
526
527 psd->str.uType = STRRET_CSTR;
528 switch (iColumn)
529 {
530 case COLUMN_NAME:
531 psd->str.uType = STRRET_WSTR;
532 hr = GetDisplayNameOf(pidl,
533 SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str);
534 break;
535 case COLUMN_SIZE:
536 _ILGetFileSize (pidl, psd->str.cStr, MAX_PATH);
537 break;
538 case COLUMN_TYPE:
539 _ILGetFileType (pidl, psd->str.cStr, MAX_PATH);
540 break;
541 case COLUMN_DATE:
542 _ILGetFileDate (pidl, psd->str.cStr, MAX_PATH);
543 break;
544 }
545
546 return hr;
547 }
548
549 HRESULT WINAPI CAdminToolsFolder::MapColumnToSCID(UINT column, SHCOLUMNID *pscid)
550 {
551 FIXME ("(%p): stub\n", this);
552 return E_NOTIMPL;
553 }
554
555 /************************************************************************
556 * CAdminToolsFolder::GetClassID
557 */
558 HRESULT WINAPI CAdminToolsFolder::GetClassID(CLSID *lpClassId)
559 {
560 TRACE ("(%p)\n", this);
561
562 memcpy(lpClassId, &CLSID_AdminFolderShortcut, sizeof(CLSID));
563
564 return S_OK;
565 }
566
567 /************************************************************************
568 * CAdminToolsFolder::Initialize
569 *
570 */
571 HRESULT WINAPI CAdminToolsFolder::Initialize(LPCITEMIDLIST pidl)
572 {
573 if (pidlRoot)
574 SHFree((LPVOID)pidlRoot);
575
576 pidlRoot = ILClone(pidl);
577 return S_OK;
578 }
579
580 /**************************************************************************
581 * CAdminToolsFolder::GetCurFolder
582 */
583 HRESULT WINAPI CAdminToolsFolder::GetCurFolder(LPITEMIDLIST *pidl)
584 {
585 TRACE ("(%p)->(%p)\n", this, pidl);
586
587 *pidl = ILClone (pidlRoot);
588 return S_OK;
589 }