d9515caa1dc1eb8830b750fcdbacf3e2b15ae9ce
[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 IDropTarget * pDt = NULL;
466 hr = this->QueryInterface(IID_PPV_ARG(IDropTarget, &pDt));
467 pObj = pDt;
468 }
469 else if ((IsEqualIID(riid, IID_IShellLinkW) ||
470 IsEqualIID(riid, IID_IShellLinkA)) && (cidl == 1))
471 {
472 pidl = ILCombine (pidlRoot, apidl[0]);
473 hr = IShellLink_ConstructFromFile(NULL, riid, pidl, (LPVOID*) &pObj);
474 SHFree (pidl);
475 }
476 else
477 hr = E_NOINTERFACE;
478
479 if (SUCCEEDED(hr) && !pObj)
480 hr = E_OUTOFMEMORY;
481
482 *ppvOut = pObj;
483 TRACE ("(%p)->hr=0x%08x\n", this, hr);
484 return hr;
485 }
486
487 /**************************************************************************
488 * CDrivesFolder::GetDisplayNameOf
489 */
490 HRESULT WINAPI CDrivesFolder::GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD dwFlags, LPSTRRET strRet)
491 {
492 LPWSTR pszPath;
493 HRESULT hr = S_OK;
494
495 TRACE ("(%p)->(pidl=%p,0x%08x,%p)\n", this, pidl, dwFlags, strRet);
496 pdump (pidl);
497
498 if (!strRet)
499 return E_INVALIDARG;
500
501 pszPath = (LPWSTR)CoTaskMemAlloc((MAX_PATH + 1) * sizeof(WCHAR));
502 if (!pszPath)
503 return E_OUTOFMEMORY;
504
505 pszPath[0] = 0;
506
507 if (!pidl->mkid.cb)
508 {
509 /* parsing name like ::{...} */
510 pszPath[0] = ':';
511 pszPath[1] = ':';
512 SHELL32_GUIDToStringW(CLSID_MyComputer, &pszPath[2]);
513 }
514 else if (_ILIsPidlSimple(pidl))
515 {
516 /* take names of special folders only if its only this folder */
517 if (_ILIsSpecialFolder(pidl))
518 {
519 GUID const *clsid;
520
521 clsid = _ILGetGUIDPointer (pidl);
522 if (clsid)
523 {
524 if (GET_SHGDN_FOR (dwFlags) & SHGDN_FORPARSING)
525 {
526 static const WCHAR clsidW[] = L"CLSID\\";
527 static const WCHAR shellfolderW[] = L"\\shellfolder";
528 static const WCHAR wantsForParsingW[] = L"WantsForParsing";
529 BOOL bWantsForParsing = FALSE;
530 WCHAR szRegPath[100];
531 LONG r;
532
533 /*
534 * We can only get a filesystem path from a shellfolder
535 * if the value WantsFORPARSING exists in
536 * CLSID\\{...}\\shellfolder
537 * exception: the MyComputer folder has this keys not
538 * but like any filesystem backed
539 * folder it needs these behaviour
540 *
541 * Get the "WantsFORPARSING" flag from the registry
542 */
543
544 wcscpy(szRegPath, clsidW);
545 SHELL32_GUIDToStringW(*clsid, &szRegPath[6]);
546 wcscat(szRegPath, shellfolderW);
547 r = SHGetValueW(HKEY_CLASSES_ROOT, szRegPath,
548 wantsForParsingW, NULL, NULL, NULL);
549 if (r == ERROR_SUCCESS)
550 bWantsForParsing = TRUE;
551
552 if ((GET_SHGDN_RELATION (dwFlags) == SHGDN_NORMAL) &&
553 bWantsForParsing)
554 {
555 /*
556 * We need the filesystem path to the destination folder
557 * Only the folder itself can know it
558 */
559 hr = SHELL32_GetDisplayNameOfChild (this, pidl,
560 dwFlags, pszPath, MAX_PATH);
561 }
562 else
563 {
564 LPWSTR p = pszPath;
565
566 /* parsing name like ::{...} */
567 p[0] = ':';
568 p[1] = ':';
569 p += 2;
570 p += SHELL32_GUIDToStringW(CLSID_MyComputer, p);
571
572 /* \:: */
573 p[0] = '\\';
574 p[1] = ':';
575 p[2] = ':';
576 p += 3;
577 SHELL32_GUIDToStringW(*clsid, p);
578 }
579 }
580 else
581 {
582 /* user friendly name */
583
584 if (_ILIsMyComputer(pidl) && sName)
585 wcscpy(pszPath, sName);
586 else
587 HCR_GetClassNameW (*clsid, pszPath, MAX_PATH);
588
589 TRACE("pszPath %s\n", debugstr_w(pszPath));
590 }
591 }
592 else
593 {
594 /* append my own path */
595 _ILSimpleGetTextW(pidl, pszPath, MAX_PATH);
596 }
597 }
598 else if (_ILIsDrive(pidl))
599 {
600
601 _ILSimpleGetTextW(pidl, pszPath, MAX_PATH); /* append my own path */
602 /* long view "lw_name (C:)" */
603 if (!(dwFlags & SHGDN_FORPARSING))
604 {
605 WCHAR wszDrive[18] = {0};
606 DWORD dwVolumeSerialNumber, dwMaximumComponentLength, dwFileSystemFlags;
607 static const WCHAR wszOpenBracket[] = {' ', '(', 0};
608 static const WCHAR wszCloseBracket[] = {')', 0};
609
610 lstrcpynW(wszDrive, pszPath, 4);
611 pszPath[0] = L'\0';
612 GetVolumeInformationW(wszDrive, pszPath,
613 MAX_PATH - 7,
614 &dwVolumeSerialNumber,
615 &dwMaximumComponentLength, &dwFileSystemFlags, NULL, 0);
616 pszPath[MAX_PATH-1] = L'\0';
617 if (!wcslen(pszPath))
618 {
619 UINT DriveType, ResourceId;
620 DriveType = GetDriveTypeW(wszDrive);
621 switch(DriveType)
622 {
623 case DRIVE_FIXED:
624 ResourceId = IDS_DRIVE_FIXED;
625 break;
626 case DRIVE_REMOTE:
627 ResourceId = IDS_DRIVE_NETWORK;
628 break;
629 case DRIVE_CDROM:
630 ResourceId = IDS_DRIVE_CDROM;
631 break;
632 default:
633 ResourceId = 0;
634 }
635 if (ResourceId)
636 {
637 dwFileSystemFlags = LoadStringW(shell32_hInstance, ResourceId, pszPath, MAX_PATH);
638 if (dwFileSystemFlags > MAX_PATH - 7)
639 pszPath[MAX_PATH-7] = L'\0';
640 }
641 }
642 wcscat (pszPath, wszOpenBracket);
643 wszDrive[2] = L'\0';
644 wcscat (pszPath, wszDrive);
645 wcscat (pszPath, wszCloseBracket);
646 }
647 }
648 else
649 {
650 /* Neither a shell namespace extension nor a drive letter. */
651 ERR("Wrong pidl type\n");
652 CoTaskMemFree(pszPath);
653 return E_INVALIDARG;
654 }
655 }
656 else
657 {
658 /* Complex pidl. Let the child folder do the work */
659 hr = SHELL32_GetDisplayNameOfChild(this, pidl, dwFlags, pszPath, MAX_PATH);
660 }
661
662 if (SUCCEEDED(hr))
663 {
664 strRet->uType = STRRET_WSTR;
665 strRet->pOleStr = pszPath;
666 }
667 else
668 CoTaskMemFree(pszPath);
669
670 TRACE("-- (%p)->(%s)\n", this, strRet->uType == STRRET_CSTR ? strRet->cStr : debugstr_w(strRet->pOleStr));
671 return hr;
672 }
673
674 /**************************************************************************
675 * CDrivesFolder::SetNameOf
676 * Changes the name of a file object or subfolder, possibly changing its item
677 * identifier in the process.
678 *
679 * PARAMETERS
680 * hwndOwner [in] Owner window for output
681 * pidl [in] simple pidl of item to change
682 * lpszName [in] the items new display name
683 * dwFlags [in] SHGNO formatting flags
684 * ppidlOut [out] simple pidl returned
685 */
686 HRESULT WINAPI CDrivesFolder::SetNameOf(HWND hwndOwner, LPCITEMIDLIST pidl,
687 LPCOLESTR lpName, DWORD dwFlags, LPITEMIDLIST *pPidlOut)
688 {
689 LPWSTR sName;
690 HKEY hKey;
691 UINT length;
692 WCHAR szName[30];
693
694 TRACE("(%p)->(%p,pidl=%p,%s,%u,%p)\n", this,
695 hwndOwner, pidl, debugstr_w (lpName), dwFlags, pPidlOut);
696
697 if (_ILIsDrive(pidl))
698 {
699 if (_ILSimpleGetTextW(pidl, szName, _countof(szName)))
700 SetVolumeLabelW(szName, lpName);
701 if (pPidlOut)
702 *pPidlOut = _ILCreateDrive(szName);
703 return S_OK;
704 }
705
706
707 if (pPidlOut != NULL)
708 *pPidlOut = _ILCreateMyComputer();
709
710 length = (wcslen(lpName) + 1) * sizeof(WCHAR);
711 sName = (LPWSTR)SHAlloc(length);
712
713 if (!sName)
714 return E_OUTOFMEMORY;
715
716 if (RegOpenKeyExW(HKEY_CURRENT_USER,
717 L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CLSID\\{20D04FE0-3AEA-1069-A2D8-08002B30309D}",
718 0,
719 KEY_WRITE,
720 &hKey) != ERROR_SUCCESS)
721 {
722 WARN("Error: failed to open registry key\n");
723 }
724 else
725 {
726 RegSetValueExW(hKey, NULL, 0, REG_SZ, (const LPBYTE)lpName, length);
727 RegCloseKey(hKey);
728 }
729
730 wcscpy(sName, lpName);
731 SHFree(this->sName);
732 this->sName = sName;
733 TRACE("result %s\n", debugstr_w(sName));
734 return S_OK;
735 }
736
737 HRESULT WINAPI CDrivesFolder::GetDefaultSearchGUID(GUID * pguid)
738 {
739 FIXME ("(%p)\n", this);
740 return E_NOTIMPL;
741 }
742
743 HRESULT WINAPI CDrivesFolder::EnumSearches(IEnumExtraSearch ** ppenum)
744 {
745 FIXME ("(%p)\n", this);
746 return E_NOTIMPL;
747 }
748
749 HRESULT WINAPI CDrivesFolder::GetDefaultColumn (DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
750 {
751 TRACE ("(%p)\n", this);
752
753 if (pSort)
754 *pSort = 0;
755 if (pDisplay)
756 *pDisplay = 0;
757 return S_OK;
758 }
759
760 HRESULT WINAPI CDrivesFolder::GetDefaultColumnState(UINT iColumn, DWORD * pcsFlags)
761 {
762 TRACE ("(%p)\n", this);
763
764 if (!pcsFlags || iColumn >= MYCOMPUTERSHELLVIEWCOLUMNS)
765 return E_INVALIDARG;
766 *pcsFlags = MyComputerSFHeader[iColumn].pcsFlags;
767 return S_OK;
768 }
769
770 HRESULT WINAPI CDrivesFolder::GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID * pscid, VARIANT * pv)
771 {
772 FIXME ("(%p)\n", this);
773 return E_NOTIMPL;
774 }
775
776 /* FIXME: drive size >4GB is rolling over */
777 HRESULT WINAPI CDrivesFolder::GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *psd)
778 {
779 HRESULT hr;
780
781 TRACE ("(%p)->(%p %i %p)\n", this, pidl, iColumn, psd);
782
783 if (!psd || iColumn >= MYCOMPUTERSHELLVIEWCOLUMNS)
784 return E_INVALIDARG;
785
786 if (!pidl)
787 {
788 psd->fmt = MyComputerSFHeader[iColumn].fmt;
789 psd->cxChar = MyComputerSFHeader[iColumn].cxChar;
790 psd->str.uType = STRRET_CSTR;
791 LoadStringA(shell32_hInstance, MyComputerSFHeader[iColumn].colnameid,
792 psd->str.cStr, MAX_PATH);
793 return S_OK;
794 }
795 else
796 {
797 char szPath[MAX_PATH];
798 ULARGE_INTEGER ulBytes;
799
800 psd->str.cStr[0] = 0x00;
801 psd->str.uType = STRRET_CSTR;
802 switch (iColumn)
803 {
804 case 0: /* name */
805 hr = GetDisplayNameOf(pidl,
806 SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str);
807 break;
808 case 1: /* type */
809 _ILGetFileType(pidl, psd->str.cStr, MAX_PATH);
810 break;
811 case 2: /* total size */
812 if (_ILIsDrive(pidl))
813 {
814 _ILSimpleGetText (pidl, szPath, MAX_PATH);
815 GetDiskFreeSpaceExA (szPath, NULL, &ulBytes, NULL);
816 StrFormatByteSizeA (ulBytes.LowPart, psd->str.cStr, MAX_PATH);
817 }
818 break;
819 case 3: /* free size */
820 if (_ILIsDrive(pidl))
821 {
822 _ILSimpleGetText (pidl, szPath, MAX_PATH);
823 GetDiskFreeSpaceExA (szPath, &ulBytes, NULL, NULL);
824 StrFormatByteSizeA (ulBytes.LowPart, psd->str.cStr, MAX_PATH);
825 }
826 break;
827 }
828 hr = S_OK;
829 }
830
831 return hr;
832 }
833
834 HRESULT WINAPI CDrivesFolder::MapColumnToSCID(UINT column, SHCOLUMNID * pscid)
835 {
836 FIXME("(%p)\n", this);
837 return E_NOTIMPL;
838 }
839
840 /************************************************************************
841 * CDrivesFolder::GetClassID
842 */
843 HRESULT WINAPI CDrivesFolder::GetClassID(CLSID *lpClassId)
844 {
845 TRACE ("(%p)\n", this);
846
847 if (!lpClassId)
848 return E_POINTER;
849
850 *lpClassId = CLSID_MyComputer;
851 return S_OK;
852 }
853
854 /************************************************************************
855 * CDrivesFolder::Initialize
856 *
857 * NOTES: it makes no sense to change the pidl
858 */
859 HRESULT WINAPI CDrivesFolder::Initialize(LPCITEMIDLIST pidl)
860 {
861 TRACE ("(%p)->(%p)\n", this, pidl);
862
863 if (pidlRoot)
864 SHFree((LPVOID)pidlRoot);
865
866 pidlRoot = ILClone(pidl);
867 return S_OK;
868 }
869
870 /**************************************************************************
871 * CDrivesFolder::GetCurFolder
872 */
873 HRESULT WINAPI CDrivesFolder::GetCurFolder(LPITEMIDLIST *pidl)
874 {
875 TRACE("(%p)->(%p)\n", this, pidl);
876
877 if (!pidl)
878 return E_POINTER;
879
880 *pidl = ILClone(pidlRoot);
881 return S_OK;
882 }