[shell32]
[reactos.git] / reactos / dll / win32 / shell32 / shfldr_mycomp.c
1 /*
2 * Virtual Workplace folder
3 *
4 * Copyright 1997 Marcus Meissner
5 * Copyright 1998, 1999, 2002 Juergen Schmied
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 St, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22 #include <precomp.h>
23
24 WINE_DEFAULT_DEBUG_CHANNEL (shell);
25
26 /***********************************************************************
27 * IShellFolder implementation
28 */
29
30 typedef struct {
31 const IShellFolder2Vtbl *lpVtbl;
32 LONG ref;
33 const IPersistFolder2Vtbl *lpVtblPersistFolder2;
34
35 /* both paths are parsible from the desktop */
36 LPITEMIDLIST pidlRoot; /* absolute pidl */
37 LPWSTR sName;
38 } IGenericSFImpl, *LPIGenericSFImpl;
39
40 static const IShellFolder2Vtbl vt_ShellFolder2;
41 static const IPersistFolder2Vtbl vt_PersistFolder2;
42
43 static LPIGenericSFImpl __inline impl_from_IPersistFolder2( IPersistFolder2 *iface )
44 {
45 return (LPIGenericSFImpl)((char*)iface - FIELD_OFFSET(IGenericSFImpl, lpVtblPersistFolder2));
46 }
47
48
49 /*
50 converts This to an interface pointer
51 */
52 #define _IUnknown_(This) (IUnknown*)&(This->lpVtbl)
53 #define _IShellFolder_(This) (IShellFolder*)&(This->lpVtbl)
54 #define _IShellFolder2_(This) (IShellFolder2*)&(This->lpVtbl)
55
56 #define _IPersist_(This) (IPersist*)&(This->lpVtblPersistFolder2)
57 #define _IPersistFolder_(This) (IPersistFolder*)&(This->lpVtblPersistFolder2)
58 #define _IPersistFolder2_(This) (IPersistFolder2*)&(This->lpVtblPersistFolder2)
59
60 /***********************************************************************
61 * IShellFolder [MyComputer] implementation
62 */
63
64 static const shvheader MyComputerSFHeader[] = {
65 {IDS_SHV_COLUMN1, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15},
66 {IDS_SHV_COLUMN3, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
67 {IDS_SHV_COLUMN6, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
68 {IDS_SHV_COLUMN7, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
69 };
70
71 #define MYCOMPUTERSHELLVIEWCOLUMNS 4
72
73 /**************************************************************************
74 * ISF_MyComputer_Constructor
75 */
76 HRESULT WINAPI ISF_MyComputer_Constructor (IUnknown * pUnkOuter, REFIID riid, LPVOID * ppv)
77 {
78 IGenericSFImpl *sf;
79 DWORD dwSize;
80 WCHAR szName[MAX_PATH];
81 TRACE ("unkOut=%p %s\n", pUnkOuter, shdebugstr_guid (riid));
82
83 if (!ppv)
84 return E_POINTER;
85 if (pUnkOuter)
86 return CLASS_E_NOAGGREGATION;
87
88 sf = LocalAlloc (LMEM_ZEROINIT, sizeof (IGenericSFImpl));
89 if (!sf)
90 return E_OUTOFMEMORY;
91
92 sf->ref = 0;
93 sf->lpVtbl = &vt_ShellFolder2;
94 sf->lpVtblPersistFolder2 = &vt_PersistFolder2;
95 sf->pidlRoot = _ILCreateMyComputer (); /* my qualified pidl */
96
97 if (FAILED (IUnknown_QueryInterface (_IUnknown_ (sf), riid, ppv)))
98 {
99 IUnknown_Release (_IUnknown_ (sf));
100 return E_NOINTERFACE;
101 }
102
103 dwSize = sizeof(szName);
104 if (RegGetValueW(HKEY_CURRENT_USER,
105 L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CLSID\\{20D04FE0-3AEA-1069-A2D8-08002B30309D}",
106 NULL,
107 RRF_RT_REG_SZ,
108 NULL,
109 szName,
110 &dwSize) == ERROR_SUCCESS)
111 {
112 szName[MAX_PATH-1] = 0;
113 sf->sName = SHAlloc((wcslen(szName)+1) * sizeof(WCHAR));
114 if (sf->sName)
115 {
116 wcscpy( sf->sName, szName );
117 }
118 TRACE("sName %s\n", debugstr_w(sf->sName));
119 }
120
121 TRACE ("--(%p)\n", sf);
122 return S_OK;
123 }
124
125 /**************************************************************************
126 * ISF_MyComputer_fnQueryInterface
127 *
128 * NOTES supports not IPersist/IPersistFolder
129 */
130 static HRESULT WINAPI ISF_MyComputer_fnQueryInterface (IShellFolder2 *iface,
131 REFIID riid, LPVOID *ppvObj)
132 {
133 IGenericSFImpl *This = (IGenericSFImpl *)iface;
134
135 TRACE ("(%p)->(%s,%p)\n", This, shdebugstr_guid (riid), ppvObj);
136
137 *ppvObj = NULL;
138
139 if (IsEqualIID (riid, &IID_IUnknown) ||
140 IsEqualIID (riid, &IID_IShellFolder) ||
141 IsEqualIID (riid, &IID_IShellFolder2))
142 {
143 *ppvObj = This;
144 }
145 else if (IsEqualIID (riid, &IID_IPersist) ||
146 IsEqualIID (riid, &IID_IPersistFolder) ||
147 IsEqualIID (riid, &IID_IPersistFolder2))
148 {
149 *ppvObj = _IPersistFolder2_ (This);
150 }
151
152 if (*ppvObj)
153 {
154 IUnknown_AddRef ((IUnknown *) (*ppvObj));
155 TRACE ("-- Interface: (%p)->(%p)\n", ppvObj, *ppvObj);
156 return S_OK;
157 }
158 TRACE ("-- Interface: E_NOINTERFACE\n");
159 return E_NOINTERFACE;
160 }
161
162 static ULONG WINAPI ISF_MyComputer_fnAddRef (IShellFolder2 * iface)
163 {
164 IGenericSFImpl *This = (IGenericSFImpl *)iface;
165 ULONG refCount = InterlockedIncrement(&This->ref);
166
167 TRACE ("(%p)->(count=%u)\n", This, refCount - 1);
168
169 return refCount;
170 }
171
172 static ULONG WINAPI ISF_MyComputer_fnRelease (IShellFolder2 * iface)
173 {
174 IGenericSFImpl *This = (IGenericSFImpl *)iface;
175 ULONG refCount = InterlockedDecrement(&This->ref);
176
177 TRACE ("(%p)->(count=%u)\n", This, refCount + 1);
178
179 if (!refCount)
180 {
181 TRACE ("-- destroying IShellFolder(%p)\n", This);
182 SHFree (This->pidlRoot);
183 LocalFree (This);
184 }
185 return refCount;
186 }
187
188 /**************************************************************************
189 * ISF_MyComputer_fnParseDisplayName
190 */
191 static HRESULT WINAPI ISF_MyComputer_fnParseDisplayName (IShellFolder2 *iface,
192 HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName,
193 DWORD * pchEaten, LPITEMIDLIST * ppidl, DWORD * pdwAttributes)
194 {
195 IGenericSFImpl *This = (IGenericSFImpl *)iface;
196 HRESULT hr = E_INVALIDARG;
197 LPCWSTR szNext = NULL;
198 WCHAR szElement[MAX_PATH];
199 LPITEMIDLIST pidlTemp = NULL;
200 CLSID clsid;
201
202 TRACE("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n", This,
203 hwndOwner, pbc, lpszDisplayName, debugstr_w (lpszDisplayName),
204 pchEaten, ppidl, pdwAttributes);
205
206 *ppidl = 0;
207 if (pchEaten)
208 *pchEaten = 0; /* strange but like the original */
209
210 /* handle CLSID paths */
211 if (lpszDisplayName[0] == ':' && lpszDisplayName[1] == ':')
212 {
213 szNext = GetNextElementW (lpszDisplayName, szElement, MAX_PATH);
214 TRACE ("-- element: %s\n", debugstr_w (szElement));
215 CLSIDFromString (szElement + 2, &clsid);
216 pidlTemp = _ILCreateGuid (PT_GUID, &clsid);
217 }
218 /* do we have an absolute path name ? */
219 else if (PathGetDriveNumberW (lpszDisplayName) >= 0 &&
220 lpszDisplayName[2] == (WCHAR) '\\')
221 {
222 szNext = GetNextElementW (lpszDisplayName, szElement, MAX_PATH);
223 /* make drive letter uppercase to enable PIDL comparison */
224 szElement[0] = toupper(szElement[0]);
225 pidlTemp = _ILCreateDrive (szElement);
226 }
227
228 if (szNext && *szNext)
229 {
230 hr = SHELL32_ParseNextElement (iface, hwndOwner, pbc, &pidlTemp,
231 (LPOLESTR) szNext, pchEaten, pdwAttributes);
232 }
233 else
234 {
235 if (pdwAttributes && *pdwAttributes)
236 SHELL32_GetItemAttributes (_IShellFolder_ (This),
237 pidlTemp, pdwAttributes);
238 hr = S_OK;
239 }
240
241 *ppidl = pidlTemp;
242
243 TRACE ("(%p)->(-- ret=0x%08x)\n", This, hr);
244
245 return hr;
246 }
247
248 /**************************************************************************
249 * CreateMyCompEnumList()
250 */
251 static const WCHAR MyComputer_NameSpaceW[] = { 'S','O','F','T','W','A','R','E',
252 '\\','M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
253 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','E','x','p','l',
254 'o','r','e','r','\\','M','y','C','o','m','p','u','t','e','r','\\','N','a','m',
255 'e','s','p','a','c','e','\0' };
256
257 static BOOL CreateMyCompEnumList(IEnumIDList *list, DWORD dwFlags)
258 {
259 BOOL ret = TRUE;
260
261 TRACE("(%p)->(flags=0x%08x)\n", list, dwFlags);
262
263 /* enumerate the folders */
264 if (dwFlags & SHCONTF_FOLDERS)
265 {
266 WCHAR wszDriveName[] = {'A', ':', '\\', '\0'};
267 DWORD dwDrivemap = GetLogicalDrives();
268 HKEY hkey;
269 UINT i;
270
271 while (ret && wszDriveName[0]<='Z')
272 {
273 if(dwDrivemap & 0x00000001L)
274 ret = AddToEnumList(list, _ILCreateDrive(wszDriveName));
275 wszDriveName[0]++;
276 dwDrivemap = dwDrivemap >> 1;
277 }
278
279 TRACE("-- (%p)-> enumerate (mycomputer shell extensions)\n",list);
280 for (i=0; i<2; i++) {
281 if (ret && !RegOpenKeyExW(i == 0 ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER,
282 MyComputer_NameSpaceW, 0, KEY_READ, &hkey))
283 {
284 WCHAR iid[50];
285 int i=0;
286
287 while (ret)
288 {
289 DWORD size;
290 LONG r;
291
292 size = sizeof(iid) / sizeof(iid[0]);
293 r = RegEnumKeyExW(hkey, i, iid, &size, 0, NULL, NULL, NULL);
294 if (ERROR_SUCCESS == r)
295 {
296 /* FIXME: shell extensions, shouldn't the type be
297 * PT_SHELLEXT? */
298 ret = AddToEnumList(list, _ILCreateGuidFromStrW(iid));
299 i++;
300 }
301 else if (ERROR_NO_MORE_ITEMS == r)
302 break;
303 else
304 ret = FALSE;
305 }
306 RegCloseKey(hkey);
307 }
308 }
309 }
310 return ret;
311 }
312
313 /**************************************************************************
314 * ISF_MyComputer_fnEnumObjects
315 */
316 static HRESULT WINAPI ISF_MyComputer_fnEnumObjects (IShellFolder2 *iface,
317 HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList)
318 {
319 IGenericSFImpl *This = (IGenericSFImpl *)iface;
320
321 TRACE("(%p)->(HWND=%p flags=0x%08x pplist=%p)\n", This,
322 hwndOwner, dwFlags, ppEnumIDList);
323
324 *ppEnumIDList = IEnumIDList_Constructor();
325 if (*ppEnumIDList)
326 CreateMyCompEnumList(*ppEnumIDList, dwFlags);
327
328 TRACE ("-- (%p)->(new ID List: %p)\n", This, *ppEnumIDList);
329
330 return (*ppEnumIDList) ? S_OK : E_OUTOFMEMORY;
331 }
332
333 /**************************************************************************
334 * ISF_MyComputer_fnBindToObject
335 */
336 static HRESULT WINAPI ISF_MyComputer_fnBindToObject (IShellFolder2 *iface,
337 LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
338 {
339 IGenericSFImpl *This = (IGenericSFImpl *)iface;
340
341 TRACE("(%p)->(pidl=%p,%p,%s,%p)\n", This,
342 pidl, pbcReserved, shdebugstr_guid (riid), ppvOut);
343
344 return SHELL32_BindToChild (This->pidlRoot, NULL, pidl, riid, ppvOut);
345 }
346
347 /**************************************************************************
348 * ISF_MyComputer_fnBindToStorage
349 */
350 static HRESULT WINAPI ISF_MyComputer_fnBindToStorage (IShellFolder2 * iface,
351 LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
352 {
353 IGenericSFImpl *This = (IGenericSFImpl *)iface;
354
355 FIXME("(%p)->(pidl=%p,%p,%s,%p) stub\n", This,
356 pidl, pbcReserved, shdebugstr_guid (riid), ppvOut);
357
358 *ppvOut = NULL;
359 return E_NOTIMPL;
360 }
361
362 /**************************************************************************
363 * ISF_MyComputer_fnCompareIDs
364 */
365
366 static HRESULT WINAPI ISF_MyComputer_fnCompareIDs (IShellFolder2 *iface,
367 LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
368 {
369 IGenericSFImpl *This = (IGenericSFImpl *)iface;
370 int nReturn;
371
372 TRACE ("(%p)->(0x%08lx,pidl1=%p,pidl2=%p)\n", This, lParam, pidl1, pidl2);
373 nReturn = SHELL32_CompareIDs (_IShellFolder_ (This), lParam, pidl1, pidl2);
374 TRACE ("-- %i\n", nReturn);
375 return nReturn;
376 }
377
378 /**************************************************************************
379 * ISF_MyComputer_fnCreateViewObject
380 */
381 static HRESULT WINAPI ISF_MyComputer_fnCreateViewObject (IShellFolder2 *iface,
382 HWND hwndOwner, REFIID riid, LPVOID * ppvOut)
383 {
384 IGenericSFImpl *This = (IGenericSFImpl *)iface;
385 LPSHELLVIEW pShellView;
386 HRESULT hr = E_INVALIDARG;
387
388 TRACE("(%p)->(hwnd=%p,%s,%p)\n", This,
389 hwndOwner, shdebugstr_guid (riid), ppvOut);
390
391 if (!ppvOut)
392 return hr;
393
394 *ppvOut = NULL;
395
396 if (IsEqualIID (riid, &IID_IDropTarget))
397 {
398 WARN ("IDropTarget not implemented\n");
399 hr = E_NOTIMPL;
400 }
401 else if (IsEqualIID (riid, &IID_IContextMenu))
402 {
403 WARN ("IContextMenu not implemented\n");
404 hr = E_NOTIMPL;
405 }
406 else if (IsEqualIID (riid, &IID_IShellView))
407 {
408 pShellView = IShellView_Constructor ((IShellFolder *) iface);
409 if (pShellView)
410 {
411 hr = IShellView_QueryInterface (pShellView, riid, ppvOut);
412 IShellView_Release (pShellView);
413 }
414 }
415 TRACE ("-- (%p)->(interface=%p)\n", This, ppvOut);
416 return hr;
417 }
418
419 /**************************************************************************
420 * ISF_MyComputer_fnGetAttributesOf
421 */
422 static HRESULT WINAPI ISF_MyComputer_fnGetAttributesOf (IShellFolder2 * iface,
423 UINT cidl, LPCITEMIDLIST * apidl, DWORD * rgfInOut)
424 {
425 IGenericSFImpl *This = (IGenericSFImpl *)iface;
426 HRESULT hr = S_OK;
427 static const DWORD dwComputerAttributes =
428 SFGAO_STORAGE | SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR | SFGAO_CANCOPY |
429 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER | SFGAO_CANRENAME | SFGAO_CANDELETE;
430
431 TRACE ("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n",
432 This, cidl, apidl, rgfInOut, rgfInOut ? *rgfInOut : 0);
433
434 if (!rgfInOut)
435 return E_INVALIDARG;
436 if (cidl && !apidl)
437 return E_INVALIDARG;
438
439 if (*rgfInOut == 0)
440 *rgfInOut = ~0;
441
442 if(cidl == 0) {
443 *rgfInOut &= dwComputerAttributes;
444 } else {
445 while (cidl > 0 && *apidl) {
446 pdump (*apidl);
447 SHELL32_GetItemAttributes (_IShellFolder_ (This), *apidl, rgfInOut);
448 apidl++;
449 cidl--;
450 }
451 }
452 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
453 *rgfInOut &= ~SFGAO_VALIDATE;
454
455 TRACE ("-- result=0x%08x\n", *rgfInOut);
456 return hr;
457 }
458
459 /**************************************************************************
460 * ISF_MyComputer_fnGetUIObjectOf
461 *
462 * PARAMETERS
463 * hwndOwner [in] Parent window for any output
464 * cidl [in] array size
465 * apidl [in] simple pidl array
466 * riid [in] Requested Interface
467 * prgfInOut [ ] reserved
468 * ppvObject [out] Resulting Interface
469 *
470 */
471 static HRESULT WINAPI ISF_MyComputer_fnGetUIObjectOf (IShellFolder2 * iface,
472 HWND hwndOwner, UINT cidl, LPCITEMIDLIST * apidl, REFIID riid,
473 UINT * prgfInOut, LPVOID * ppvOut)
474 {
475 IGenericSFImpl *This = (IGenericSFImpl *)iface;
476
477 LPITEMIDLIST pidl;
478 IUnknown *pObj = NULL;
479 HRESULT hr = E_INVALIDARG;
480
481 TRACE("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n", This,
482 hwndOwner, cidl, apidl, shdebugstr_guid (riid), prgfInOut, ppvOut);
483
484 if (!ppvOut)
485 return hr;
486
487 *ppvOut = NULL;
488
489 if (IsEqualIID (riid, &IID_IContextMenu) && (cidl >= 1))
490 {
491 hr = CDefFolderMenu_Create2(This->pidlRoot, hwndOwner, cidl, apidl, (IShellFolder*)iface, NULL, 0, NULL, (IContextMenu**)&pObj);
492 }
493 else if (IsEqualIID (riid, &IID_IDataObject) && (cidl >= 1))
494 {
495 pObj = (LPUNKNOWN) IDataObject_Constructor (hwndOwner,
496 This->pidlRoot, apidl, cidl);
497 hr = S_OK;
498 }
499 else if (IsEqualIID (riid, &IID_IExtractIconA) && (cidl == 1))
500 {
501 pidl = ILCombine (This->pidlRoot, apidl[0]);
502 pObj = (LPUNKNOWN) IExtractIconA_Constructor (pidl);
503 SHFree (pidl);
504 hr = S_OK;
505 }
506 else if (IsEqualIID (riid, &IID_IExtractIconW) && (cidl == 1))
507 {
508 pidl = ILCombine (This->pidlRoot, apidl[0]);
509 pObj = (LPUNKNOWN) IExtractIconW_Constructor (pidl);
510 SHFree (pidl);
511 hr = S_OK;
512 }
513 else if (IsEqualIID (riid, &IID_IDropTarget) && (cidl >= 1))
514 {
515 hr = IShellFolder_QueryInterface (iface, &IID_IDropTarget,
516 (LPVOID *) &pObj);
517 }
518 else if ((IsEqualIID(riid,&IID_IShellLinkW) ||
519 IsEqualIID(riid,&IID_IShellLinkA)) && (cidl == 1))
520 {
521 pidl = ILCombine (This->pidlRoot, apidl[0]);
522 hr = IShellLink_ConstructFromFile(NULL, riid, pidl, (LPVOID*) &pObj);
523 SHFree (pidl);
524 }
525 else
526 hr = E_NOINTERFACE;
527
528 if (SUCCEEDED(hr) && !pObj)
529 hr = E_OUTOFMEMORY;
530
531 *ppvOut = pObj;
532 TRACE ("(%p)->hr=0x%08x\n", This, hr);
533 return hr;
534 }
535
536 /**************************************************************************
537 * ISF_MyComputer_fnGetDisplayNameOf
538 */
539 static HRESULT WINAPI ISF_MyComputer_fnGetDisplayNameOf (IShellFolder2 *iface,
540 LPCITEMIDLIST pidl, DWORD dwFlags, LPSTRRET strRet)
541 {
542 IGenericSFImpl *This = (IGenericSFImpl *)iface;
543
544 LPWSTR pszPath;
545 HRESULT hr = S_OK;
546
547 TRACE ("(%p)->(pidl=%p,0x%08x,%p)\n", This, pidl, dwFlags, strRet);
548 pdump (pidl);
549
550 if (!strRet)
551 return E_INVALIDARG;
552
553 pszPath = CoTaskMemAlloc((MAX_PATH +1) * sizeof(WCHAR));
554 if (!pszPath)
555 return E_OUTOFMEMORY;
556
557 pszPath[0] = 0;
558
559 if (!pidl->mkid.cb)
560 {
561 /* parsing name like ::{...} */
562 pszPath[0] = ':';
563 pszPath[1] = ':';
564 SHELL32_GUIDToStringW(&CLSID_MyComputer, &pszPath[2]);
565 }
566 else if (_ILIsPidlSimple(pidl))
567 {
568 /* take names of special folders only if its only this folder */
569 if (_ILIsSpecialFolder(pidl))
570 {
571 GUID const *clsid;
572
573 clsid = _ILGetGUIDPointer (pidl);
574 if (clsid)
575 {
576 if (GET_SHGDN_FOR (dwFlags) & SHGDN_FORPARSING)
577 {
578 static const WCHAR clsidW[] =
579 { 'C','L','S','I','D','\\',0 };
580 static const WCHAR shellfolderW[] =
581 { '\\','s','h','e','l','l','f','o','l','d','e','r',0 };
582 static const WCHAR wantsForParsingW[] =
583 { 'W','a','n','t','s','F','o','r','P','a','r','s','i','n',
584 'g',0 };
585 int bWantsForParsing = FALSE;
586 WCHAR szRegPath[100];
587 LONG r;
588
589 /*
590 * We can only get a filesystem path from a shellfolder
591 * if the value WantsFORPARSING exists in
592 * CLSID\\{...}\\shellfolder
593 * exception: the MyComputer folder has this keys not
594 * but like any filesystem backed
595 * folder it needs these behaviour
596 *
597 * Get the "WantsFORPARSING" flag from the registry
598 */
599
600 wcscpy (szRegPath, clsidW);
601 SHELL32_GUIDToStringW (clsid, &szRegPath[6]);
602 wcscat (szRegPath, shellfolderW);
603 r = SHGetValueW (HKEY_CLASSES_ROOT, szRegPath,
604 wantsForParsingW, NULL, NULL, NULL);
605 if (r == ERROR_SUCCESS)
606 bWantsForParsing = TRUE;
607
608 if ((GET_SHGDN_RELATION (dwFlags) == SHGDN_NORMAL) &&
609 bWantsForParsing)
610 {
611 /*
612 * We need the filesystem path to the destination folder
613 * Only the folder itself can know it
614 */
615 hr = SHELL32_GetDisplayNameOfChild (iface, pidl,
616 dwFlags, pszPath, MAX_PATH);
617 }
618 else
619 {
620 LPWSTR p = pszPath;
621
622 /* parsing name like ::{...} */
623 p[0] = ':';
624 p[1] = ':';
625 p += 2;
626 p += SHELL32_GUIDToStringW(&CLSID_MyComputer, p);
627
628 /* \:: */
629 p[0] = '\\';
630 p[1] = ':';
631 p[2] = ':';
632 p += 3;
633 SHELL32_GUIDToStringW(clsid, p);
634 }
635 }
636 else
637 {
638 /* user friendly name */
639
640 if (_ILIsMyComputer(pidl) && This->sName)
641 wcscpy(pszPath, This->sName);
642 else
643 HCR_GetClassNameW (clsid, pszPath, MAX_PATH);
644
645 TRACE("pszPath %s\n", debugstr_w(pszPath));
646 }
647 }
648 else
649 {
650 /* append my own path */
651 _ILSimpleGetTextW (pidl, pszPath, MAX_PATH);
652 }
653 }
654 else if (_ILIsDrive(pidl))
655 {
656
657 _ILSimpleGetTextW (pidl, pszPath, MAX_PATH); /* append my own path */
658 /* long view "lw_name (C:)" */
659 if (!(dwFlags & SHGDN_FORPARSING))
660 {
661 WCHAR wszDrive[18] = {0};
662 DWORD dwVolumeSerialNumber, dwMaximumComponentLength, dwFileSystemFlags;
663 static const WCHAR wszOpenBracket[] = {' ','(',0};
664 static const WCHAR wszCloseBracket[] = {')',0};
665
666 lstrcpynW(wszDrive, pszPath, 4);
667 pszPath[0] = L'\0';
668 GetVolumeInformationW (wszDrive, pszPath,
669 MAX_PATH - 7,
670 &dwVolumeSerialNumber,
671 &dwMaximumComponentLength, &dwFileSystemFlags, NULL, 0);
672 pszPath[MAX_PATH-1] = L'\0';
673 if (!wcslen(pszPath))
674 {
675 UINT DriveType, ResourceId;
676 DriveType = GetDriveTypeW(wszDrive);
677 switch(DriveType)
678 {
679 case DRIVE_FIXED:
680 ResourceId = IDS_DRIVE_FIXED;
681 break;
682 case DRIVE_REMOTE:
683 ResourceId = IDS_DRIVE_NETWORK;
684 break;
685 case DRIVE_CDROM:
686 ResourceId = IDS_DRIVE_CDROM;
687 break;
688 default:
689 ResourceId = 0;
690 }
691 if (ResourceId)
692 {
693 dwFileSystemFlags = LoadStringW(shell32_hInstance, ResourceId, pszPath, MAX_PATH);
694 if (dwFileSystemFlags > MAX_PATH - 7)
695 pszPath[MAX_PATH-7] = L'\0';
696 }
697 }
698 wcscat (pszPath, wszOpenBracket);
699 wszDrive[2] = L'\0';
700 wcscat (pszPath, wszDrive);
701 wcscat (pszPath, wszCloseBracket);
702 }
703 }
704 else
705 {
706 /* Neither a shell namespace extension nor a drive letter. */
707 ERR("Wrong pidl type\n");
708 CoTaskMemFree(pszPath);
709 return E_INVALIDARG;
710 }
711 }
712 else
713 {
714 /* Complex pidl. Let the child folder do the work */
715 hr = SHELL32_GetDisplayNameOfChild(iface, pidl, dwFlags, pszPath, MAX_PATH);
716 }
717
718 if (SUCCEEDED (hr))
719 {
720 strRet->uType = STRRET_WSTR;
721 strRet->u.pOleStr = pszPath;
722 }
723 else
724 CoTaskMemFree(pszPath);
725
726 TRACE ("-- (%p)->(%s)\n", This, strRet->uType == STRRET_CSTR ? strRet->u.cStr : debugstr_w(strRet->u.pOleStr));
727 return hr;
728 }
729
730 /**************************************************************************
731 * ISF_MyComputer_fnSetNameOf
732 * Changes the name of a file object or subfolder, possibly changing its item
733 * identifier in the process.
734 *
735 * PARAMETERS
736 * hwndOwner [in] Owner window for output
737 * pidl [in] simple pidl of item to change
738 * lpszName [in] the items new display name
739 * dwFlags [in] SHGNO formatting flags
740 * ppidlOut [out] simple pidl returned
741 */
742 static HRESULT WINAPI ISF_MyComputer_fnSetNameOf (
743 IShellFolder2 * iface, HWND hwndOwner, LPCITEMIDLIST pidl,
744 LPCOLESTR lpName, DWORD dwFlags, LPITEMIDLIST * pPidlOut)
745 {
746 IGenericSFImpl *This = (IGenericSFImpl *)iface;
747 LPWSTR sName;
748 HKEY hKey;
749 UINT length;
750 WCHAR szName[30];
751
752 TRACE ("(%p)->(%p,pidl=%p,%s,%u,%p)\n", This,
753 hwndOwner, pidl, debugstr_w (lpName), dwFlags, pPidlOut);
754
755 if (_ILIsDrive(pidl))
756 {
757 if (_ILSimpleGetTextW(pidl, szName, sizeof(szName)/sizeof(WCHAR)))
758 {
759 SetVolumeLabelW(szName, lpName);
760 }
761 if (pPidlOut)
762 *pPidlOut = _ILCreateDrive(szName);
763 return S_OK;
764 }
765
766
767 if (pPidlOut != NULL)
768 {
769 *pPidlOut = _ILCreateMyComputer();
770 }
771
772 length = (wcslen(lpName)+1) * sizeof(WCHAR);
773 sName = SHAlloc(length);
774
775 if (!sName)
776 {
777 return E_OUTOFMEMORY;
778 }
779
780 if (RegOpenKeyExW(HKEY_CURRENT_USER,
781 L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CLSID\\{20D04FE0-3AEA-1069-A2D8-08002B30309D}",
782 0,
783 KEY_WRITE,
784 &hKey) != ERROR_SUCCESS)
785 {
786 WARN("Error: failed to open registry key\n");
787 }
788 else
789 {
790 RegSetValueExW(hKey, NULL, 0, REG_SZ, (const LPBYTE)lpName, length);
791 RegCloseKey(hKey);
792 }
793
794 wcscpy(sName, lpName);
795 SHFree(This->sName);
796 This->sName = sName;
797 TRACE("result %s\n", debugstr_w(This->sName));
798 return S_OK;
799 }
800
801 static HRESULT WINAPI ISF_MyComputer_fnGetDefaultSearchGUID (
802 IShellFolder2 * iface, GUID * pguid)
803 {
804 IGenericSFImpl *This = (IGenericSFImpl *)iface;
805 FIXME ("(%p)\n", This);
806 return E_NOTIMPL;
807 }
808 static HRESULT WINAPI ISF_MyComputer_fnEnumSearches (
809 IShellFolder2 * iface, IEnumExtraSearch ** ppenum)
810 {
811 IGenericSFImpl *This = (IGenericSFImpl *)iface;
812 FIXME ("(%p)\n", This);
813 return E_NOTIMPL;
814 }
815 static HRESULT WINAPI ISF_MyComputer_fnGetDefaultColumn (
816 IShellFolder2 *iface, DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
817 {
818 IGenericSFImpl *This = (IGenericSFImpl *)iface;
819
820 TRACE ("(%p)\n", This);
821
822 if (pSort)
823 *pSort = 0;
824 if (pDisplay)
825 *pDisplay = 0;
826 return S_OK;
827 }
828 static HRESULT WINAPI ISF_MyComputer_fnGetDefaultColumnState (
829 IShellFolder2 * iface, UINT iColumn, DWORD * pcsFlags)
830 {
831 IGenericSFImpl *This = (IGenericSFImpl *)iface;
832
833 TRACE ("(%p)\n", This);
834
835 if (!pcsFlags || iColumn >= MYCOMPUTERSHELLVIEWCOLUMNS)
836 return E_INVALIDARG;
837 *pcsFlags = MyComputerSFHeader[iColumn].pcsFlags;
838 return S_OK;
839 }
840
841 static HRESULT WINAPI ISF_MyComputer_fnGetDetailsEx (IShellFolder2 * iface,
842 LPCITEMIDLIST pidl, const SHCOLUMNID * pscid, VARIANT * pv)
843 {
844 IGenericSFImpl *This = (IGenericSFImpl *)iface;
845 FIXME ("(%p)\n", This);
846 return E_NOTIMPL;
847 }
848
849 /* FIXME: drive size >4GB is rolling over */
850 static HRESULT WINAPI ISF_MyComputer_fnGetDetailsOf (IShellFolder2 * iface,
851 LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS * psd)
852 {
853 IGenericSFImpl *This = (IGenericSFImpl *)iface;
854 HRESULT hr;
855
856 TRACE ("(%p)->(%p %i %p)\n", This, pidl, iColumn, psd);
857
858 if (!psd || iColumn >= MYCOMPUTERSHELLVIEWCOLUMNS)
859 return E_INVALIDARG;
860
861 if (!pidl)
862 {
863 psd->fmt = MyComputerSFHeader[iColumn].fmt;
864 psd->cxChar = MyComputerSFHeader[iColumn].cxChar;
865 psd->str.uType = STRRET_CSTR;
866 LoadStringA (shell32_hInstance, MyComputerSFHeader[iColumn].colnameid,
867 psd->str.u.cStr, MAX_PATH);
868 return S_OK;
869 }
870 else
871 {
872 char szPath[MAX_PATH];
873 ULARGE_INTEGER ulBytes;
874
875 psd->str.u.cStr[0] = 0x00;
876 psd->str.uType = STRRET_CSTR;
877 switch (iColumn)
878 {
879 case 0: /* name */
880 hr = IShellFolder_GetDisplayNameOf (iface, pidl,
881 SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str);
882 break;
883 case 1: /* type */
884 _ILGetFileType (pidl, psd->str.u.cStr, MAX_PATH);
885 break;
886 case 2: /* total size */
887 if (_ILIsDrive (pidl))
888 {
889 _ILSimpleGetText (pidl, szPath, MAX_PATH);
890 GetDiskFreeSpaceExA (szPath, NULL, &ulBytes, NULL);
891 StrFormatByteSizeA (ulBytes.u.LowPart, psd->str.u.cStr, MAX_PATH);
892 }
893 break;
894 case 3: /* free size */
895 if (_ILIsDrive (pidl))
896 {
897 _ILSimpleGetText (pidl, szPath, MAX_PATH);
898 GetDiskFreeSpaceExA (szPath, &ulBytes, NULL, NULL);
899 StrFormatByteSizeA (ulBytes.u.LowPart, psd->str.u.cStr, MAX_PATH);
900 }
901 break;
902 }
903 hr = S_OK;
904 }
905
906 return hr;
907 }
908
909 static HRESULT WINAPI ISF_MyComputer_fnMapColumnToSCID (
910 IShellFolder2 * iface, UINT column, SHCOLUMNID * pscid)
911 {
912 IGenericSFImpl *This = (IGenericSFImpl *)iface;
913 FIXME ("(%p)\n", This);
914 return E_NOTIMPL;
915 }
916
917 static const IShellFolder2Vtbl vt_ShellFolder2 =
918 {
919 ISF_MyComputer_fnQueryInterface,
920 ISF_MyComputer_fnAddRef,
921 ISF_MyComputer_fnRelease,
922 ISF_MyComputer_fnParseDisplayName,
923 ISF_MyComputer_fnEnumObjects,
924 ISF_MyComputer_fnBindToObject,
925 ISF_MyComputer_fnBindToStorage,
926 ISF_MyComputer_fnCompareIDs,
927 ISF_MyComputer_fnCreateViewObject,
928 ISF_MyComputer_fnGetAttributesOf,
929 ISF_MyComputer_fnGetUIObjectOf,
930 ISF_MyComputer_fnGetDisplayNameOf,
931 ISF_MyComputer_fnSetNameOf,
932 /* ShellFolder2 */
933 ISF_MyComputer_fnGetDefaultSearchGUID,
934 ISF_MyComputer_fnEnumSearches,
935 ISF_MyComputer_fnGetDefaultColumn,
936 ISF_MyComputer_fnGetDefaultColumnState,
937 ISF_MyComputer_fnGetDetailsEx,
938 ISF_MyComputer_fnGetDetailsOf,
939 ISF_MyComputer_fnMapColumnToSCID
940 };
941
942 /************************************************************************
943 * IMCFldr_PersistFolder2_QueryInterface
944 */
945 static HRESULT WINAPI IMCFldr_PersistFolder2_QueryInterface (
946 IPersistFolder2 * iface, REFIID iid, LPVOID * ppvObj)
947 {
948 IGenericSFImpl *This = impl_from_IPersistFolder2(iface);
949
950 TRACE ("(%p)\n", This);
951
952 return IUnknown_QueryInterface (_IUnknown_ (This), iid, ppvObj);
953 }
954
955 /************************************************************************
956 * IMCFldr_PersistFolder2_AddRef
957 */
958 static ULONG WINAPI IMCFldr_PersistFolder2_AddRef (IPersistFolder2 * iface)
959 {
960 IGenericSFImpl *This = impl_from_IPersistFolder2(iface);
961
962 TRACE ("(%p)->(count=%u)\n", This, This->ref);
963
964 return IUnknown_AddRef (_IUnknown_ (This));
965 }
966
967 /************************************************************************
968 * ISFPersistFolder_Release
969 */
970 static ULONG WINAPI IMCFldr_PersistFolder2_Release (IPersistFolder2 * iface)
971 {
972 IGenericSFImpl *This = impl_from_IPersistFolder2(iface);
973
974 TRACE ("(%p)->(count=%u)\n", This, This->ref);
975
976 return IUnknown_Release (_IUnknown_ (This));
977 }
978
979 /************************************************************************
980 * IMCFldr_PersistFolder2_GetClassID
981 */
982 static HRESULT WINAPI IMCFldr_PersistFolder2_GetClassID (
983 IPersistFolder2 * iface, CLSID * lpClassId)
984 {
985 IGenericSFImpl *This = impl_from_IPersistFolder2(iface);
986
987 TRACE ("(%p)\n", This);
988
989 if (!lpClassId)
990 return E_POINTER;
991 *lpClassId = CLSID_MyComputer;
992
993 return S_OK;
994 }
995
996 /************************************************************************
997 * IMCFldr_PersistFolder2_Initialize
998 *
999 * NOTES: it makes no sense to change the pidl
1000 */
1001 static HRESULT WINAPI IMCFldr_PersistFolder2_Initialize (
1002 IPersistFolder2 * iface, LPCITEMIDLIST pidl)
1003 {
1004 IGenericSFImpl *This = impl_from_IPersistFolder2(iface);
1005 TRACE ("(%p)->(%p)\n", This, pidl);
1006
1007 if (This->pidlRoot)
1008 SHFree((LPVOID)This->pidlRoot);
1009
1010 This->pidlRoot = ILClone(pidl);
1011 return S_OK;
1012 }
1013
1014 /**************************************************************************
1015 * IPersistFolder2_fnGetCurFolder
1016 */
1017 static HRESULT WINAPI IMCFldr_PersistFolder2_GetCurFolder (
1018 IPersistFolder2 * iface, LPITEMIDLIST * pidl)
1019 {
1020 IGenericSFImpl *This = impl_from_IPersistFolder2(iface);
1021
1022 TRACE ("(%p)->(%p)\n", This, pidl);
1023
1024 if (!pidl)
1025 return E_POINTER;
1026 *pidl = ILClone (This->pidlRoot);
1027 return S_OK;
1028 }
1029
1030 static const IPersistFolder2Vtbl vt_PersistFolder2 =
1031 {
1032 IMCFldr_PersistFolder2_QueryInterface,
1033 IMCFldr_PersistFolder2_AddRef,
1034 IMCFldr_PersistFolder2_Release,
1035 IMCFldr_PersistFolder2_GetClassID,
1036 IMCFldr_PersistFolder2_Initialize,
1037 IMCFldr_PersistFolder2_GetCurFolder
1038 };