2 * Virtual Workplace folder
4 * Copyright 1997 Marcus Meissner
5 * Copyright 1998, 1999, 2002 Juergen Schmied
6 * Copyright 2009 Andrew Hill
7 * Copyright 2017 Katayama Hirofumi MZ
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 WINE_DEFAULT_DEBUG_CHANNEL (shell
);
29 CDrivesFolder should create a CRegFolder to represent the virtual items that exist only in
30 the registry. The CRegFolder is aggregated by the CDrivesFolder.
31 The CDrivesFolderEnum class should enumerate only drives on the system. Since the CRegFolder
32 implementation of IShellFolder::EnumObjects enumerates the virtual items, the
33 CDrivesFolderEnum is only responsible for returning the physical items.
35 2. At least on my XP system, the drive pidls returned are of type PT_DRIVE1, not PT_DRIVE
36 3. The parsing name returned for my computer is incorrect. It should be "My Computer"
39 static int iDriveIconIds
[7] = { IDI_SHELL_DRIVE
, /* DRIVE_UNKNOWN */
40 IDI_SHELL_CDROM
, /* DRIVE_NO_ROOT_DIR*/
41 IDI_SHELL_3_14_FLOPPY
, /* DRIVE_REMOVABLE*/
42 IDI_SHELL_DRIVE
, /* DRIVE_FIXED*/
43 IDI_SHELL_NETDRIVE
, /* DRIVE_REMOTE*/
44 IDI_SHELL_CDROM
, /* DRIVE_CDROM*/
45 IDI_SHELL_RAMDISK
/* DRIVE_RAMDISK*/
48 static int iDriveTypeIds
[7] = { IDS_DRIVE_FIXED
, /* DRIVE_UNKNOWN */
49 IDS_DRIVE_FIXED
, /* DRIVE_NO_ROOT_DIR*/
50 IDS_DRIVE_FLOPPY
, /* DRIVE_REMOVABLE*/
51 IDS_DRIVE_FIXED
, /* DRIVE_FIXED*/
52 IDS_DRIVE_NETWORK
, /* DRIVE_REMOTE*/
53 IDS_DRIVE_CDROM
, /* DRIVE_CDROM*/
54 IDS_DRIVE_FIXED
/* DRIVE_RAMDISK*/
57 /***********************************************************************
58 * IShellFolder implementation
62 #define RETRY_SLEEP 250
63 static BOOL
TryToLockOrUnlockDrive(HANDLE hDrive
, BOOL bLock
)
65 DWORD dwError
, dwBytesReturned
;
66 DWORD dwCode
= (bLock
? FSCTL_LOCK_VOLUME
: FSCTL_UNLOCK_VOLUME
);
67 for (DWORD i
= 0; i
< RETRY_COUNT
; ++i
)
69 if (DeviceIoControl(hDrive
, dwCode
, NULL
, 0, NULL
, 0, &dwBytesReturned
, NULL
))
72 dwError
= GetLastError();
73 if (dwError
== ERROR_INVALID_FUNCTION
)
74 break; /* don't sleep if function is not implemented */
78 SetLastError(dwError
);
82 // NOTE: See also https://support.microsoft.com/en-us/help/165721/how-to-ejecting-removable-media-in-windows-nt-windows-2000-windows-xp
83 static BOOL
DoEjectDrive(const WCHAR
*physical
, UINT nDriveType
, INT
*pnStringID
)
85 /* GENERIC_WRITE isn't needed for umount */
86 DWORD dwAccessMode
= GENERIC_READ
;
87 DWORD dwShareMode
= FILE_SHARE_READ
| FILE_SHARE_WRITE
;
89 HANDLE hDrive
= CreateFile(physical
, dwAccessMode
, dwShareMode
, 0, OPEN_EXISTING
, 0, NULL
);
90 if (hDrive
== INVALID_HANDLE_VALUE
)
93 BOOL bResult
, bNeedUnlock
= FALSE
;
94 DWORD dwBytesReturned
, dwError
= NO_ERROR
;
95 PREVENT_MEDIA_REMOVAL removal
;
98 bResult
= TryToLockOrUnlockDrive(hDrive
, TRUE
);
101 dwError
= GetLastError();
102 *pnStringID
= IDS_CANTLOCKVOLUME
; /* Unable to lock volume */
105 bResult
= DeviceIoControl(hDrive
, FSCTL_DISMOUNT_VOLUME
, NULL
, 0, NULL
, 0, &dwBytesReturned
, NULL
);
108 dwError
= GetLastError();
109 *pnStringID
= IDS_CANTDISMOUNTVOLUME
; /* Unable to dismount volume */
113 removal
.PreventMediaRemoval
= FALSE
;
114 bResult
= DeviceIoControl(hDrive
, IOCTL_STORAGE_MEDIA_REMOVAL
, &removal
, sizeof(removal
), NULL
,
115 0, &dwBytesReturned
, NULL
);
118 *pnStringID
= IDS_CANTEJECTMEDIA
; /* Unable to eject media */
119 dwError
= GetLastError();
123 bResult
= DeviceIoControl(hDrive
, IOCTL_STORAGE_EJECT_MEDIA
, NULL
, 0, NULL
, 0, &dwBytesReturned
, NULL
);
126 *pnStringID
= IDS_CANTEJECTMEDIA
; /* Unable to eject media */
127 dwError
= GetLastError();
135 TryToLockOrUnlockDrive(hDrive
, FALSE
);
140 SetLastError(dwError
);
144 HRESULT CALLBACK
DrivesContextMenuCallback(IShellFolder
*psf
,
151 if (uMsg
!= DFM_MERGECONTEXTMENU
&& uMsg
!= DFM_INVOKECOMMAND
)
154 PIDLIST_ABSOLUTE pidlFolder
;
155 PUITEMID_CHILD
*apidl
;
159 HRESULT hr
= SH_GetApidlFromDataObject(pdtobj
, &pidlFolder
, &apidl
, &cidl
);
160 if (FAILED_UNEXPECTEDLY(hr
))
163 char szDrive
[8] = {0};
164 if (!_ILGetDrive(apidl
[0], szDrive
, sizeof(szDrive
)))
166 ERR("pidl is not a drive\n");
168 _ILFreeaPidl(apidl
, cidl
);
171 nDriveType
= GetDriveTypeA(szDrive
);
172 GetVolumeInformationA(szDrive
, NULL
, 0, NULL
, NULL
, &dwFlags
, NULL
, 0);
174 // custom command IDs
175 #define CMDID_FORMAT 1
176 #define CMDID_EJECT 2
177 #define CMDID_DISCONNECT 3
179 if (uMsg
== DFM_MERGECONTEXTMENU
)
181 QCMINFO
*pqcminfo
= (QCMINFO
*)lParam
;
183 UINT idCmdFirst
= pqcminfo
->idCmdFirst
;
184 if (!(dwFlags
& FILE_READ_ONLY_VOLUME
) && nDriveType
!= DRIVE_REMOTE
)
186 /* add separator and Format */
187 UINT idCmd
= idCmdFirst
+ CMDID_FORMAT
;
188 _InsertMenuItemW(pqcminfo
->hmenu
, pqcminfo
->indexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
189 _InsertMenuItemW(pqcminfo
->hmenu
, pqcminfo
->indexMenu
++, TRUE
, idCmd
, MFT_STRING
, MAKEINTRESOURCEW(IDS_FORMATDRIVE
), MFS_ENABLED
);
191 if (nDriveType
== DRIVE_REMOVABLE
|| nDriveType
== DRIVE_CDROM
)
193 /* add separator and Eject */
194 UINT idCmd
= idCmdFirst
+ CMDID_EJECT
;
195 _InsertMenuItemW(pqcminfo
->hmenu
, pqcminfo
->indexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
196 _InsertMenuItemW(pqcminfo
->hmenu
, pqcminfo
->indexMenu
++, TRUE
, idCmd
, MFT_STRING
, MAKEINTRESOURCEW(IDS_EJECT
), MFS_ENABLED
);
198 if (nDriveType
== DRIVE_REMOTE
)
200 /* add separator and Disconnect */
201 UINT idCmd
= idCmdFirst
+ CMDID_DISCONNECT
;
202 _InsertMenuItemW(pqcminfo
->hmenu
, pqcminfo
->indexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
203 _InsertMenuItemW(pqcminfo
->hmenu
, pqcminfo
->indexMenu
++, TRUE
, idCmd
, MFT_STRING
, MAKEINTRESOURCEW(IDS_DISCONNECT
), MFS_ENABLED
);
206 pqcminfo
->idCmdFirst
+= 3;
208 else if (uMsg
== DFM_INVOKECOMMAND
)
210 WCHAR wszBuf
[4] = L
"A:\\";
211 wszBuf
[0] = (WCHAR
)szDrive
[0];
214 DWORD dwError
= NO_ERROR
;
216 if (wParam
== DFM_CMD_PROPERTIES
)
218 hr
= SH_ShowDriveProperties(wszBuf
, pidlFolder
, apidl
);
221 dwError
= ERROR_CAN_NOT_COMPLETE
;
222 nStringID
= IDS_CANTSHOWPROPERTIES
;
227 if (wParam
== CMDID_FORMAT
)
230 DWORD dwRet
= SHFormatDrive(hwnd
, szDrive
[0] - 'A', SHFMT_ID_DEFAULT
, 0);
233 case SHFMT_ERROR
: case SHFMT_CANCEL
: case SHFMT_NOFORMAT
:
238 else if (wParam
== CMDID_EJECT
)
242 wsprintfW(physical
, _T("\\\\.\\%c:"), szDrive
[0]);
244 if (DoEjectDrive(physical
, nDriveType
, &nStringID
))
246 SHChangeNotify(SHCNE_MEDIAREMOVED
, SHCNF_PATHW
| SHCNF_FLUSHNOWAIT
, wszBuf
, NULL
);
250 dwError
= GetLastError();
253 else if (wParam
== CMDID_DISCONNECT
)
256 wszBuf
[2] = UNICODE_NULL
;
257 dwError
= WNetCancelConnection2W(wszBuf
, 0, FALSE
);
258 if (dwError
== NO_ERROR
)
260 SHChangeNotify(SHCNE_DRIVEREMOVED
, SHCNF_PATHW
| SHCNF_FLUSHNOWAIT
, wszBuf
, NULL
);
264 nStringID
= IDS_CANTDISCONNECT
;
271 /* show error message */
272 WCHAR szFormat
[128], szMessage
[128];
273 LoadStringW(shell32_hInstance
, nStringID
, szFormat
, _countof(szFormat
));
274 wsprintfW(szMessage
, szFormat
, dwError
);
275 MessageBoxW(hwnd
, szMessage
, NULL
, MB_ICONERROR
);
280 _ILFreeaPidl(apidl
, cidl
);
285 HRESULT
CDrivesContextMenu_CreateInstance(PCIDLIST_ABSOLUTE pidlFolder
,
288 PCUITEMID_CHILD_ARRAY apidl
,
294 AddClassKeyToArray(L
"Drive", hKeys
, &cKeys
);
295 AddClassKeyToArray(L
"Folder", hKeys
, &cKeys
);
297 return CDefFolderMenu_Create2(pidlFolder
, hwnd
, cidl
, apidl
, psf
, DrivesContextMenuCallback
, cKeys
, hKeys
, ppcm
);
300 HRESULT
CDrivesExtractIcon_CreateInstance(IShellFolder
* psf
, LPCITEMIDLIST pidl
, REFIID riid
, LPVOID
* ppvOut
)
302 CComPtr
<IDefaultExtractIconInit
> initIcon
;
303 HRESULT hr
= SHCreateDefaultExtractIcon(IID_PPV_ARG(IDefaultExtractIconInit
, &initIcon
));
304 if (FAILED_UNEXPECTEDLY(hr
))
307 CHAR
* pszDrive
= _ILGetDataPointer(pidl
)->u
.drive
.szDriveName
;
308 UINT DriveType
= GetDriveTypeA(pszDrive
);
309 if (DriveType
> DRIVE_RAMDISK
)
310 DriveType
= DRIVE_FIXED
;
312 WCHAR wTemp
[MAX_PATH
];
314 if ((DriveType
== DRIVE_FIXED
|| DriveType
== DRIVE_UNKNOWN
) &&
315 (HCR_GetIconW(L
"Drive", wTemp
, NULL
, MAX_PATH
, &icon_idx
)))
317 initIcon
->SetNormalIcon(wTemp
, icon_idx
);
321 icon_idx
= iDriveIconIds
[DriveType
];
322 initIcon
->SetNormalIcon(swShell32Name
, -icon_idx
);
325 return initIcon
->QueryInterface(riid
, ppvOut
);
328 class CDrivesFolderEnum
:
329 public CEnumIDListBase
332 HRESULT WINAPI
Initialize(HWND hwndOwner
, DWORD dwFlags
, IEnumIDList
* pRegEnumerator
)
334 /* enumerate the folders */
335 if (dwFlags
& SHCONTF_FOLDERS
)
337 WCHAR wszDriveName
[] = {'A', ':', '\\', '\0'};
338 DWORD dwDrivemap
= GetLogicalDrives();
340 while (wszDriveName
[0] <= 'Z')
342 if(dwDrivemap
& 0x00000001L
)
343 AddToEnumList(_ILCreateDrive(wszDriveName
));
345 dwDrivemap
= dwDrivemap
>> 1;
349 /* Enumerate the items of the reg folder */
350 AppendItemsFromEnumerator(pRegEnumerator
);
355 BEGIN_COM_MAP(CDrivesFolderEnum
)
356 COM_INTERFACE_ENTRY_IID(IID_IEnumIDList
, IEnumIDList
)
360 /***********************************************************************
361 * IShellFolder [MyComputer] implementation
364 static const shvheader MyComputerSFHeader
[] = {
365 {IDS_SHV_COLUMN_NAME
, SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_LEFT
, 15},
366 {IDS_SHV_COLUMN_COMMENTS
, SHCOLSTATE_TYPE_STR
, LVCFMT_LEFT
, 10},
367 {IDS_SHV_COLUMN_TYPE
, SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_LEFT
, 10},
368 {IDS_SHV_COLUMN_DISK_CAPACITY
, SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_RIGHT
, 10},
369 {IDS_SHV_COLUMN_DISK_AVAILABLE
, SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_RIGHT
, 10},
372 #define MYCOMPUTERSHELLVIEWCOLUMNS 5
374 static const DWORD dwComputerAttributes
=
375 SFGAO_CANRENAME
| SFGAO_CANDELETE
| SFGAO_HASPROPSHEET
| SFGAO_DROPTARGET
|
376 SFGAO_FILESYSANCESTOR
| SFGAO_FOLDER
| SFGAO_HASSUBFOLDER
| SFGAO_CANLINK
;
377 static const DWORD dwControlPanelAttributes
=
378 SFGAO_HASSUBFOLDER
| SFGAO_FOLDER
| SFGAO_CANLINK
;
379 static const DWORD dwDriveAttributes
=
380 SFGAO_HASSUBFOLDER
| SFGAO_FILESYSTEM
| SFGAO_FOLDER
| SFGAO_FILESYSANCESTOR
|
381 SFGAO_DROPTARGET
| SFGAO_HASPROPSHEET
| SFGAO_CANRENAME
| SFGAO_CANLINK
;
383 CDrivesFolder::CDrivesFolder()
388 CDrivesFolder::~CDrivesFolder()
390 TRACE ("-- destroying IShellFolder(%p)\n", this);
394 HRESULT WINAPI
CDrivesFolder::FinalConstruct()
396 pidlRoot
= _ILCreateMyComputer(); /* my qualified pidl */
397 if (pidlRoot
== NULL
)
398 return E_OUTOFMEMORY
;
400 HRESULT hr
= CRegFolder_CreateInstance(&CLSID_MyComputer
,
402 L
"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}",
404 IID_PPV_ARG(IShellFolder2
, &m_regFolder
));
409 /**************************************************************************
410 * CDrivesFolder::ParseDisplayName
412 HRESULT WINAPI
CDrivesFolder::ParseDisplayName(HWND hwndOwner
, LPBC pbc
, LPOLESTR lpszDisplayName
,
413 DWORD
* pchEaten
, PIDLIST_RELATIVE
* ppidl
, DWORD
* pdwAttributes
)
415 HRESULT hr
= E_INVALIDARG
;
416 LPCWSTR szNext
= NULL
;
417 LPITEMIDLIST pidlTemp
= NULL
;
419 TRACE("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n", this,
420 hwndOwner
, pbc
, lpszDisplayName
, debugstr_w (lpszDisplayName
),
421 pchEaten
, ppidl
, pdwAttributes
);
425 *pchEaten
= 0; /* strange but like the original */
427 /* handle CLSID paths */
428 if (lpszDisplayName
[0] == ':' && lpszDisplayName
[1] == ':')
429 return m_regFolder
->ParseDisplayName(hwndOwner
, pbc
, lpszDisplayName
, pchEaten
, ppidl
, pdwAttributes
);
431 if (PathGetDriveNumberW(lpszDisplayName
) < 0)
434 pidlTemp
= _ILCreateDrive(lpszDisplayName
);
436 return E_OUTOFMEMORY
;
438 if (lpszDisplayName
[2] == L
'\\')
440 szNext
= &lpszDisplayName
[3];
443 if (szNext
&& *szNext
)
445 hr
= SHELL32_ParseNextElement (this, hwndOwner
, pbc
, &pidlTemp
,
446 (LPOLESTR
) szNext
, pchEaten
, pdwAttributes
);
451 if (pdwAttributes
&& *pdwAttributes
)
453 if (_ILIsDrive(pidlTemp
))
454 *pdwAttributes
&= dwDriveAttributes
;
455 else if (_ILIsSpecialFolder(pidlTemp
))
456 m_regFolder
->GetAttributesOf(1, &pidlTemp
, pdwAttributes
);
458 ERR("Got an unkown pidl here!\n");
464 TRACE ("(%p)->(-- ret=0x%08x)\n", this, hr
);
469 /**************************************************************************
470 * CDrivesFolder::EnumObjects
472 HRESULT WINAPI
CDrivesFolder::EnumObjects(HWND hwndOwner
, DWORD dwFlags
, LPENUMIDLIST
*ppEnumIDList
)
474 CComPtr
<IEnumIDList
> pRegEnumerator
;
475 m_regFolder
->EnumObjects(hwndOwner
, dwFlags
, &pRegEnumerator
);
477 return ShellObjectCreatorInit
<CDrivesFolderEnum
>(hwndOwner
, dwFlags
, pRegEnumerator
, IID_PPV_ARG(IEnumIDList
, ppEnumIDList
));
480 /**************************************************************************
481 * CDrivesFolder::BindToObject
483 HRESULT WINAPI
CDrivesFolder::BindToObject(PCUIDLIST_RELATIVE pidl
, LPBC pbcReserved
, REFIID riid
, LPVOID
*ppvOut
)
485 TRACE("(%p)->(pidl=%p,%p,%s,%p)\n", this,
486 pidl
, pbcReserved
, shdebugstr_guid(&riid
), ppvOut
);
488 if (_ILIsSpecialFolder(pidl
))
489 return m_regFolder
->BindToObject(pidl
, pbcReserved
, riid
, ppvOut
);
491 CHAR
* pchDrive
= _ILGetDataPointer(pidl
)->u
.drive
.szDriveName
;
493 PERSIST_FOLDER_TARGET_INFO pfti
= {0};
494 pfti
.dwAttributes
= -1;
496 pfti
.szTargetParsingName
[0] = *pchDrive
;
497 pfti
.szTargetParsingName
[1] = L
':';
498 pfti
.szTargetParsingName
[2] = L
'\\';
500 HRESULT hr
= SHELL32_BindToSF(pidlRoot
,
503 &CLSID_ShellFSFolder
,
506 if (FAILED_UNEXPECTEDLY(hr
))
512 /**************************************************************************
513 * CDrivesFolder::BindToStorage
515 HRESULT WINAPI
CDrivesFolder::BindToStorage(PCUIDLIST_RELATIVE pidl
, LPBC pbcReserved
, REFIID riid
, LPVOID
*ppvOut
)
517 FIXME("(%p)->(pidl=%p,%p,%s,%p) stub\n", this,
518 pidl
, pbcReserved
, shdebugstr_guid (&riid
), ppvOut
);
524 /**************************************************************************
525 * CDrivesFolder::CompareIDs
528 HRESULT WINAPI
CDrivesFolder::CompareIDs(LPARAM lParam
, PCUIDLIST_RELATIVE pidl1
, PCUIDLIST_RELATIVE pidl2
)
532 if (!pidl1
|| !pidl2
)
534 ERR("Got null pidl pointer (%Ix %p %p)!\n", lParam
, pidl1
, pidl2
);
538 if (_ILIsSpecialFolder(pidl1
) || _ILIsSpecialFolder(pidl2
))
539 return m_regFolder
->CompareIDs(lParam
, pidl1
, pidl2
);
541 if (!_ILIsDrive(pidl1
) || !_ILIsDrive(pidl2
) || LOWORD(lParam
) >= MYCOMPUTERSHELLVIEWCOLUMNS
)
544 CHAR
* pszDrive1
= _ILGetDataPointer(pidl1
)->u
.drive
.szDriveName
;
545 CHAR
* pszDrive2
= _ILGetDataPointer(pidl2
)->u
.drive
.szDriveName
;
548 switch(LOWORD(lParam
))
552 result
= stricmp(pszDrive1
, pszDrive2
);
553 hres
= MAKE_COMPARE_HRESULT(result
);
556 case 1: /* comments */
557 hres
= MAKE_COMPARE_HRESULT(0);
561 /* We want to return immediately because SHELL32_CompareDetails also compares children. */
562 return SHELL32_CompareDetails(this, lParam
, pidl1
, pidl2
);
565 case 4: /* Size Available */
567 ULARGE_INTEGER Drive1Available
, Drive1Total
, Drive2Available
, Drive2Total
;
569 if (GetVolumeInformationA(pszDrive1
, NULL
, 0, NULL
, NULL
, NULL
, NULL
, 0))
570 GetDiskFreeSpaceExA(pszDrive1
, &Drive1Available
, &Drive1Total
, NULL
);
572 Drive1Available
.QuadPart
= Drive1Total
.QuadPart
= 0;
574 if (GetVolumeInformationA(pszDrive2
, NULL
, 0, NULL
, NULL
, NULL
, NULL
, 0))
575 GetDiskFreeSpaceExA(pszDrive2
, &Drive2Available
, &Drive2Total
, NULL
);
577 Drive2Available
.QuadPart
= Drive2Total
.QuadPart
= 0;
580 if (lParam
== 3) /* Size */
581 Diff
.QuadPart
= Drive1Total
.QuadPart
- Drive2Total
.QuadPart
;
582 else /* Size available */
583 Diff
.QuadPart
= Drive1Available
.QuadPart
- Drive2Available
.QuadPart
;
585 hres
= MAKE_COMPARE_HRESULT(Diff
.QuadPart
);
592 if (HRESULT_CODE(hres
) == 0)
593 return SHELL32_CompareChildren(this, lParam
, pidl1
, pidl2
);
598 /**************************************************************************
599 * CDrivesFolder::CreateViewObject
601 HRESULT WINAPI
CDrivesFolder::CreateViewObject(HWND hwndOwner
, REFIID riid
, LPVOID
* ppvOut
)
603 CComPtr
<IShellView
> pShellView
;
604 HRESULT hr
= E_INVALIDARG
;
606 TRACE("(%p)->(hwnd=%p,%s,%p)\n", this,
607 hwndOwner
, shdebugstr_guid (&riid
), ppvOut
);
614 if (IsEqualIID(riid
, IID_IDropTarget
))
616 WARN("IDropTarget not implemented\n");
619 else if (IsEqualIID(riid
, IID_IContextMenu
))
621 WARN("IContextMenu not implemented\n");
624 else if (IsEqualIID(riid
, IID_IShellView
))
626 SFV_CREATE sfvparams
= {sizeof(SFV_CREATE
), this};
627 hr
= SHCreateShellFolderView(&sfvparams
, (IShellView
**)ppvOut
);
629 TRACE ("-- (%p)->(interface=%p)\n", this, ppvOut
);
633 static BOOL
_ILIsControlPanel(LPCITEMIDLIST pidl
)
635 GUID
*guid
= _ILGetGUIDPointer(pidl
);
637 TRACE("(%p)\n", pidl
);
640 return IsEqualIID(*guid
, CLSID_ControlPanel
);
644 /**************************************************************************
645 * CDrivesFolder::GetAttributesOf
647 HRESULT WINAPI
CDrivesFolder::GetAttributesOf(UINT cidl
, PCUITEMID_CHILD_ARRAY apidl
, DWORD
* rgfInOut
)
649 TRACE ("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n",
650 this, cidl
, apidl
, rgfInOut
, rgfInOut
? *rgfInOut
: 0);
658 /* FIXME: always add SFGAO_CANLINK */
660 *rgfInOut
&= dwComputerAttributes
;
663 for (UINT i
= 0; i
< cidl
; ++i
)
665 if (_ILIsDrive(apidl
[i
]))
666 *rgfInOut
&= dwDriveAttributes
;
667 else if (_ILIsControlPanel(apidl
[i
]))
668 *rgfInOut
&= dwControlPanelAttributes
;
669 else if (_ILIsSpecialFolder(*apidl
))
670 m_regFolder
->GetAttributesOf(1, &apidl
[i
], rgfInOut
);
672 ERR("Got unknown pidl type!\n");
676 /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
677 *rgfInOut
&= ~SFGAO_VALIDATE
;
679 TRACE ("-- result=0x%08x\n", *rgfInOut
);
683 /**************************************************************************
684 * CDrivesFolder::GetUIObjectOf
687 * hwndOwner [in] Parent window for any output
688 * cidl [in] array size
689 * apidl [in] simple pidl array
690 * riid [in] Requested Interface
691 * prgfInOut [ ] reserved
692 * ppvObject [out] Resulting Interface
695 HRESULT WINAPI
CDrivesFolder::GetUIObjectOf(HWND hwndOwner
,
696 UINT cidl
, PCUITEMID_CHILD_ARRAY apidl
,
697 REFIID riid
, UINT
*prgfInOut
, LPVOID
*ppvOut
)
700 HRESULT hr
= E_INVALIDARG
;
702 TRACE("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n", this,
703 hwndOwner
, cidl
, apidl
, shdebugstr_guid (&riid
), prgfInOut
, ppvOut
);
710 if (IsEqualIID (riid
, IID_IContextMenu
) && (cidl
>= 1))
712 if (_ILIsDrive(apidl
[0]))
713 hr
= CDrivesContextMenu_CreateInstance(pidlRoot
, hwndOwner
, cidl
, apidl
, static_cast<IShellFolder
*>(this), (IContextMenu
**)&pObj
);
715 hr
= m_regFolder
->GetUIObjectOf(hwndOwner
, cidl
, apidl
, riid
, prgfInOut
, &pObj
);
717 else if (IsEqualIID (riid
, IID_IDataObject
) && (cidl
>= 1))
719 hr
= IDataObject_Constructor (hwndOwner
,
720 pidlRoot
, apidl
, cidl
, (IDataObject
**)&pObj
);
722 else if ((IsEqualIID (riid
, IID_IExtractIconA
) || IsEqualIID (riid
, IID_IExtractIconW
)) && (cidl
== 1))
724 if (_ILIsDrive(apidl
[0]))
725 hr
= CDrivesExtractIcon_CreateInstance(this, apidl
[0], riid
, &pObj
);
727 hr
= m_regFolder
->GetUIObjectOf(hwndOwner
, cidl
, apidl
, riid
, prgfInOut
, &pObj
);
729 else if (IsEqualIID (riid
, IID_IDropTarget
) && (cidl
== 1))
731 CComPtr
<IShellFolder
> psfChild
;
732 hr
= this->BindToObject(apidl
[0], NULL
, IID_PPV_ARG(IShellFolder
, &psfChild
));
733 if (FAILED_UNEXPECTEDLY(hr
))
736 return psfChild
->CreateViewObject(NULL
, riid
, ppvOut
);
741 if (SUCCEEDED(hr
) && !pObj
)
745 TRACE ("(%p)->hr=0x%08x\n", this, hr
);
749 /**************************************************************************
750 * CDrivesFolder::GetDisplayNameOf
752 HRESULT WINAPI
CDrivesFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl
, DWORD dwFlags
, LPSTRRET strRet
)
757 TRACE ("(%p)->(pidl=%p,0x%08x,%p)\n", this, pidl
, dwFlags
, strRet
);
763 if (!_ILIsPidlSimple (pidl
))
765 return SHELL32_GetDisplayNameOfChild(this, pidl
, dwFlags
, strRet
);
767 else if (_ILIsSpecialFolder(pidl
))
769 return m_regFolder
->GetDisplayNameOf(pidl
, dwFlags
, strRet
);
771 else if (!_ILIsDrive(pidl
))
773 ERR("Wrong pidl type\n");
777 pszPath
= (LPWSTR
)CoTaskMemAlloc((MAX_PATH
+ 1) * sizeof(WCHAR
));
779 return E_OUTOFMEMORY
;
783 _ILSimpleGetTextW(pidl
, pszPath
, MAX_PATH
); /* append my own path */
784 /* long view "lw_name (C:)" */
785 if (!(dwFlags
& SHGDN_FORPARSING
))
787 WCHAR wszDrive
[18] = {0};
788 DWORD dwVolumeSerialNumber
, dwMaximumComponentLength
, dwFileSystemFlags
;
789 static const WCHAR wszOpenBracket
[] = {' ', '(', 0};
790 static const WCHAR wszCloseBracket
[] = {')', 0};
792 lstrcpynW(wszDrive
, pszPath
, 4);
794 GetVolumeInformationW(wszDrive
, pszPath
,
796 &dwVolumeSerialNumber
,
797 &dwMaximumComponentLength
, &dwFileSystemFlags
, NULL
, 0);
798 pszPath
[MAX_PATH
-1] = L
'\0';
799 if (!wcslen(pszPath
))
801 UINT DriveType
, ResourceId
;
802 DriveType
= GetDriveTypeW(wszDrive
);
806 ResourceId
= IDS_DRIVE_FIXED
;
809 ResourceId
= IDS_DRIVE_NETWORK
;
812 ResourceId
= IDS_DRIVE_CDROM
;
819 dwFileSystemFlags
= LoadStringW(shell32_hInstance
, ResourceId
, pszPath
, MAX_PATH
);
820 if (dwFileSystemFlags
> MAX_PATH
- 7)
821 pszPath
[MAX_PATH
-7] = L
'\0';
824 wcscat (pszPath
, wszOpenBracket
);
826 wcscat (pszPath
, wszDrive
);
827 wcscat (pszPath
, wszCloseBracket
);
832 strRet
->uType
= STRRET_WSTR
;
833 strRet
->pOleStr
= pszPath
;
836 CoTaskMemFree(pszPath
);
838 TRACE("-- (%p)->(%s)\n", this, strRet
->uType
== STRRET_CSTR
? strRet
->cStr
: debugstr_w(strRet
->pOleStr
));
842 /**************************************************************************
843 * CDrivesFolder::SetNameOf
844 * Changes the name of a file object or subfolder, possibly changing its item
845 * identifier in the process.
848 * hwndOwner [in] Owner window for output
849 * pidl [in] simple pidl of item to change
850 * lpszName [in] the items new display name
851 * dwFlags [in] SHGNO formatting flags
852 * ppidlOut [out] simple pidl returned
854 HRESULT WINAPI
CDrivesFolder::SetNameOf(HWND hwndOwner
, PCUITEMID_CHILD pidl
,
855 LPCOLESTR lpName
, DWORD dwFlags
, PITEMID_CHILD
*pPidlOut
)
859 if (_ILIsDrive(pidl
))
861 if (_ILSimpleGetTextW(pidl
, szName
, _countof(szName
)))
862 SetVolumeLabelW(szName
, lpName
);
864 *pPidlOut
= _ILCreateDrive(szName
);
868 return m_regFolder
->SetNameOf(hwndOwner
, pidl
, lpName
, dwFlags
, pPidlOut
);
871 HRESULT WINAPI
CDrivesFolder::GetDefaultSearchGUID(GUID
* pguid
)
873 FIXME ("(%p)\n", this);
877 HRESULT WINAPI
CDrivesFolder::EnumSearches(IEnumExtraSearch
** ppenum
)
879 FIXME ("(%p)\n", this);
883 HRESULT WINAPI
CDrivesFolder::GetDefaultColumn (DWORD dwRes
, ULONG
*pSort
, ULONG
*pDisplay
)
885 TRACE ("(%p)\n", this);
894 HRESULT WINAPI
CDrivesFolder::GetDefaultColumnState(UINT iColumn
, DWORD
* pcsFlags
)
896 TRACE ("(%p)\n", this);
898 if (!pcsFlags
|| iColumn
>= MYCOMPUTERSHELLVIEWCOLUMNS
)
900 *pcsFlags
= MyComputerSFHeader
[iColumn
].pcsFlags
;
904 HRESULT WINAPI
CDrivesFolder::GetDetailsEx(PCUITEMID_CHILD pidl
, const SHCOLUMNID
* pscid
, VARIANT
* pv
)
906 FIXME ("(%p)\n", this);
910 HRESULT WINAPI
CDrivesFolder::GetDetailsOf(PCUITEMID_CHILD pidl
, UINT iColumn
, SHELLDETAILS
*psd
)
914 TRACE ("(%p)->(%p %i %p)\n", this, pidl
, iColumn
, psd
);
916 if (!psd
|| iColumn
>= MYCOMPUTERSHELLVIEWCOLUMNS
)
921 psd
->fmt
= MyComputerSFHeader
[iColumn
].fmt
;
922 psd
->cxChar
= MyComputerSFHeader
[iColumn
].cxChar
;
923 return SHSetStrRet(&psd
->str
, MyComputerSFHeader
[iColumn
].colnameid
);
925 else if (!_ILIsDrive(pidl
))
927 return m_regFolder
->GetDetailsOf(pidl
, iColumn
, psd
);
931 ULARGE_INTEGER ulTotalBytes
, ulFreeBytes
;
932 CHAR
* pszDrive
= _ILGetDataPointer(pidl
)->u
.drive
.szDriveName
;
933 UINT DriveType
= GetDriveTypeA(pszDrive
);
934 if (DriveType
> DRIVE_RAMDISK
)
935 DriveType
= DRIVE_FIXED
;
940 hr
= GetDisplayNameOf(pidl
, SHGDN_NORMAL
| SHGDN_INFOLDER
, &psd
->str
);
942 case 1: /* FIXME: comments */
943 hr
= SHSetStrRet(&psd
->str
, "");
946 hr
= SHSetStrRet(&psd
->str
, iDriveTypeIds
[DriveType
]);
948 case 3: /* total size */
949 case 4: /* free size */
950 psd
->str
.cStr
[0] = 0x00;
951 psd
->str
.uType
= STRRET_CSTR
;
952 if (GetVolumeInformationA(pszDrive
, NULL
, 0, NULL
, NULL
, NULL
, NULL
, 0))
954 GetDiskFreeSpaceExA(pszDrive
, &ulFreeBytes
, &ulTotalBytes
, NULL
);
956 StrFormatByteSize64A(ulTotalBytes
.QuadPart
, psd
->str
.cStr
, MAX_PATH
);
958 StrFormatByteSize64A(ulFreeBytes
.QuadPart
, psd
->str
.cStr
, MAX_PATH
);
968 HRESULT WINAPI
CDrivesFolder::MapColumnToSCID(UINT column
, SHCOLUMNID
* pscid
)
970 FIXME("(%p)\n", this);
974 /************************************************************************
975 * CDrivesFolder::GetClassID
977 HRESULT WINAPI
CDrivesFolder::GetClassID(CLSID
*lpClassId
)
979 TRACE ("(%p)\n", this);
984 *lpClassId
= CLSID_MyComputer
;
988 /************************************************************************
989 * CDrivesFolder::Initialize
991 * NOTES: it makes no sense to change the pidl
993 HRESULT WINAPI
CDrivesFolder::Initialize(LPCITEMIDLIST pidl
)
998 /**************************************************************************
999 * CDrivesFolder::GetCurFolder
1001 HRESULT WINAPI
CDrivesFolder::GetCurFolder(LPITEMIDLIST
*pidl
)
1003 TRACE("(%p)->(%p)\n", this, pidl
);
1006 return E_INVALIDARG
; /* xp doesn't have this check and crashes on NULL */
1008 *pidl
= ILClone(pidlRoot
);