user32: Add wsprintfW %C tests.
[wine.git] / dlls / shell32 / shfldr_mycomp.c
blob6a31e8ce1e6966daf7e84d6dfd5dbab1c60f13b6
1 /*
2 * Virtual Workplace folder
4 * Copyright 1997 Marcus Meissner
5 * Copyright 1998, 1999, 2002 Juergen Schmied
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.
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.
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
22 #include "config.h"
23 #include "wine/port.h"
25 #include <stdlib.h>
26 #include <string.h>
27 #include <stdarg.h>
28 #include <stdio.h>
30 #define COBJMACROS
31 #define NONAMELESSUNION
33 #include "winerror.h"
34 #include "windef.h"
35 #include "winbase.h"
36 #include "winreg.h"
38 #include "wingdi.h"
39 #include "pidl.h"
40 #include "shlguid.h"
41 #include "undocshell.h"
42 #include "shell32_main.h"
43 #include "shresdef.h"
44 #include "shlwapi.h"
45 #include "wine/debug.h"
46 #include "debughlp.h"
47 #include "shfldr.h"
49 WINE_DEFAULT_DEBUG_CHANNEL (shell);
51 /***********************************************************************
52 * IShellFolder implementation
55 typedef struct {
56 IShellFolder2 IShellFolder2_iface;
57 IPersistFolder2 IPersistFolder2_iface;
58 LONG ref;
60 /* both paths are parsible from the desktop */
61 LPITEMIDLIST pidlRoot; /* absolute pidl */
62 } IMyComputerFolderImpl;
64 static const IShellFolder2Vtbl vt_ShellFolder2;
65 static const IPersistFolder2Vtbl vt_PersistFolder2;
67 static inline IMyComputerFolderImpl *impl_from_IShellFolder2(IShellFolder2 *iface)
69 return CONTAINING_RECORD(iface, IMyComputerFolderImpl, IShellFolder2_iface);
72 static inline IMyComputerFolderImpl *impl_from_IPersistFolder2(IPersistFolder2 *iface)
74 return CONTAINING_RECORD(iface, IMyComputerFolderImpl, IPersistFolder2_iface);
78 /***********************************************************************
79 * IShellFolder [MyComputer] implementation
82 static const shvheader mycomputer_header[] =
84 { &FMTID_Storage, PID_STG_NAME, IDS_SHV_COLUMN1, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15 },
85 { &FMTID_Storage, PID_STG_STORAGETYPE, IDS_SHV_COLUMN3, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10 },
86 { NULL, 0, IDS_SHV_COLUMN6, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10 },
87 { NULL, 0, IDS_SHV_COLUMN7, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10 },
90 /**************************************************************************
91 * ISF_MyComputer_Constructor
93 HRESULT WINAPI ISF_MyComputer_Constructor (IUnknown * pUnkOuter, REFIID riid, LPVOID * ppv)
95 IMyComputerFolderImpl *sf;
97 TRACE ("unkOut=%p %s\n", pUnkOuter, shdebugstr_guid (riid));
99 if (!ppv)
100 return E_POINTER;
101 if (pUnkOuter)
102 return CLASS_E_NOAGGREGATION;
104 sf = LocalAlloc (LMEM_ZEROINIT, sizeof (IMyComputerFolderImpl));
105 if (!sf)
106 return E_OUTOFMEMORY;
108 sf->ref = 0;
109 sf->IShellFolder2_iface.lpVtbl = &vt_ShellFolder2;
110 sf->IPersistFolder2_iface.lpVtbl = &vt_PersistFolder2;
111 sf->pidlRoot = _ILCreateMyComputer (); /* my qualified pidl */
113 if (FAILED (IShellFolder2_QueryInterface (&sf->IShellFolder2_iface, riid, ppv)))
115 IShellFolder2_Release (&sf->IShellFolder2_iface);
116 return E_NOINTERFACE;
119 TRACE ("--(%p)\n", sf);
120 return S_OK;
123 /**************************************************************************
124 * ISF_MyComputer_fnQueryInterface
126 * NOTES supports not IPersist/IPersistFolder
128 static HRESULT WINAPI ISF_MyComputer_fnQueryInterface (IShellFolder2 *iface,
129 REFIID riid, LPVOID *ppvObj)
131 IMyComputerFolderImpl *This = impl_from_IShellFolder2(iface);
133 TRACE ("(%p)->(%s,%p)\n", This, shdebugstr_guid (riid), ppvObj);
135 *ppvObj = NULL;
137 if (IsEqualIID (riid, &IID_IUnknown) ||
138 IsEqualIID (riid, &IID_IShellFolder) ||
139 IsEqualIID (riid, &IID_IShellFolder2))
141 *ppvObj = &This->IShellFolder2_iface;
143 else if (IsEqualIID (riid, &IID_IPersist) ||
144 IsEqualIID (riid, &IID_IPersistFolder) ||
145 IsEqualIID (riid, &IID_IPersistFolder2))
147 *ppvObj = &This->IPersistFolder2_iface;
150 if (*ppvObj)
152 IUnknown_AddRef ((IUnknown *) (*ppvObj));
153 TRACE ("-- Interface: (%p)->(%p)\n", ppvObj, *ppvObj);
154 return S_OK;
156 TRACE ("-- Interface: E_NOINTERFACE\n");
157 return E_NOINTERFACE;
160 static ULONG WINAPI ISF_MyComputer_fnAddRef (IShellFolder2 * iface)
162 IMyComputerFolderImpl *This = impl_from_IShellFolder2(iface);
163 ULONG refCount = InterlockedIncrement(&This->ref);
165 TRACE ("(%p)->(count=%u)\n", This, refCount - 1);
167 return refCount;
170 static ULONG WINAPI ISF_MyComputer_fnRelease (IShellFolder2 * iface)
172 IMyComputerFolderImpl *This = impl_from_IShellFolder2(iface);
173 ULONG refCount = InterlockedDecrement(&This->ref);
175 TRACE ("(%p)->(count=%u)\n", This, refCount + 1);
177 if (!refCount)
179 TRACE ("-- destroying IShellFolder(%p)\n", This);
180 SHFree (This->pidlRoot);
181 LocalFree (This);
183 return refCount;
186 /**************************************************************************
187 * ISF_MyComputer_fnParseDisplayName
189 static HRESULT WINAPI ISF_MyComputer_fnParseDisplayName (IShellFolder2 *iface,
190 HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName,
191 DWORD * pchEaten, LPITEMIDLIST * ppidl, DWORD * pdwAttributes)
193 IMyComputerFolderImpl *This = impl_from_IShellFolder2(iface);
194 HRESULT hr = E_INVALIDARG;
195 LPCWSTR szNext = NULL;
196 WCHAR szElement[MAX_PATH];
197 LPITEMIDLIST pidlTemp = NULL;
198 CLSID clsid;
200 TRACE("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n", This,
201 hwndOwner, pbc, lpszDisplayName, debugstr_w (lpszDisplayName),
202 pchEaten, ppidl, pdwAttributes);
204 *ppidl = 0;
205 if (pchEaten)
206 *pchEaten = 0; /* strange but like the original */
208 /* handle CLSID paths */
209 if (lpszDisplayName[0] == ':' && lpszDisplayName[1] == ':')
211 szNext = GetNextElementW (lpszDisplayName, szElement, MAX_PATH);
212 TRACE ("-- element: %s\n", debugstr_w (szElement));
213 SHCLSIDFromStringW (szElement + 2, &clsid);
214 pidlTemp = _ILCreateGuid (PT_GUID, &clsid);
216 /* do we have an absolute path name ? */
217 else if (PathGetDriveNumberW (lpszDisplayName) >= 0 &&
218 lpszDisplayName[2] == (WCHAR) '\\')
220 szNext = GetNextElementW (lpszDisplayName, szElement, MAX_PATH);
221 /* make drive letter uppercase to enable PIDL comparison */
222 szElement[0] = toupper(szElement[0]);
223 pidlTemp = _ILCreateDrive (szElement);
226 if (szNext && *szNext)
228 hr = SHELL32_ParseNextElement (iface, hwndOwner, pbc, &pidlTemp,
229 (LPOLESTR) szNext, pchEaten, pdwAttributes);
231 else
233 if (pdwAttributes && *pdwAttributes)
234 SHELL32_GetItemAttributes (&This->IShellFolder2_iface, pidlTemp, pdwAttributes);
235 hr = S_OK;
238 *ppidl = pidlTemp;
240 TRACE ("(%p)->(-- ret=0x%08x)\n", This, hr);
242 return hr;
245 /* retrieve a map of drives that should be displayed */
246 static DWORD get_drive_map(void)
248 static const WCHAR policiesW[] = {'S','o','f','t','w','a','r','e','\\',
249 'M','i','c','r','o','s','o','f','t','\\',
250 'W','i','n','d','o','w','s','\\',
251 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
252 'P','o','l','i','c','i','e','s','\\',
253 'E','x','p','l','o','r','e','r',0};
254 static const WCHAR nodrivesW[] = {'N','o','D','r','i','v','e','s',0};
255 static DWORD drive_mask;
256 static BOOL init_done = FALSE;
258 if (!init_done)
260 DWORD type, size, data, mask = 0;
261 HKEY hkey;
263 if (!RegOpenKeyW( HKEY_LOCAL_MACHINE, policiesW, &hkey ))
265 size = sizeof(data);
266 if (!RegQueryValueExW( hkey, nodrivesW, NULL, &type, (LPBYTE)&data, &size ) && type == REG_DWORD)
267 mask |= data;
268 RegCloseKey( hkey );
270 if (!RegOpenKeyW( HKEY_CURRENT_USER, policiesW, &hkey ))
272 size = sizeof(data);
273 if (!RegQueryValueExW( hkey, nodrivesW, NULL, &type, (LPBYTE)&data, &size ) && type == REG_DWORD)
274 mask |= data;
275 RegCloseKey( hkey );
277 drive_mask = mask;
278 init_done = TRUE;
281 return GetLogicalDrives() & ~drive_mask;
284 /**************************************************************************
285 * CreateMyCompEnumList()
287 static const WCHAR MyComputer_NameSpaceW[] = { 'S','O','F','T','W','A','R','E',
288 '\\','M','i','c','r','o','s','o','f','t','\\','W','i','n','d','o','w','s','\\',
289 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\','E','x','p','l',
290 'o','r','e','r','\\','M','y','C','o','m','p','u','t','e','r','\\','N','a','m',
291 'e','s','p','a','c','e','\0' };
293 static BOOL CreateMyCompEnumList(IEnumIDListImpl *list, DWORD dwFlags)
295 BOOL ret = TRUE;
297 TRACE("(%p)->(flags=0x%08x)\n", list, dwFlags);
299 /* enumerate the folders */
300 if (dwFlags & SHCONTF_FOLDERS)
302 WCHAR wszDriveName[] = {'A', ':', '\\', '\0'};
303 DWORD dwDrivemap = get_drive_map();
304 HKEY hkey;
305 UINT i;
307 while (ret && wszDriveName[0]<='Z')
309 if(dwDrivemap & 0x00000001L)
310 ret = AddToEnumList(list, _ILCreateDrive(wszDriveName));
311 wszDriveName[0]++;
312 dwDrivemap = dwDrivemap >> 1;
315 TRACE("-- (%p)-> enumerate (mycomputer shell extensions)\n",list);
316 for (i=0; i<2; i++) {
317 if (ret && !RegOpenKeyExW(i == 0 ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER,
318 MyComputer_NameSpaceW, 0, KEY_READ, &hkey))
320 WCHAR iid[50];
321 int i=0;
323 while (ret)
325 DWORD size;
326 LONG r;
328 size = ARRAY_SIZE(iid);
329 r = RegEnumKeyExW(hkey, i, iid, &size, 0, NULL, NULL, NULL);
330 if (ERROR_SUCCESS == r)
332 /* FIXME: shell extensions, shouldn't the type be
333 * PT_SHELLEXT? */
334 ret = AddToEnumList(list, _ILCreateGuidFromStrW(iid));
335 i++;
337 else if (ERROR_NO_MORE_ITEMS == r)
338 break;
339 else
340 ret = FALSE;
342 RegCloseKey(hkey);
346 return ret;
349 /**************************************************************************
350 * ISF_MyComputer_fnEnumObjects
352 static HRESULT WINAPI ISF_MyComputer_fnEnumObjects (IShellFolder2 *iface,
353 HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList)
355 IMyComputerFolderImpl *This = impl_from_IShellFolder2(iface);
356 IEnumIDListImpl *list;
358 TRACE("(%p)->(HWND=%p flags=0x%08x pplist=%p)\n", This,
359 hwndOwner, dwFlags, ppEnumIDList);
361 if (!(list = IEnumIDList_Constructor()))
362 return E_OUTOFMEMORY;
363 CreateMyCompEnumList(list, dwFlags);
364 *ppEnumIDList = &list->IEnumIDList_iface;
366 TRACE ("-- (%p)->(new ID List: %p)\n", This, *ppEnumIDList);
368 return S_OK;
371 /**************************************************************************
372 * ISF_MyComputer_fnBindToObject
374 static HRESULT WINAPI ISF_MyComputer_fnBindToObject (IShellFolder2 *iface,
375 LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
377 IMyComputerFolderImpl *This = impl_from_IShellFolder2(iface);
379 TRACE("(%p)->(pidl=%p,%p,%s,%p)\n", This,
380 pidl, pbcReserved, shdebugstr_guid (riid), ppvOut);
382 return SHELL32_BindToChild (This->pidlRoot, NULL, pidl, riid, ppvOut);
385 /**************************************************************************
386 * ISF_MyComputer_fnBindToStorage
388 static HRESULT WINAPI ISF_MyComputer_fnBindToStorage (IShellFolder2 * iface,
389 LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
391 IMyComputerFolderImpl *This = impl_from_IShellFolder2(iface);
393 FIXME("(%p)->(pidl=%p,%p,%s,%p) stub\n", This,
394 pidl, pbcReserved, shdebugstr_guid (riid), ppvOut);
396 *ppvOut = NULL;
397 return E_NOTIMPL;
400 /**************************************************************************
401 * ISF_MyComputer_fnCompareIDs
404 static HRESULT WINAPI ISF_MyComputer_fnCompareIDs (IShellFolder2 *iface,
405 LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
407 IMyComputerFolderImpl *This = impl_from_IShellFolder2(iface);
408 HRESULT hr;
410 TRACE ("(%p)->(0x%08lx,pidl1=%p,pidl2=%p)\n", This, lParam, pidl1, pidl2);
411 hr = SHELL32_CompareIDs(&This->IShellFolder2_iface, lParam, pidl1, pidl2);
412 TRACE ("-- 0x%08x\n", hr);
413 return hr;
416 /**************************************************************************
417 * ISF_MyComputer_fnCreateViewObject
419 static HRESULT WINAPI ISF_MyComputer_fnCreateViewObject (IShellFolder2 *iface,
420 HWND hwndOwner, REFIID riid, LPVOID * ppvOut)
422 IMyComputerFolderImpl *This = impl_from_IShellFolder2(iface);
423 LPSHELLVIEW pShellView;
424 HRESULT hr = E_INVALIDARG;
426 TRACE("(%p)->(hwnd=%p,%s,%p)\n", This,
427 hwndOwner, shdebugstr_guid (riid), ppvOut);
429 if (!ppvOut)
430 return hr;
432 *ppvOut = NULL;
434 if (IsEqualIID (riid, &IID_IDropTarget))
436 WARN ("IDropTarget not implemented\n");
437 hr = E_NOTIMPL;
439 else if (IsEqualIID (riid, &IID_IContextMenu))
441 WARN ("IContextMenu not implemented\n");
442 hr = E_NOTIMPL;
444 else if (IsEqualIID (riid, &IID_IShellView))
446 pShellView = IShellView_Constructor ((IShellFolder *) iface);
447 if (pShellView)
449 hr = IShellView_QueryInterface (pShellView, riid, ppvOut);
450 IShellView_Release (pShellView);
453 TRACE ("-- (%p)->(interface=%p)\n", This, ppvOut);
454 return hr;
457 /**************************************************************************
458 * ISF_MyComputer_fnGetAttributesOf
460 static HRESULT WINAPI ISF_MyComputer_fnGetAttributesOf (IShellFolder2 * iface,
461 UINT cidl, LPCITEMIDLIST * apidl, DWORD * rgfInOut)
463 IMyComputerFolderImpl *This = impl_from_IShellFolder2(iface);
464 HRESULT hr = S_OK;
466 TRACE ("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n",
467 This, cidl, apidl, rgfInOut, rgfInOut ? *rgfInOut : 0);
469 if (!rgfInOut)
470 return E_INVALIDARG;
471 if (cidl && !apidl)
472 return E_INVALIDARG;
474 if (*rgfInOut == 0)
475 *rgfInOut = ~0;
477 if(cidl == 0){
478 IShellFolder2 *parent = NULL;
479 LPCITEMIDLIST rpidl = NULL;
481 hr = SHBindToParent(This->pidlRoot, &IID_IShellFolder2, (void **)&parent, &rpidl);
482 if(SUCCEEDED(hr)) {
483 SHELL32_GetItemAttributes(parent, rpidl, rgfInOut);
484 IShellFolder2_Release(parent);
486 } else {
487 while (cidl > 0 && *apidl) {
488 pdump (*apidl);
489 SHELL32_GetItemAttributes(&This->IShellFolder2_iface, *apidl, rgfInOut);
490 apidl++;
491 cidl--;
494 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
495 *rgfInOut &= ~SFGAO_VALIDATE;
497 TRACE ("-- result=0x%08x\n", *rgfInOut);
498 return hr;
501 /**************************************************************************
502 * ISF_MyComputer_fnGetUIObjectOf
504 * PARAMETERS
505 * hwndOwner [in] Parent window for any output
506 * cidl [in] array size
507 * apidl [in] simple pidl array
508 * riid [in] Requested Interface
509 * prgfInOut [ ] reserved
510 * ppvObject [out] Resulting Interface
513 static HRESULT WINAPI ISF_MyComputer_fnGetUIObjectOf (IShellFolder2 * iface,
514 HWND hwndOwner, UINT cidl, LPCITEMIDLIST * apidl, REFIID riid,
515 UINT * prgfInOut, LPVOID * ppvOut)
517 IMyComputerFolderImpl *This = impl_from_IShellFolder2(iface);
519 LPITEMIDLIST pidl;
520 IUnknown *pObj = NULL;
521 HRESULT hr = E_INVALIDARG;
523 TRACE("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n", This,
524 hwndOwner, cidl, apidl, shdebugstr_guid (riid), prgfInOut, ppvOut);
526 if (!ppvOut)
527 return hr;
529 *ppvOut = NULL;
531 if (IsEqualIID (riid, &IID_IContextMenu) && (cidl >= 1))
533 return ItemMenu_Constructor((IShellFolder*) iface, This->pidlRoot, apidl, cidl, riid, ppvOut);
535 else if (IsEqualIID (riid, &IID_IDataObject) && (cidl >= 1))
537 pObj = (LPUNKNOWN) IDataObject_Constructor (hwndOwner,
538 This->pidlRoot, apidl, cidl);
539 hr = S_OK;
541 else if (IsEqualIID (riid, &IID_IExtractIconA) && (cidl == 1))
543 pidl = ILCombine (This->pidlRoot, apidl[0]);
544 pObj = (LPUNKNOWN) IExtractIconA_Constructor (pidl);
545 SHFree (pidl);
546 hr = S_OK;
548 else if (IsEqualIID (riid, &IID_IExtractIconW) && (cidl == 1))
550 pidl = ILCombine (This->pidlRoot, apidl[0]);
551 pObj = (LPUNKNOWN) IExtractIconW_Constructor (pidl);
552 SHFree (pidl);
553 hr = S_OK;
555 else if (IsEqualIID (riid, &IID_IDropTarget) && (cidl >= 1))
557 hr = IShellFolder2_QueryInterface (iface, &IID_IDropTarget,
558 (LPVOID *) &pObj);
560 else if ((IsEqualIID(riid,&IID_IShellLinkW) ||
561 IsEqualIID(riid,&IID_IShellLinkA)) && (cidl == 1))
563 pidl = ILCombine (This->pidlRoot, apidl[0]);
564 hr = IShellLink_ConstructFromFile(NULL, riid, pidl, &pObj);
565 SHFree (pidl);
567 else
568 hr = E_NOINTERFACE;
570 if (SUCCEEDED(hr) && !pObj)
571 hr = E_OUTOFMEMORY;
573 *ppvOut = pObj;
574 TRACE ("(%p)->hr=0x%08x\n", This, hr);
575 return hr;
578 /**************************************************************************
579 * ISF_MyComputer_fnGetDisplayNameOf
581 static HRESULT WINAPI ISF_MyComputer_fnGetDisplayNameOf (IShellFolder2 *iface,
582 LPCITEMIDLIST pidl, DWORD dwFlags, LPSTRRET strRet)
584 IMyComputerFolderImpl *This = impl_from_IShellFolder2(iface);
586 LPWSTR pszPath;
587 HRESULT hr = S_OK;
589 TRACE ("(%p)->(pidl=%p,0x%08x,%p)\n", This, pidl, dwFlags, strRet);
590 pdump (pidl);
592 if (!strRet)
593 return E_INVALIDARG;
595 pszPath = CoTaskMemAlloc((MAX_PATH +1) * sizeof(WCHAR));
596 if (!pszPath)
597 return E_OUTOFMEMORY;
599 pszPath[0] = 0;
601 if (!pidl->mkid.cb)
603 /* parsing name like ::{...} */
604 pszPath[0] = ':';
605 pszPath[1] = ':';
606 SHELL32_GUIDToStringW(&CLSID_MyComputer, &pszPath[2]);
608 else if (_ILIsPidlSimple(pidl))
610 /* take names of special folders only if its only this folder */
611 if (_ILIsSpecialFolder(pidl))
613 GUID const *clsid;
615 clsid = _ILGetGUIDPointer (pidl);
616 if (clsid)
618 if ((GET_SHGDN_FOR (dwFlags) & (SHGDN_FORPARSING | SHGDN_FORADDRESSBAR)) == SHGDN_FORPARSING)
620 static const WCHAR clsidW[] =
621 { 'C','L','S','I','D','\\',0 };
622 static const WCHAR shellfolderW[] =
623 { '\\','s','h','e','l','l','f','o','l','d','e','r',0 };
624 static const WCHAR wantsForParsingW[] =
625 { 'W','a','n','t','s','F','o','r','P','a','r','s','i','n',
626 'g',0 };
627 BOOL bWantsForParsing = FALSE;
628 WCHAR szRegPath[100];
629 LONG r;
632 * We can only get a filesystem path from a shellfolder
633 * if the value WantsFORPARSING exists in
634 * CLSID\\{...}\\shellfolder
635 * exception: the MyComputer folder has this keys not
636 * but like any filesystem backed
637 * folder it needs these behaviour
639 * Get the "WantsFORPARSING" flag from the registry
642 lstrcpyW (szRegPath, clsidW);
643 SHELL32_GUIDToStringW (clsid, &szRegPath[6]);
644 lstrcatW (szRegPath, shellfolderW);
645 r = SHGetValueW (HKEY_CLASSES_ROOT, szRegPath,
646 wantsForParsingW, NULL, NULL, NULL);
647 if (r == ERROR_SUCCESS)
648 bWantsForParsing = TRUE;
650 if ((GET_SHGDN_RELATION (dwFlags) == SHGDN_NORMAL) &&
651 bWantsForParsing)
654 * We need the filesystem path to the destination folder
655 * Only the folder itself can know it
657 hr = SHELL32_GetDisplayNameOfChild (iface, pidl,
658 dwFlags, pszPath, MAX_PATH);
660 else
662 LPWSTR p = pszPath;
664 /* parsing name like ::{...} */
665 p[0] = ':';
666 p[1] = ':';
667 p += 2;
668 p += SHELL32_GUIDToStringW(&CLSID_MyComputer, p);
670 /* \:: */
671 p[0] = '\\';
672 p[1] = ':';
673 p[2] = ':';
674 p += 3;
675 SHELL32_GUIDToStringW(clsid, p);
678 else
680 /* user friendly name */
681 HCR_GetClassNameW (clsid, pszPath, MAX_PATH);
684 else
686 /* append my own path */
687 _ILSimpleGetTextW (pidl, pszPath, MAX_PATH);
690 else if (_ILIsDrive(pidl))
692 _ILSimpleGetTextW (pidl, pszPath, MAX_PATH); /* append my own path */
694 /* long view "lw_name (C:)" */
695 if (!(dwFlags & SHGDN_FORPARSING))
697 static const WCHAR wszOpenBracket[] = {' ','(',0};
698 static const WCHAR wszCloseBracket[] = {')',0};
699 WCHAR wszDrive[32 /* label */ + 6 /* ' (C:)'\0 */] = {0};
701 GetVolumeInformationW (pszPath, wszDrive, ARRAY_SIZE(wszDrive) - 5, NULL, NULL,
702 NULL, NULL, 0);
703 strcatW (wszDrive, wszOpenBracket);
704 lstrcpynW (wszDrive + strlenW(wszDrive), pszPath, 3);
705 strcatW (wszDrive, wszCloseBracket);
706 strcpyW (pszPath, wszDrive);
709 else
711 /* Neither a shell namespace extension nor a drive letter. */
712 ERR("Wrong pidl type\n");
713 CoTaskMemFree(pszPath);
714 return E_INVALIDARG;
717 else
719 /* Complex pidl. Let the child folder do the work */
720 hr = SHELL32_GetDisplayNameOfChild(iface, pidl, dwFlags, pszPath, MAX_PATH);
723 if (SUCCEEDED (hr))
725 /* Win9x always returns ANSI strings, NT always returns Unicode strings */
726 if (GetVersion() & 0x80000000)
728 strRet->uType = STRRET_CSTR;
729 if (!WideCharToMultiByte(CP_ACP, 0, pszPath, -1, strRet->u.cStr, MAX_PATH,
730 NULL, NULL))
731 strRet->u.cStr[0] = '\0';
732 CoTaskMemFree(pszPath);
734 else
736 strRet->uType = STRRET_WSTR;
737 strRet->u.pOleStr = pszPath;
740 else
741 CoTaskMemFree(pszPath);
743 TRACE ("-- (%p)->(%s)\n", This, strRet->uType == STRRET_CSTR ? strRet->u.cStr : debugstr_w(strRet->u.pOleStr));
744 return hr;
747 /**************************************************************************
748 * ISF_MyComputer_fnSetNameOf
749 * Changes the name of a file object or subfolder, possibly changing its item
750 * identifier in the process.
752 * PARAMETERS
753 * hwndOwner [in] Owner window for output
754 * pidl [in] simple pidl of item to change
755 * lpszName [in] the items new display name
756 * dwFlags [in] SHGNO formatting flags
757 * ppidlOut [out] simple pidl returned
759 static HRESULT WINAPI ISF_MyComputer_fnSetNameOf (
760 IShellFolder2 * iface, HWND hwndOwner, LPCITEMIDLIST pidl,
761 LPCOLESTR lpName, DWORD dwFlags, LPITEMIDLIST * pPidlOut)
763 IMyComputerFolderImpl *This = impl_from_IShellFolder2(iface);
764 FIXME ("(%p)->(%p,pidl=%p,%s,%u,%p)\n", This,
765 hwndOwner, pidl, debugstr_w (lpName), dwFlags, pPidlOut);
766 return E_FAIL;
769 static HRESULT WINAPI ISF_MyComputer_fnGetDefaultSearchGUID(IShellFolder2 *iface, GUID *guid)
771 IMyComputerFolderImpl *This = impl_from_IShellFolder2(iface);
772 TRACE("(%p)->(%p)\n", This, guid);
773 return E_NOTIMPL;
775 static HRESULT WINAPI ISF_MyComputer_fnEnumSearches (
776 IShellFolder2 * iface, IEnumExtraSearch ** ppenum)
778 IMyComputerFolderImpl *This = impl_from_IShellFolder2(iface);
779 FIXME ("(%p)\n", This);
780 return E_NOTIMPL;
783 static HRESULT WINAPI ISF_MyComputer_fnGetDefaultColumn(IShellFolder2 *iface, DWORD reserved,
784 ULONG *sort, ULONG *display)
786 IMyComputerFolderImpl *This = impl_from_IShellFolder2(iface);
788 TRACE("(%p)->(%#x, %p, %p)\n", This, reserved, sort, display);
790 return E_NOTIMPL;
793 static HRESULT WINAPI ISF_MyComputer_fnGetDefaultColumnState (
794 IShellFolder2 * iface, UINT iColumn, DWORD * pcsFlags)
796 IMyComputerFolderImpl *This = impl_from_IShellFolder2(iface);
798 TRACE ("(%p)->(%d %p)\n", This, iColumn, pcsFlags);
800 if (!pcsFlags || iColumn >= ARRAY_SIZE(mycomputer_header))
801 return E_INVALIDARG;
803 *pcsFlags = mycomputer_header[iColumn].pcsFlags;
805 return S_OK;
808 static HRESULT WINAPI ISF_MyComputer_fnGetDetailsEx (IShellFolder2 * iface,
809 LPCITEMIDLIST pidl, const SHCOLUMNID * pscid, VARIANT * pv)
811 IMyComputerFolderImpl *This = impl_from_IShellFolder2(iface);
812 FIXME ("(%p)\n", This);
813 return E_NOTIMPL;
816 /* FIXME: drive size >4GB is rolling over */
817 static HRESULT WINAPI ISF_MyComputer_fnGetDetailsOf (IShellFolder2 *iface,
818 LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *psd)
820 IMyComputerFolderImpl *This = impl_from_IShellFolder2(iface);
821 char szPath[MAX_PATH];
822 ULARGE_INTEGER ulBytes;
823 HRESULT hr = S_OK;
825 TRACE ("(%p)->(%p %i %p)\n", This, pidl, iColumn, psd);
827 if (!psd || iColumn >= ARRAY_SIZE(mycomputer_header))
828 return E_INVALIDARG;
830 if (!pidl)
831 return SHELL32_GetColumnDetails(mycomputer_header, iColumn, psd);
833 psd->str.u.cStr[0] = 0;
834 psd->str.uType = STRRET_CSTR;
836 switch (iColumn)
838 case 0: /* name */
839 hr = IShellFolder2_GetDisplayNameOf (iface, pidl,
840 SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str);
841 break;
842 case 1: /* type */
843 _ILGetFileType (pidl, psd->str.u.cStr, MAX_PATH);
844 break;
845 case 2: /* total size */
846 if (_ILIsDrive (pidl))
848 _ILSimpleGetText (pidl, szPath, MAX_PATH);
849 GetDiskFreeSpaceExA (szPath, NULL, &ulBytes, NULL);
850 StrFormatByteSizeA (ulBytes.u.LowPart, psd->str.u.cStr, MAX_PATH);
852 break;
853 case 3: /* free size */
854 if (_ILIsDrive (pidl))
856 _ILSimpleGetText (pidl, szPath, MAX_PATH);
857 GetDiskFreeSpaceExA (szPath, &ulBytes, NULL, NULL);
858 StrFormatByteSizeA (ulBytes.u.LowPart, psd->str.u.cStr, MAX_PATH);
860 break;
863 return hr;
866 static HRESULT WINAPI ISF_MyComputer_fnMapColumnToSCID (IShellFolder2 *iface, UINT column, SHCOLUMNID *scid)
868 IMyComputerFolderImpl *This = impl_from_IShellFolder2(iface);
870 TRACE("(%p)->(%u %p)\n", This, column, scid);
872 if (column >= ARRAY_SIZE(mycomputer_header))
873 return E_INVALIDARG;
875 return shellfolder_map_column_to_scid(mycomputer_header, column, scid);
878 static const IShellFolder2Vtbl vt_ShellFolder2 =
880 ISF_MyComputer_fnQueryInterface,
881 ISF_MyComputer_fnAddRef,
882 ISF_MyComputer_fnRelease,
883 ISF_MyComputer_fnParseDisplayName,
884 ISF_MyComputer_fnEnumObjects,
885 ISF_MyComputer_fnBindToObject,
886 ISF_MyComputer_fnBindToStorage,
887 ISF_MyComputer_fnCompareIDs,
888 ISF_MyComputer_fnCreateViewObject,
889 ISF_MyComputer_fnGetAttributesOf,
890 ISF_MyComputer_fnGetUIObjectOf,
891 ISF_MyComputer_fnGetDisplayNameOf,
892 ISF_MyComputer_fnSetNameOf,
893 /* ShellFolder2 */
894 ISF_MyComputer_fnGetDefaultSearchGUID,
895 ISF_MyComputer_fnEnumSearches,
896 ISF_MyComputer_fnGetDefaultColumn,
897 ISF_MyComputer_fnGetDefaultColumnState,
898 ISF_MyComputer_fnGetDetailsEx,
899 ISF_MyComputer_fnGetDetailsOf,
900 ISF_MyComputer_fnMapColumnToSCID
903 /************************************************************************
904 * IMCFldr_PersistFolder2_QueryInterface
906 static HRESULT WINAPI IMCFldr_PersistFolder2_QueryInterface (
907 IPersistFolder2 * iface, REFIID iid, LPVOID * ppvObj)
909 IMyComputerFolderImpl *This = impl_from_IPersistFolder2(iface);
910 TRACE ("(%p)\n", This);
911 return IShellFolder2_QueryInterface (&This->IShellFolder2_iface, iid, ppvObj);
914 /************************************************************************
915 * IMCFldr_PersistFolder2_AddRef
917 static ULONG WINAPI IMCFldr_PersistFolder2_AddRef (IPersistFolder2 * iface)
919 IMyComputerFolderImpl *This = impl_from_IPersistFolder2(iface);
920 TRACE ("(%p)->(count=%u)\n", This, This->ref);
921 return IShellFolder2_AddRef (&This->IShellFolder2_iface);
924 /************************************************************************
925 * ISFPersistFolder_Release
927 static ULONG WINAPI IMCFldr_PersistFolder2_Release (IPersistFolder2 * iface)
929 IMyComputerFolderImpl *This = impl_from_IPersistFolder2(iface);
930 TRACE ("(%p)->(count=%u)\n", This, This->ref);
931 return IShellFolder2_Release (&This->IShellFolder2_iface);
934 /************************************************************************
935 * IMCFldr_PersistFolder2_GetClassID
937 static HRESULT WINAPI IMCFldr_PersistFolder2_GetClassID (
938 IPersistFolder2 * iface, CLSID * lpClassId)
940 IMyComputerFolderImpl *This = impl_from_IPersistFolder2(iface);
942 TRACE ("(%p)\n", This);
944 if (!lpClassId)
945 return E_POINTER;
946 *lpClassId = CLSID_MyComputer;
948 return S_OK;
951 /************************************************************************
952 * IMCFldr_PersistFolder2_Initialize
954 * NOTES: it makes no sense to change the pidl
956 static HRESULT WINAPI IMCFldr_PersistFolder2_Initialize (
957 IPersistFolder2 * iface, LPCITEMIDLIST pidl)
959 IMyComputerFolderImpl *This = impl_from_IPersistFolder2(iface);
960 TRACE ("(%p)->(%p)\n", This, pidl);
961 return E_NOTIMPL;
964 /**************************************************************************
965 * IPersistFolder2_fnGetCurFolder
967 static HRESULT WINAPI IMCFldr_PersistFolder2_GetCurFolder (
968 IPersistFolder2 * iface, LPITEMIDLIST * pidl)
970 IMyComputerFolderImpl *This = impl_from_IPersistFolder2(iface);
972 TRACE ("(%p)->(%p)\n", This, pidl);
974 if (!pidl)
975 return E_POINTER;
976 *pidl = ILClone (This->pidlRoot);
977 return S_OK;
980 static const IPersistFolder2Vtbl vt_PersistFolder2 =
982 IMCFldr_PersistFolder2_QueryInterface,
983 IMCFldr_PersistFolder2_AddRef,
984 IMCFldr_PersistFolder2_Release,
985 IMCFldr_PersistFolder2_GetClassID,
986 IMCFldr_PersistFolder2_Initialize,
987 IMCFldr_PersistFolder2_GetCurFolder