Sync with trunk r63831.
[reactos.git] / dll / win32 / shell32 / folders / mycomp.cpp
1 /*
2 * Virtual Workplace folder
3 *
4 * Copyright 1997 Marcus Meissner
5 * Copyright 1998, 1999, 2002 Juergen Schmied
6 * Copyright 2009 Andrew Hill
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 */
22
23 #include <precomp.h>
24
25 WINE_DEFAULT_DEBUG_CHANNEL (shell);
26
27 /*
28 CDrivesFolder should create a CRegFolder to represent the virtual items that exist only in
29 the registry. The CRegFolder is aggregated by the CDrivesFolder.
30 The CDrivesFolderEnum class should enumerate only drives on the system. Since the CRegFolder
31 implementation of IShellFolder::EnumObjects enumerates the virtual items, the
32 CDrivesFolderEnum is only responsible for returning the physical items.
33
34 2. At least on my XP system, the drive pidls returned are of type PT_DRIVE1, not PT_DRIVE
35 3. The parsing name returned for my computer is incorrect. It should be "My Computer"
36 */
37
38 /***********************************************************************
39 * IShellFolder implementation
40 */
41
42 class CDrivesFolderEnum :
43 public IEnumIDListImpl
44 {
45 public:
46 CDrivesFolderEnum();
47 ~CDrivesFolderEnum();
48 HRESULT WINAPI Initialize(HWND hwndOwner, DWORD dwFlags);
49 BOOL CreateMyCompEnumList(DWORD dwFlags);
50
51 BEGIN_COM_MAP(CDrivesFolderEnum)
52 COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList)
53 END_COM_MAP()
54 };
55
56 /***********************************************************************
57 * IShellFolder [MyComputer] implementation
58 */
59
60 static const shvheader MyComputerSFHeader[] = {
61 {IDS_SHV_COLUMN1, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15},
62 {IDS_SHV_COLUMN3, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
63 {IDS_SHV_COLUMN6, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
64 {IDS_SHV_COLUMN7, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
65 };
66
67 #define MYCOMPUTERSHELLVIEWCOLUMNS 4
68
69 CDrivesFolderEnum::CDrivesFolderEnum()
70 {
71 }
72
73 CDrivesFolderEnum::~CDrivesFolderEnum()
74 {
75 }
76
77 HRESULT WINAPI CDrivesFolderEnum::Initialize(HWND hwndOwner, DWORD dwFlags)
78 {
79 if (CreateMyCompEnumList(dwFlags) == FALSE)
80 return E_FAIL;
81
82 return S_OK;
83 }
84
85 /**************************************************************************
86 * CDrivesFolderEnum::CreateMyCompEnumList()
87 */
88
89 BOOL CDrivesFolderEnum::CreateMyCompEnumList(DWORD dwFlags)
90 {
91 BOOL bRet = TRUE;
92 static const WCHAR MyComputer_NameSpaceW[] = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MyComputer\\Namespace";
93
94 TRACE("(%p)->(flags=0x%08x)\n", this, dwFlags);
95
96 /* enumerate the folders */
97 if (dwFlags & SHCONTF_FOLDERS)
98 {
99 WCHAR wszDriveName[] = {'A', ':', '\\', '\0'};
100 DWORD dwDrivemap = GetLogicalDrives();
101 HKEY hKey;
102 UINT i;
103
104 while (bRet && wszDriveName[0] <= 'Z')
105 {
106 if(dwDrivemap & 0x00000001L)
107 bRet = AddToEnumList(_ILCreateDrive(wszDriveName));
108 wszDriveName[0]++;
109 dwDrivemap = dwDrivemap >> 1;
110 }
111
112 TRACE("-- (%p)-> enumerate (mycomputer shell extensions)\n", this);
113 for (i = 0; i < 2; i++)
114 {
115 if (bRet && ERROR_SUCCESS == RegOpenKeyExW(i == 0 ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER,
116 MyComputer_NameSpaceW, 0, KEY_READ, &hKey))
117 {
118 WCHAR wszBuf[50];
119 DWORD dwSize, j = 0;
120 LONG ErrorCode;
121 LPITEMIDLIST pidl;
122
123 while (bRet)
124 {
125 dwSize = sizeof(wszBuf) / sizeof(wszBuf[0]);
126 ErrorCode = RegEnumKeyExW(hKey, j, wszBuf, &dwSize, 0, NULL, NULL, NULL);
127 if (ERROR_SUCCESS == ErrorCode)
128 {
129 if (wszBuf[0] != L'{')
130 {
131 dwSize = sizeof(wszBuf);
132 RegGetValueW(hKey, wszBuf, NULL, RRF_RT_REG_SZ, NULL, wszBuf, &dwSize);
133 }
134
135 /* FIXME: shell extensions - the type should be PT_SHELLEXT (tested) */
136 pidl = _ILCreateGuidFromStrW(wszBuf);
137 if (pidl != NULL)
138 bRet = AddToEnumList(pidl);
139 else
140 ERR("Invalid MyComputer namespace extesion: %s\n", wszBuf);
141 j++;
142 }
143 else if (ERROR_NO_MORE_ITEMS == ErrorCode)
144 break;
145 else
146 bRet = FALSE;
147 }
148 RegCloseKey(hKey);
149 }
150 }
151 }
152 return bRet;
153 }
154
155 CDrivesFolder::CDrivesFolder()
156 {
157 pidlRoot = NULL;
158 sName = NULL;
159 }
160
161 CDrivesFolder::~CDrivesFolder()
162 {
163 TRACE ("-- destroying IShellFolder(%p)\n", this);
164 SHFree(pidlRoot);
165 }
166
167 HRESULT WINAPI CDrivesFolder::FinalConstruct()
168 {
169 DWORD dwSize;
170 WCHAR szName[MAX_PATH];
171 WCHAR wszMyCompKey[256];
172 INT i;
173
174 pidlRoot = _ILCreateMyComputer(); /* my qualified pidl */
175 if (pidlRoot == NULL)
176 return E_OUTOFMEMORY;
177
178 i = swprintf(wszMyCompKey, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CLSID\\");
179 StringFromGUID2(CLSID_MyComputer, wszMyCompKey + i, sizeof(wszMyCompKey) / sizeof(wszMyCompKey[0]) - i);
180 dwSize = sizeof(szName);
181 if (RegGetValueW(HKEY_CURRENT_USER, wszMyCompKey,
182 NULL, RRF_RT_REG_SZ, NULL, szName, &dwSize) == ERROR_SUCCESS)
183 {
184 sName = (LPWSTR)SHAlloc((wcslen(szName) + 1) * sizeof(WCHAR));
185 if (sName)
186 wcscpy(sName, szName);
187 TRACE("sName %s\n", debugstr_w(sName));
188 }
189 return S_OK;
190 }
191
192 /**************************************************************************
193 * CDrivesFolder::ParseDisplayName
194 */
195 HRESULT WINAPI CDrivesFolder::ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName,
196 DWORD * pchEaten, LPITEMIDLIST * ppidl, DWORD * pdwAttributes)
197 {
198 HRESULT hr = E_INVALIDARG;
199 LPCWSTR szNext = NULL;
200 WCHAR szElement[MAX_PATH];
201 LPITEMIDLIST pidlTemp = NULL;
202 CLSID clsid;
203
204 TRACE("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n", this,
205 hwndOwner, pbc, lpszDisplayName, debugstr_w (lpszDisplayName),
206 pchEaten, ppidl, pdwAttributes);
207
208 *ppidl = 0;
209 if (pchEaten)
210 *pchEaten = 0; /* strange but like the original */
211
212 /* handle CLSID paths */
213 if (lpszDisplayName[0] == ':' && lpszDisplayName[1] == ':')
214 {
215 szNext = GetNextElementW (lpszDisplayName, szElement, MAX_PATH);
216 TRACE ("-- element: %s\n", debugstr_w (szElement));
217 CLSIDFromString (szElement + 2, &clsid);
218 pidlTemp = _ILCreateGuid (PT_GUID, clsid);
219 }
220 /* do we have an absolute path name ? */
221 else if (PathGetDriveNumberW (lpszDisplayName) >= 0 &&
222 lpszDisplayName[2] == (WCHAR) '\\')
223 {
224 szNext = GetNextElementW (lpszDisplayName, szElement, MAX_PATH);
225 /* make drive letter uppercase to enable PIDL comparison */
226 szElement[0] = toupper(szElement[0]);
227 pidlTemp = _ILCreateDrive (szElement);
228 }
229
230 if (szNext && *szNext)
231 {
232 hr = SHELL32_ParseNextElement (this, hwndOwner, pbc, &pidlTemp,
233 (LPOLESTR) szNext, pchEaten, pdwAttributes);
234 }
235 else
236 {
237 if (pdwAttributes && *pdwAttributes)
238 SHELL32_GetItemAttributes (this,
239 pidlTemp, pdwAttributes);
240 hr = S_OK;
241 }
242
243 *ppidl = pidlTemp;
244
245 TRACE ("(%p)->(-- ret=0x%08x)\n", this, hr);
246
247 return hr;
248 }
249
250 /**************************************************************************
251 * CDrivesFolder::EnumObjects
252 */
253 HRESULT WINAPI CDrivesFolder::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList)
254 {
255 CComObject<CDrivesFolderEnum> *theEnumerator;
256 CComPtr<IEnumIDList> result;
257 HRESULT hResult;
258
259 TRACE ("(%p)->(HWND=%p flags=0x%08x pplist=%p)\n", this, hwndOwner, dwFlags, ppEnumIDList);
260
261 if (ppEnumIDList == NULL)
262 return E_POINTER;
263
264 *ppEnumIDList = NULL;
265 ATLTRY(theEnumerator = new CComObject<CDrivesFolderEnum>);
266
267 if (theEnumerator == NULL)
268 return E_OUTOFMEMORY;
269
270 hResult = theEnumerator->QueryInterface(IID_IEnumIDList, (void **)&result);
271 if (FAILED(hResult))
272 {
273 delete theEnumerator;
274 return hResult;
275 }
276
277 hResult = theEnumerator->Initialize(hwndOwner, dwFlags);
278 if (FAILED(hResult))
279 return hResult;
280 *ppEnumIDList = result.Detach();
281
282 TRACE("-- (%p)->(new ID List: %p)\n", this, *ppEnumIDList);
283
284 return S_OK;
285 }
286
287 /**************************************************************************
288 * CDrivesFolder::BindToObject
289 */
290 HRESULT WINAPI CDrivesFolder::BindToObject(LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
291 {
292 TRACE("(%p)->(pidl=%p,%p,%s,%p)\n", this,
293 pidl, pbcReserved, shdebugstr_guid(&riid), ppvOut);
294
295 return SHELL32_BindToChild(pidlRoot, NULL, pidl, riid, ppvOut);
296 }
297
298 /**************************************************************************
299 * CDrivesFolder::BindToStorage
300 */
301 HRESULT WINAPI CDrivesFolder::BindToStorage(LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
302 {
303 FIXME("(%p)->(pidl=%p,%p,%s,%p) stub\n", this,
304 pidl, pbcReserved, shdebugstr_guid (&riid), ppvOut);
305
306 *ppvOut = NULL;
307 return E_NOTIMPL;
308 }
309
310 /**************************************************************************
311 * CDrivesFolder::CompareIDs
312 */
313
314 HRESULT WINAPI CDrivesFolder::CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
315 {
316 int nReturn;
317
318 TRACE("(%p)->(0x%08lx,pidl1=%p,pidl2=%p)\n", this, lParam, pidl1, pidl2);
319 nReturn = SHELL32_CompareIDs (this, lParam, pidl1, pidl2);
320 TRACE("-- %i\n", nReturn);
321 return nReturn;
322 }
323
324 /**************************************************************************
325 * CDrivesFolder::CreateViewObject
326 */
327 HRESULT WINAPI CDrivesFolder::CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID * ppvOut)
328 {
329 LPSHELLVIEW pShellView;
330 HRESULT hr = E_INVALIDARG;
331
332 TRACE("(%p)->(hwnd=%p,%s,%p)\n", this,
333 hwndOwner, shdebugstr_guid (&riid), ppvOut);
334
335 if (!ppvOut)
336 return hr;
337
338 *ppvOut = NULL;
339
340 if (IsEqualIID(riid, IID_IDropTarget))
341 {
342 WARN("IDropTarget not implemented\n");
343 hr = E_NOTIMPL;
344 }
345 else if (IsEqualIID(riid, IID_IContextMenu))
346 {
347 WARN("IContextMenu not implemented\n");
348 hr = E_NOTIMPL;
349 }
350 else if (IsEqualIID(riid, IID_IShellView))
351 {
352 hr = IShellView_Constructor ((IShellFolder *)this, &pShellView);
353 if (pShellView)
354 {
355 hr = pShellView->QueryInterface(riid, ppvOut);
356 pShellView->Release();
357 }
358 }
359 TRACE ("-- (%p)->(interface=%p)\n", this, ppvOut);
360 return hr;
361 }
362
363 /**************************************************************************
364 * CDrivesFolder::GetAttributesOf
365 */
366 HRESULT WINAPI CDrivesFolder::GetAttributesOf(UINT cidl, LPCITEMIDLIST * apidl, DWORD * rgfInOut)
367 {
368 static const DWORD dwComputerAttributes =
369 SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET |
370 SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_CANLINK;
371 static const DWORD dwControlPanelAttributes =
372 SFGAO_HASSUBFOLDER | SFGAO_FOLDER | SFGAO_CANLINK;
373 static const DWORD dwDriveAttributes =
374 SFGAO_HASSUBFOLDER | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR |
375 SFGAO_DROPTARGET | SFGAO_HASPROPSHEET | SFGAO_CANRENAME | SFGAO_CANLINK;
376
377 TRACE ("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n",
378 this, cidl, apidl, rgfInOut, rgfInOut ? *rgfInOut : 0);
379
380 if (cidl && !apidl)
381 return E_INVALIDARG;
382
383 if (*rgfInOut == 0)
384 *rgfInOut = ~0;
385
386 /* FIXME: always add SFGAO_CANLINK */
387 if(cidl == 0)
388 *rgfInOut &= dwComputerAttributes;
389 else
390 {
391 for (UINT i = 0; i < cidl; ++i)
392 {
393 if (_ILIsDrive(apidl[i]))
394 *rgfInOut &= dwDriveAttributes;
395 else if (_ILIsControlPanel(apidl[i]))
396 *rgfInOut &= dwControlPanelAttributes;
397 else
398 {
399 pdump(apidl[i]);
400 SHELL32_GetItemAttributes(this, apidl[i], rgfInOut);
401 }
402 }
403 }
404
405 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
406 *rgfInOut &= ~SFGAO_VALIDATE;
407
408 TRACE ("-- result=0x%08x\n", *rgfInOut);
409 return S_OK;
410 }
411
412 /**************************************************************************
413 * CDrivesFolder::GetUIObjectOf
414 *
415 * PARAMETERS
416 * hwndOwner [in] Parent window for any output
417 * cidl [in] array size
418 * apidl [in] simple pidl array
419 * riid [in] Requested Interface
420 * prgfInOut [ ] reserved
421 * ppvObject [out] Resulting Interface
422 *
423 */
424 HRESULT WINAPI CDrivesFolder::GetUIObjectOf(HWND hwndOwner,
425 UINT cidl, LPCITEMIDLIST *apidl,
426 REFIID riid, UINT *prgfInOut, LPVOID *ppvOut)
427 {
428 LPITEMIDLIST pidl;
429 IUnknown *pObj = NULL;
430 HRESULT hr = E_INVALIDARG;
431
432 TRACE("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n", this,
433 hwndOwner, cidl, apidl, shdebugstr_guid (&riid), prgfInOut, ppvOut);
434
435 if (!ppvOut)
436 return hr;
437
438 *ppvOut = NULL;
439
440 if (IsEqualIID (riid, IID_IContextMenu) && (cidl >= 1))
441 {
442 hr = CDefFolderMenu_Create2(pidlRoot, hwndOwner, cidl, apidl, (IShellFolder*)this, NULL, 0, NULL, (IContextMenu**)&pObj);
443 }
444 else if (IsEqualIID (riid, IID_IDataObject) && (cidl >= 1))
445 {
446 hr = IDataObject_Constructor (hwndOwner,
447 pidlRoot, apidl, cidl, (IDataObject **)&pObj);
448 }
449 else if (IsEqualIID (riid, IID_IExtractIconA) && (cidl == 1))
450 {
451 pidl = ILCombine (pidlRoot, apidl[0]);
452 pObj = (LPUNKNOWN) IExtractIconA_Constructor (pidl);
453 SHFree (pidl);
454 hr = S_OK;
455 }
456 else if (IsEqualIID (riid, IID_IExtractIconW) && (cidl == 1))
457 {
458 pidl = ILCombine (pidlRoot, apidl[0]);
459 pObj = (LPUNKNOWN) IExtractIconW_Constructor (pidl);
460 SHFree (pidl);
461 hr = S_OK;
462 }
463 else if (IsEqualIID (riid, IID_IDropTarget) && (cidl >= 1))
464 {
465 hr = this->QueryInterface(IID_IDropTarget,
466 (LPVOID *) &pObj);
467 }
468 else if ((IsEqualIID(riid, IID_IShellLinkW) ||
469 IsEqualIID(riid, IID_IShellLinkA)) && (cidl == 1))
470 {
471 pidl = ILCombine (pidlRoot, apidl[0]);
472 hr = IShellLink_ConstructFromFile(NULL, riid, pidl, (LPVOID*) &pObj);
473 SHFree (pidl);
474 }
475 else
476 hr = E_NOINTERFACE;
477
478 if (SUCCEEDED(hr) && !pObj)
479 hr = E_OUTOFMEMORY;
480
481 *ppvOut = pObj;
482 TRACE ("(%p)->hr=0x%08x\n", this, hr);
483 return hr;
484 }
485
486 /**************************************************************************
487 * CDrivesFolder::GetDisplayNameOf
488 */
489 HRESULT WINAPI CDrivesFolder::GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD dwFlags, LPSTRRET strRet)
490 {
491 LPWSTR pszPath;
492 HRESULT hr = S_OK;
493
494 TRACE ("(%p)->(pidl=%p,0x%08x,%p)\n", this, pidl, dwFlags, strRet);
495 pdump (pidl);
496
497 if (!strRet)
498 return E_INVALIDARG;
499
500 pszPath = (LPWSTR)CoTaskMemAlloc((MAX_PATH + 1) * sizeof(WCHAR));
501 if (!pszPath)
502 return E_OUTOFMEMORY;
503
504 pszPath[0] = 0;
505
506 if (!pidl->mkid.cb)
507 {
508 /* parsing name like ::{...} */
509 pszPath[0] = ':';
510 pszPath[1] = ':';
511 SHELL32_GUIDToStringW(CLSID_MyComputer, &pszPath[2]);
512 }
513 else if (_ILIsPidlSimple(pidl))
514 {
515 /* take names of special folders only if its only this folder */
516 if (_ILIsSpecialFolder(pidl))
517 {
518 GUID const *clsid;
519
520 clsid = _ILGetGUIDPointer (pidl);
521 if (clsid)
522 {
523 if (GET_SHGDN_FOR (dwFlags) & SHGDN_FORPARSING)
524 {
525 static const WCHAR clsidW[] = L"CLSID\\";
526 static const WCHAR shellfolderW[] = L"\\shellfolder";
527 static const WCHAR wantsForParsingW[] = L"WantsForParsing";
528 BOOL bWantsForParsing = FALSE;
529 WCHAR szRegPath[100];
530 LONG r;
531
532 /*
533 * We can only get a filesystem path from a shellfolder
534 * if the value WantsFORPARSING exists in
535 * CLSID\\{...}\\shellfolder
536 * exception: the MyComputer folder has this keys not
537 * but like any filesystem backed
538 * folder it needs these behaviour
539 *
540 * Get the "WantsFORPARSING" flag from the registry
541 */
542
543 wcscpy(szRegPath, clsidW);
544 SHELL32_GUIDToStringW(*clsid, &szRegPath[6]);
545 wcscat(szRegPath, shellfolderW);
546 r = SHGetValueW(HKEY_CLASSES_ROOT, szRegPath,
547 wantsForParsingW, NULL, NULL, NULL);
548 if (r == ERROR_SUCCESS)
549 bWantsForParsing = TRUE;
550
551 if ((GET_SHGDN_RELATION (dwFlags) == SHGDN_NORMAL) &&
552 bWantsForParsing)
553 {
554 /*
555 * We need the filesystem path to the destination folder
556 * Only the folder itself can know it
557 */
558 hr = SHELL32_GetDisplayNameOfChild (this, pidl,
559 dwFlags, pszPath, MAX_PATH);
560 }
561 else
562 {
563 LPWSTR p = pszPath;
564
565 /* parsing name like ::{...} */
566 p[0] = ':';
567 p[1] = ':';
568 p += 2;
569 p += SHELL32_GUIDToStringW(CLSID_MyComputer, p);
570
571 /* \:: */
572 p[0] = '\\';
573 p[1] = ':';
574 p[2] = ':';
575 p += 3;
576 SHELL32_GUIDToStringW(*clsid, p);
577 }
578 }
579 else
580 {
581 /* user friendly name */
582
583 if (_ILIsMyComputer(pidl) && sName)
584 wcscpy(pszPath, sName);
585 else
586 HCR_GetClassNameW (*clsid, pszPath, MAX_PATH);
587
588 TRACE("pszPath %s\n", debugstr_w(pszPath));
589 }
590 }
591 else
592 {
593 /* append my own path */
594 _ILSimpleGetTextW(pidl, pszPath, MAX_PATH);
595 }
596 }
597 else if (_ILIsDrive(pidl))
598 {
599
600 _ILSimpleGetTextW(pidl, pszPath, MAX_PATH); /* append my own path */
601 /* long view "lw_name (C:)" */
602 if (!(dwFlags & SHGDN_FORPARSING))
603 {
604 WCHAR wszDrive[18] = {0};
605 DWORD dwVolumeSerialNumber, dwMaximumComponentLength, dwFileSystemFlags;
606 static const WCHAR wszOpenBracket[] = {' ', '(', 0};
607 static const WCHAR wszCloseBracket[] = {')', 0};
608
609 lstrcpynW(wszDrive, pszPath, 4);
610 pszPath[0] = L'\0';
611 GetVolumeInformationW(wszDrive, pszPath,
612 MAX_PATH - 7,
613 &dwVolumeSerialNumber,
614 &dwMaximumComponentLength, &dwFileSystemFlags, NULL, 0);
615 pszPath[MAX_PATH-1] = L'\0';
616 if (!wcslen(pszPath))
617 {
618 UINT DriveType, ResourceId;
619 DriveType = GetDriveTypeW(wszDrive);
620 switch(DriveType)
621 {
622 case DRIVE_FIXED:
623 ResourceId = IDS_DRIVE_FIXED;
624 break;
625 case DRIVE_REMOTE:
626 ResourceId = IDS_DRIVE_NETWORK;
627 break;
628 case DRIVE_CDROM:
629 ResourceId = IDS_DRIVE_CDROM;
630 break;
631 default:
632 ResourceId = 0;
633 }
634 if (ResourceId)
635 {
636 dwFileSystemFlags = LoadStringW(shell32_hInstance, ResourceId, pszPath, MAX_PATH);
637 if (dwFileSystemFlags > MAX_PATH - 7)
638 pszPath[MAX_PATH-7] = L'\0';
639 }
640 }
641 wcscat (pszPath, wszOpenBracket);
642 wszDrive[2] = L'\0';
643 wcscat (pszPath, wszDrive);
644 wcscat (pszPath, wszCloseBracket);
645 }
646 }
647 else
648 {
649 /* Neither a shell namespace extension nor a drive letter. */
650 ERR("Wrong pidl type\n");
651 CoTaskMemFree(pszPath);
652 return E_INVALIDARG;
653 }
654 }
655 else
656 {
657 /* Complex pidl. Let the child folder do the work */
658 hr = SHELL32_GetDisplayNameOfChild(this, pidl, dwFlags, pszPath, MAX_PATH);
659 }
660
661 if (SUCCEEDED(hr))
662 {
663 strRet->uType = STRRET_WSTR;
664 strRet->pOleStr = pszPath;
665 }
666 else
667 CoTaskMemFree(pszPath);
668
669 TRACE("-- (%p)->(%s)\n", this, strRet->uType == STRRET_CSTR ? strRet->cStr : debugstr_w(strRet->pOleStr));
670 return hr;
671 }
672
673 /**************************************************************************
674 * CDrivesFolder::SetNameOf
675 * Changes the name of a file object or subfolder, possibly changing its item
676 * identifier in the process.
677 *
678 * PARAMETERS
679 * hwndOwner [in] Owner window for output
680 * pidl [in] simple pidl of item to change
681 * lpszName [in] the items new display name
682 * dwFlags [in] SHGNO formatting flags
683 * ppidlOut [out] simple pidl returned
684 */
685 HRESULT WINAPI CDrivesFolder::SetNameOf(HWND hwndOwner, LPCITEMIDLIST pidl,
686 LPCOLESTR lpName, DWORD dwFlags, LPITEMIDLIST *pPidlOut)
687 {
688 LPWSTR sName;
689 HKEY hKey;
690 UINT length;
691 WCHAR szName[30];
692
693 TRACE("(%p)->(%p,pidl=%p,%s,%u,%p)\n", this,
694 hwndOwner, pidl, debugstr_w (lpName), dwFlags, pPidlOut);
695
696 if (_ILIsDrive(pidl))
697 {
698 if (_ILSimpleGetTextW(pidl, szName, _countof(szName)))
699 SetVolumeLabelW(szName, lpName);
700 if (pPidlOut)
701 *pPidlOut = _ILCreateDrive(szName);
702 return S_OK;
703 }
704
705
706 if (pPidlOut != NULL)
707 *pPidlOut = _ILCreateMyComputer();
708
709 length = (wcslen(lpName) + 1) * sizeof(WCHAR);
710 sName = (LPWSTR)SHAlloc(length);
711
712 if (!sName)
713 return E_OUTOFMEMORY;
714
715 if (RegOpenKeyExW(HKEY_CURRENT_USER,
716 L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CLSID\\{20D04FE0-3AEA-1069-A2D8-08002B30309D}",
717 0,
718 KEY_WRITE,
719 &hKey) != ERROR_SUCCESS)
720 {
721 WARN("Error: failed to open registry key\n");
722 }
723 else
724 {
725 RegSetValueExW(hKey, NULL, 0, REG_SZ, (const LPBYTE)lpName, length);
726 RegCloseKey(hKey);
727 }
728
729 wcscpy(sName, lpName);
730 SHFree(this->sName);
731 this->sName = sName;
732 TRACE("result %s\n", debugstr_w(sName));
733 return S_OK;
734 }
735
736 HRESULT WINAPI CDrivesFolder::GetDefaultSearchGUID(GUID * pguid)
737 {
738 FIXME ("(%p)\n", this);
739 return E_NOTIMPL;
740 }
741
742 HRESULT WINAPI CDrivesFolder::EnumSearches(IEnumExtraSearch ** ppenum)
743 {
744 FIXME ("(%p)\n", this);
745 return E_NOTIMPL;
746 }
747
748 HRESULT WINAPI CDrivesFolder::GetDefaultColumn (DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
749 {
750 TRACE ("(%p)\n", this);
751
752 if (pSort)
753 *pSort = 0;
754 if (pDisplay)
755 *pDisplay = 0;
756 return S_OK;
757 }
758
759 HRESULT WINAPI CDrivesFolder::GetDefaultColumnState(UINT iColumn, DWORD * pcsFlags)
760 {
761 TRACE ("(%p)\n", this);
762
763 if (!pcsFlags || iColumn >= MYCOMPUTERSHELLVIEWCOLUMNS)
764 return E_INVALIDARG;
765 *pcsFlags = MyComputerSFHeader[iColumn].pcsFlags;
766 return S_OK;
767 }
768
769 HRESULT WINAPI CDrivesFolder::GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID * pscid, VARIANT * pv)
770 {
771 FIXME ("(%p)\n", this);
772 return E_NOTIMPL;
773 }
774
775 /* FIXME: drive size >4GB is rolling over */
776 HRESULT WINAPI CDrivesFolder::GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *psd)
777 {
778 HRESULT hr;
779
780 TRACE ("(%p)->(%p %i %p)\n", this, pidl, iColumn, psd);
781
782 if (!psd || iColumn >= MYCOMPUTERSHELLVIEWCOLUMNS)
783 return E_INVALIDARG;
784
785 if (!pidl)
786 {
787 psd->fmt = MyComputerSFHeader[iColumn].fmt;
788 psd->cxChar = MyComputerSFHeader[iColumn].cxChar;
789 psd->str.uType = STRRET_CSTR;
790 LoadStringA(shell32_hInstance, MyComputerSFHeader[iColumn].colnameid,
791 psd->str.cStr, MAX_PATH);
792 return S_OK;
793 }
794 else
795 {
796 char szPath[MAX_PATH];
797 ULARGE_INTEGER ulBytes;
798
799 psd->str.cStr[0] = 0x00;
800 psd->str.uType = STRRET_CSTR;
801 switch (iColumn)
802 {
803 case 0: /* name */
804 hr = GetDisplayNameOf(pidl,
805 SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str);
806 break;
807 case 1: /* type */
808 _ILGetFileType(pidl, psd->str.cStr, MAX_PATH);
809 break;
810 case 2: /* total size */
811 if (_ILIsDrive(pidl))
812 {
813 _ILSimpleGetText (pidl, szPath, MAX_PATH);
814 GetDiskFreeSpaceExA (szPath, NULL, &ulBytes, NULL);
815 StrFormatByteSizeA (ulBytes.LowPart, psd->str.cStr, MAX_PATH);
816 }
817 break;
818 case 3: /* free size */
819 if (_ILIsDrive(pidl))
820 {
821 _ILSimpleGetText (pidl, szPath, MAX_PATH);
822 GetDiskFreeSpaceExA (szPath, &ulBytes, NULL, NULL);
823 StrFormatByteSizeA (ulBytes.LowPart, psd->str.cStr, MAX_PATH);
824 }
825 break;
826 }
827 hr = S_OK;
828 }
829
830 return hr;
831 }
832
833 HRESULT WINAPI CDrivesFolder::MapColumnToSCID(UINT column, SHCOLUMNID * pscid)
834 {
835 FIXME("(%p)\n", this);
836 return E_NOTIMPL;
837 }
838
839 /************************************************************************
840 * CDrivesFolder::GetClassID
841 */
842 HRESULT WINAPI CDrivesFolder::GetClassID(CLSID *lpClassId)
843 {
844 TRACE ("(%p)\n", this);
845
846 if (!lpClassId)
847 return E_POINTER;
848
849 *lpClassId = CLSID_MyComputer;
850 return S_OK;
851 }
852
853 /************************************************************************
854 * CDrivesFolder::Initialize
855 *
856 * NOTES: it makes no sense to change the pidl
857 */
858 HRESULT WINAPI CDrivesFolder::Initialize(LPCITEMIDLIST pidl)
859 {
860 TRACE ("(%p)->(%p)\n", this, pidl);
861
862 if (pidlRoot)
863 SHFree((LPVOID)pidlRoot);
864
865 pidlRoot = ILClone(pidl);
866 return S_OK;
867 }
868
869 /**************************************************************************
870 * CDrivesFolder::GetCurFolder
871 */
872 HRESULT WINAPI CDrivesFolder::GetCurFolder(LPITEMIDLIST *pidl)
873 {
874 TRACE("(%p)->(%p)\n", this, pidl);
875
876 if (!pidl)
877 return E_POINTER;
878
879 *pidl = ILClone(pidlRoot);
880 return S_OK;
881 }