* Copyright 1997 Marcus Meissner
* Copyright 1998, 1999, 2002 Juergen Schmied
* Copyright 2009 Andrew Hill
+ * Copyright 2017-2018 Katayama Hirofumi MZ
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
3. The parsing name returned for my computer is incorrect. It should be "My Computer"
*/
+static int iDriveIconIds[7] = { IDI_SHELL_DRIVE, /* DRIVE_UNKNOWN */
+ IDI_SHELL_CDROM, /* DRIVE_NO_ROOT_DIR*/
+ IDI_SHELL_3_14_FLOPPY, /* DRIVE_REMOVABLE*/
+ IDI_SHELL_DRIVE, /* DRIVE_FIXED*/
+ IDI_SHELL_NETDRIVE, /* DRIVE_REMOTE*/
+ IDI_SHELL_CDROM, /* DRIVE_CDROM*/
+ IDI_SHELL_RAMDISK /* DRIVE_RAMDISK*/
+ };
+
+static int iDriveTypeIds[7] = { IDS_DRIVE_FIXED, /* DRIVE_UNKNOWN */
+ IDS_DRIVE_FIXED, /* DRIVE_NO_ROOT_DIR*/
+ IDS_DRIVE_FLOPPY, /* DRIVE_REMOVABLE*/
+ IDS_DRIVE_FIXED, /* DRIVE_FIXED*/
+ IDS_DRIVE_NETWORK, /* DRIVE_REMOTE*/
+ IDS_DRIVE_CDROM, /* DRIVE_CDROM*/
+ IDS_DRIVE_FIXED /* DRIVE_RAMDISK*/
+ };
+
/***********************************************************************
* IShellFolder implementation
*/
-class CDrivesFolderEnum :
- public CEnumIDListBase
+#define RETRY_COUNT 3
+#define RETRY_SLEEP 250
+static BOOL TryToLockOrUnlockDrive(HANDLE hDrive, BOOL bLock)
{
- public:
- CDrivesFolderEnum();
- ~CDrivesFolderEnum();
- HRESULT WINAPI Initialize(HWND hwndOwner, DWORD dwFlags);
- BOOL CreateMyCompEnumList(DWORD dwFlags);
+ DWORD dwError, dwBytesReturned;
+ DWORD dwCode = (bLock ? FSCTL_LOCK_VOLUME : FSCTL_UNLOCK_VOLUME);
+ for (DWORD i = 0; i < RETRY_COUNT; ++i)
+ {
+ if (DeviceIoControl(hDrive, dwCode, NULL, 0, NULL, 0, &dwBytesReturned, NULL))
+ return TRUE;
- BEGIN_COM_MAP(CDrivesFolderEnum)
- COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList)
- END_COM_MAP()
-};
+ dwError = GetLastError();
+ if (dwError == ERROR_INVALID_FUNCTION)
+ break; /* don't sleep if function is not implemented */
-/***********************************************************************
-* IShellFolder [MyComputer] implementation
-*/
+ Sleep(RETRY_SLEEP);
+ }
+ SetLastError(dwError);
+ return FALSE;
+}
-static const shvheader MyComputerSFHeader[] = {
- {IDS_SHV_COLUMN1, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 15},
- {IDS_SHV_COLUMN3, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 10},
- {IDS_SHV_COLUMN6, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
- {IDS_SHV_COLUMN7, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
-};
+// NOTE: See also https://support.microsoft.com/en-us/help/165721/how-to-ejecting-removable-media-in-windows-nt-windows-2000-windows-xp
+static BOOL DoEjectDrive(const WCHAR *physical, UINT nDriveType, INT *pnStringID)
+{
+ /* GENERIC_WRITE isn't needed for umount */
+ DWORD dwAccessMode = GENERIC_READ;
+ DWORD dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
+
+ HANDLE hDrive = CreateFile(physical, dwAccessMode, dwShareMode, 0, OPEN_EXISTING, 0, NULL);
+ if (hDrive == INVALID_HANDLE_VALUE)
+ return FALSE;
+
+ BOOL bResult, bNeedUnlock = FALSE;
+ DWORD dwBytesReturned, dwError = NO_ERROR;
+ PREVENT_MEDIA_REMOVAL removal;
+ do
+ {
+ bResult = TryToLockOrUnlockDrive(hDrive, TRUE);
+ if (!bResult)
+ {
+ dwError = GetLastError();
+ *pnStringID = IDS_CANTLOCKVOLUME; /* Unable to lock volume */
+ break;
+ }
+ bResult = DeviceIoControl(hDrive, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0, &dwBytesReturned, NULL);
+ if (!bResult)
+ {
+ dwError = GetLastError();
+ *pnStringID = IDS_CANTDISMOUNTVOLUME; /* Unable to dismount volume */
+ bNeedUnlock = TRUE;
+ break;
+ }
+ removal.PreventMediaRemoval = FALSE;
+ bResult = DeviceIoControl(hDrive, IOCTL_STORAGE_MEDIA_REMOVAL, &removal, sizeof(removal), NULL,
+ 0, &dwBytesReturned, NULL);
+ if (!bResult)
+ {
+ *pnStringID = IDS_CANTEJECTMEDIA; /* Unable to eject media */
+ dwError = GetLastError();
+ bNeedUnlock = TRUE;
+ break;
+ }
+ bResult = DeviceIoControl(hDrive, IOCTL_STORAGE_EJECT_MEDIA, NULL, 0, NULL, 0, &dwBytesReturned, NULL);
+ if (!bResult)
+ {
+ *pnStringID = IDS_CANTEJECTMEDIA; /* Unable to eject media */
+ dwError = GetLastError();
+ bNeedUnlock = TRUE;
+ break;
+ }
+ } while (0);
-#define MYCOMPUTERSHELLVIEWCOLUMNS 4
+ if (bNeedUnlock)
+ {
+ TryToLockOrUnlockDrive(hDrive, FALSE);
+ }
-static const DWORD dwComputerAttributes =
- SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET |
- SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_CANLINK;
-static const DWORD dwControlPanelAttributes =
- SFGAO_HASSUBFOLDER | SFGAO_FOLDER | SFGAO_CANLINK;
-static const DWORD dwDriveAttributes =
- SFGAO_HASSUBFOLDER | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR |
- SFGAO_DROPTARGET | SFGAO_HASPROPSHEET | SFGAO_CANRENAME | SFGAO_CANLINK;
+ CloseHandle(hDrive);
-CDrivesFolderEnum::CDrivesFolderEnum()
+ SetLastError(dwError);
+ return bResult;
+}
+
+HRESULT CALLBACK DrivesContextMenuCallback(IShellFolder *psf,
+ HWND hwnd,
+ IDataObject *pdtobj,
+ UINT uMsg,
+ WPARAM wParam,
+ LPARAM lParam)
{
+ if (uMsg != DFM_MERGECONTEXTMENU && uMsg != DFM_INVOKECOMMAND)
+ return S_OK;
+
+ PIDLIST_ABSOLUTE pidlFolder;
+ PUITEMID_CHILD *apidl;
+ UINT cidl;
+ UINT nDriveType;
+ DWORD dwFlags;
+ HRESULT hr = SH_GetApidlFromDataObject(pdtobj, &pidlFolder, &apidl, &cidl);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+
+ char szDrive[8] = {0};
+ if (!_ILGetDrive(apidl[0], szDrive, sizeof(szDrive)))
+ {
+ ERR("pidl is not a drive\n");
+ SHFree(pidlFolder);
+ _ILFreeaPidl(apidl, cidl);
+ return E_FAIL;
+ }
+ nDriveType = GetDriveTypeA(szDrive);
+ GetVolumeInformationA(szDrive, NULL, 0, NULL, NULL, &dwFlags, NULL, 0);
+
+// custom command IDs
+#define CMDID_FORMAT 1
+#define CMDID_EJECT 2
+#define CMDID_DISCONNECT 3
+
+ if (uMsg == DFM_MERGECONTEXTMENU)
+ {
+ QCMINFO *pqcminfo = (QCMINFO *)lParam;
+
+ UINT idCmdFirst = pqcminfo->idCmdFirst;
+ if (!(dwFlags & FILE_READ_ONLY_VOLUME) && nDriveType != DRIVE_REMOTE)
+ {
+ /* add separator and Format */
+ UINT idCmd = idCmdFirst + CMDID_FORMAT;
+ _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);
+ _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, idCmd, MFT_STRING, MAKEINTRESOURCEW(IDS_FORMATDRIVE), MFS_ENABLED);
+ }
+ if (nDriveType == DRIVE_REMOVABLE || nDriveType == DRIVE_CDROM)
+ {
+ /* add separator and Eject */
+ UINT idCmd = idCmdFirst + CMDID_EJECT;
+ _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);
+ _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, idCmd, MFT_STRING, MAKEINTRESOURCEW(IDS_EJECT), MFS_ENABLED);
+ }
+ if (nDriveType == DRIVE_REMOTE)
+ {
+ /* add separator and Disconnect */
+ UINT idCmd = idCmdFirst + CMDID_DISCONNECT;
+ _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);
+ _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, idCmd, MFT_STRING, MAKEINTRESOURCEW(IDS_DISCONNECT), MFS_ENABLED);
+ }
+
+ pqcminfo->idCmdFirst += 3;
+ }
+ else if (uMsg == DFM_INVOKECOMMAND)
+ {
+ WCHAR wszBuf[4] = L"A:\\";
+ wszBuf[0] = (WCHAR)szDrive[0];
+
+ INT nStringID = 0;
+ DWORD dwError = NO_ERROR;
+
+ if (wParam == DFM_CMD_PROPERTIES)
+ {
+ hr = SH_ShowDriveProperties(wszBuf, pidlFolder, apidl);
+ if (FAILED(hr))
+ {
+ dwError = ERROR_CAN_NOT_COMPLETE;
+ nStringID = IDS_CANTSHOWPROPERTIES;
+ }
+ }
+ else
+ {
+ if (wParam == CMDID_FORMAT)
+ {
+ /* do format */
+ DWORD dwRet = SHFormatDrive(hwnd, szDrive[0] - 'A', SHFMT_ID_DEFAULT, 0);
+ switch (dwRet)
+ {
+ case SHFMT_ERROR: case SHFMT_CANCEL: case SHFMT_NOFORMAT:
+ hr = E_FAIL;
+ break;
+ }
+ }
+ else if (wParam == CMDID_EJECT)
+ {
+ /* do eject */
+ WCHAR physical[10];
+ wsprintfW(physical, _T("\\\\.\\%c:"), szDrive[0]);
+
+ if (DoEjectDrive(physical, nDriveType, &nStringID))
+ {
+ SHChangeNotify(SHCNE_MEDIAREMOVED, SHCNF_PATHW | SHCNF_FLUSHNOWAIT, wszBuf, NULL);
+ }
+ else
+ {
+ dwError = GetLastError();
+ }
+ }
+ else if (wParam == CMDID_DISCONNECT)
+ {
+ /* do disconnect */
+ wszBuf[2] = UNICODE_NULL;
+ dwError = WNetCancelConnection2W(wszBuf, 0, FALSE);
+ if (dwError == NO_ERROR)
+ {
+ SHChangeNotify(SHCNE_DRIVEREMOVED, SHCNF_PATHW | SHCNF_FLUSHNOWAIT, wszBuf, NULL);
+ }
+ else
+ {
+ nStringID = IDS_CANTDISCONNECT;
+ }
+ }
+ }
+
+ if (nStringID != 0)
+ {
+ /* show error message */
+ WCHAR szFormat[128], szMessage[128];
+ LoadStringW(shell32_hInstance, nStringID, szFormat, _countof(szFormat));
+ wsprintfW(szMessage, szFormat, dwError);
+ MessageBoxW(hwnd, szMessage, NULL, MB_ICONERROR);
+ }
+ }
+
+ SHFree(pidlFolder);
+ _ILFreeaPidl(apidl, cidl);
+
+ return hr;
}
-CDrivesFolderEnum::~CDrivesFolderEnum()
+HRESULT CDrivesContextMenu_CreateInstance(PCIDLIST_ABSOLUTE pidlFolder,
+ HWND hwnd,
+ UINT cidl,
+ PCUITEMID_CHILD_ARRAY apidl,
+ IShellFolder *psf,
+ IContextMenu **ppcm)
{
+ HKEY hKeys[2];
+ UINT cKeys = 0;
+ AddClassKeyToArray(L"Drive", hKeys, &cKeys);
+ AddClassKeyToArray(L"Folder", hKeys, &cKeys);
+
+ return CDefFolderMenu_Create2(pidlFolder, hwnd, cidl, apidl, psf, DrivesContextMenuCallback, cKeys, hKeys, ppcm);
}
-HRESULT WINAPI CDrivesFolderEnum::Initialize(HWND hwndOwner, DWORD dwFlags)
+static HRESULT
+getIconLocationForDrive(IShellFolder *psf, PCITEMID_CHILD pidl, UINT uFlags,
+ LPWSTR szIconFile, UINT cchMax, int *piIndex, UINT *pwFlags)
{
- if (CreateMyCompEnumList(dwFlags) == FALSE)
+ WCHAR wszPath[MAX_PATH];
+ WCHAR wszAutoRunInfPath[MAX_PATH];
+ WCHAR wszValue[MAX_PATH], wszTemp[MAX_PATH];
+ static const WCHAR wszAutoRunInf[] = { 'a','u','t','o','r','u','n','.','i','n','f',0 };
+ static const WCHAR wszAutoRun[] = { 'a','u','t','o','r','u','n',0 };
+
+ // get path
+ if (!ILGetDisplayNameExW(psf, pidl, wszPath, 0))
+ return E_FAIL;
+ if (!PathIsDirectoryW(wszPath))
return E_FAIL;
- return S_OK;
-}
+ // build the full path of autorun.inf
+ StringCchCopyW(wszAutoRunInfPath, _countof(wszAutoRunInfPath), wszPath);
+ PathAppendW(wszAutoRunInfPath, wszAutoRunInf);
-/**************************************************************************
- * CDrivesFolderEnum::CreateMyCompEnumList()
- */
+ // autorun.inf --> wszValue
+ if (GetPrivateProfileStringW(wszAutoRun, L"icon", NULL, wszValue, _countof(wszValue),
+ wszAutoRunInfPath) && wszValue[0] != 0)
+ {
+ // wszValue --> wszTemp
+ ExpandEnvironmentStringsW(wszValue, wszTemp, _countof(wszTemp));
+
+ // parse the icon location
+ *piIndex = PathParseIconLocationW(wszTemp);
+
+ // wszPath + wszTemp --> wszPath
+ if (PathIsRelativeW(wszTemp))
+ PathAppendW(wszPath, wszTemp);
+ else
+ StringCchCopyW(wszPath, _countof(wszPath), wszTemp);
+
+ // wszPath --> szIconFile
+ GetFullPathNameW(wszPath, cchMax, szIconFile, NULL);
+
+ return S_OK;
+ }
+
+ return E_FAIL;
+}
-BOOL CDrivesFolderEnum::CreateMyCompEnumList(DWORD dwFlags)
+HRESULT CDrivesExtractIcon_CreateInstance(IShellFolder * psf, LPCITEMIDLIST pidl, REFIID riid, LPVOID * ppvOut)
{
- BOOL bRet = TRUE;
- static const WCHAR MyComputer_NameSpaceW[] = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MyComputer\\Namespace";
+ CComPtr<IDefaultExtractIconInit> initIcon;
+ HRESULT hr = SHCreateDefaultExtractIcon(IID_PPV_ARG(IDefaultExtractIconInit, &initIcon));
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
- TRACE("(%p)->(flags=0x%08x)\n", this, dwFlags);
+ CHAR* pszDrive = _ILGetDataPointer(pidl)->u.drive.szDriveName;
+ UINT DriveType = GetDriveTypeA(pszDrive);
+ if (DriveType > DRIVE_RAMDISK)
+ DriveType = DRIVE_FIXED;
- /* enumerate the folders */
- if (dwFlags & SHCONTF_FOLDERS)
+ WCHAR wTemp[MAX_PATH];
+ int icon_idx;
+ UINT flags = 0;
+ if ((DriveType == DRIVE_FIXED || DriveType == DRIVE_UNKNOWN) &&
+ (HCR_GetIconW(L"Drive", wTemp, NULL, MAX_PATH, &icon_idx)))
+ {
+ initIcon->SetNormalIcon(wTemp, icon_idx);
+ }
+ else if (SUCCEEDED(getIconLocationForDrive(psf, pidl, 0, wTemp, _countof(wTemp),
+ &icon_idx, &flags)))
+ {
+ initIcon->SetNormalIcon(wTemp, icon_idx);
+ }
+ else
{
- WCHAR wszDriveName[] = {'A', ':', '\\', '\0'};
- DWORD dwDrivemap = GetLogicalDrives();
- HKEY hKey;
- UINT i;
+ icon_idx = iDriveIconIds[DriveType];
+ initIcon->SetNormalIcon(swShell32Name, -icon_idx);
+ }
- while (bRet && wszDriveName[0] <= 'Z')
- {
- if(dwDrivemap & 0x00000001L)
- bRet = AddToEnumList(_ILCreateDrive(wszDriveName));
- wszDriveName[0]++;
- dwDrivemap = dwDrivemap >> 1;
- }
+ return initIcon->QueryInterface(riid, ppvOut);
+}
- TRACE("-- (%p)-> enumerate (mycomputer shell extensions)\n", this);
- for (i = 0; i < 2; i++)
+class CDrivesFolderEnum :
+ public CEnumIDListBase
+{
+ public:
+ HRESULT WINAPI Initialize(HWND hwndOwner, DWORD dwFlags, IEnumIDList* pRegEnumerator)
{
- if (bRet && ERROR_SUCCESS == RegOpenKeyExW(i == 0 ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER,
- MyComputer_NameSpaceW, 0, KEY_READ, &hKey))
+ /* enumerate the folders */
+ if (dwFlags & SHCONTF_FOLDERS)
{
- WCHAR wszBuf[50];
- DWORD dwSize, j = 0;
- LONG ErrorCode;
- LPITEMIDLIST pidl;
+ WCHAR wszDriveName[] = {'A', ':', '\\', '\0'};
+ DWORD dwDrivemap = GetLogicalDrives();
- while (bRet)
+ while (wszDriveName[0] <= 'Z')
{
- dwSize = sizeof(wszBuf) / sizeof(wszBuf[0]);
- ErrorCode = RegEnumKeyExW(hKey, j, wszBuf, &dwSize, 0, NULL, NULL, NULL);
- if (ERROR_SUCCESS == ErrorCode)
- {
- if (wszBuf[0] != L'{')
- {
- dwSize = sizeof(wszBuf);
- RegGetValueW(hKey, wszBuf, NULL, RRF_RT_REG_SZ, NULL, wszBuf, &dwSize);
- }
-
- /* FIXME: shell extensions - the type should be PT_SHELLEXT (tested) */
- pidl = _ILCreateGuidFromStrW(wszBuf);
- if (pidl != NULL)
- bRet = AddToEnumList(pidl);
- else
- ERR("Invalid MyComputer namespace extesion: %s\n", wszBuf);
- j++;
- }
- else if (ERROR_NO_MORE_ITEMS == ErrorCode)
- break;
- else
- bRet = FALSE;
+ if(dwDrivemap & 0x00000001L)
+ AddToEnumList(_ILCreateDrive(wszDriveName));
+ wszDriveName[0]++;
+ dwDrivemap = dwDrivemap >> 1;
}
- RegCloseKey(hKey);
}
+
+ /* Enumerate the items of the reg folder */
+ AppendItemsFromEnumerator(pRegEnumerator);
+
+ return S_OK;
}
- }
- return bRet;
-}
+
+ BEGIN_COM_MAP(CDrivesFolderEnum)
+ COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList)
+ END_COM_MAP()
+};
+
+/***********************************************************************
+* IShellFolder [MyComputer] implementation
+*/
+
+static const shvheader MyComputerSFHeader[] = {
+ {IDS_SHV_COLUMN_NAME, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 15},
+ {IDS_SHV_COLUMN_COMMENTS, SHCOLSTATE_TYPE_STR, LVCFMT_LEFT, 10},
+ {IDS_SHV_COLUMN_TYPE, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 10},
+ {IDS_SHV_COLUMN_DISK_CAPACITY, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
+ {IDS_SHV_COLUMN_DISK_AVAILABLE, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
+};
+
+#define MYCOMPUTERSHELLVIEWCOLUMNS 5
+
+static const DWORD dwComputerAttributes =
+ SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET |
+ SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
+static const DWORD dwControlPanelAttributes =
+ SFGAO_HASSUBFOLDER | SFGAO_FOLDER | SFGAO_CANLINK;
+static const DWORD dwDriveAttributes =
+ SFGAO_HASSUBFOLDER | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR |
+ SFGAO_DROPTARGET | SFGAO_HASPROPSHEET | SFGAO_CANRENAME | SFGAO_CANLINK;
CDrivesFolder::CDrivesFolder()
{
pidlRoot = NULL;
- sName = NULL;
}
CDrivesFolder::~CDrivesFolder()
HRESULT WINAPI CDrivesFolder::FinalConstruct()
{
- DWORD dwSize;
- WCHAR szName[MAX_PATH];
- WCHAR wszMyCompKey[256];
- INT i;
-
pidlRoot = _ILCreateMyComputer(); /* my qualified pidl */
if (pidlRoot == NULL)
return E_OUTOFMEMORY;
- i = swprintf(wszMyCompKey, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CLSID\\");
- StringFromGUID2(CLSID_MyComputer, wszMyCompKey + i, sizeof(wszMyCompKey) / sizeof(wszMyCompKey[0]) - i);
- dwSize = sizeof(szName);
- if (RegGetValueW(HKEY_CURRENT_USER, wszMyCompKey,
- NULL, RRF_RT_REG_SZ, NULL, szName, &dwSize) == ERROR_SUCCESS)
- {
- sName = (LPWSTR)SHAlloc((wcslen(szName) + 1) * sizeof(WCHAR));
- if (sName)
- wcscpy(sName, szName);
- TRACE("sName %s\n", debugstr_w(sName));
- }
- return S_OK;
+ HRESULT hr = CRegFolder_CreateInstance(&CLSID_MyComputer,
+ pidlRoot,
+ L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}",
+ L"MyComputer",
+ IID_PPV_ARG(IShellFolder2, &m_regFolder));
+
+ return hr;
}
/**************************************************************************
{
HRESULT hr = E_INVALIDARG;
LPCWSTR szNext = NULL;
- WCHAR szElement[MAX_PATH];
LPITEMIDLIST pidlTemp = NULL;
TRACE("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n", this,
/* handle CLSID paths */
if (lpszDisplayName[0] == ':' && lpszDisplayName[1] == ':')
+ return m_regFolder->ParseDisplayName(hwndOwner, pbc, lpszDisplayName, pchEaten, ppidl, pdwAttributes);
+
+ if (PathGetDriveNumberW(lpszDisplayName) < 0)
+ return E_INVALIDARG;
+
+ pidlTemp = _ILCreateDrive(lpszDisplayName);
+ if (!pidlTemp)
+ return E_OUTOFMEMORY;
+
+ if (lpszDisplayName[2] == L'\\')
{
- return SH_ParseGuidDisplayName(this, hwndOwner, pbc, lpszDisplayName, pchEaten, ppidl, pdwAttributes);
- }
- /* do we have an absolute path name ? */
- else if (PathGetDriveNumberW (lpszDisplayName) >= 0 &&
- lpszDisplayName[2] == (WCHAR) '\\')
- {
- szNext = GetNextElementW (lpszDisplayName, szElement, MAX_PATH);
- /* make drive letter uppercase to enable PIDL comparison */
- szElement[0] = toupper(szElement[0]);
- pidlTemp = _ILCreateDrive (szElement);
+ szNext = &lpszDisplayName[3];
}
if (szNext && *szNext)
if (_ILIsDrive(pidlTemp))
*pdwAttributes &= dwDriveAttributes;
else if (_ILIsSpecialFolder(pidlTemp))
- SHELL32_GetGuidItemAttributes(this, pidlTemp, pdwAttributes);
+ m_regFolder->GetAttributesOf(1, &pidlTemp, pdwAttributes);
else
ERR("Got an unkown pidl here!\n");
}
*/
HRESULT WINAPI CDrivesFolder::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList)
{
- return ShellObjectCreatorInit<CDrivesFolderEnum>(hwndOwner, dwFlags, IID_IEnumIDList, ppEnumIDList);
+ CComPtr<IEnumIDList> pRegEnumerator;
+ m_regFolder->EnumObjects(hwndOwner, dwFlags, &pRegEnumerator);
+
+ return ShellObjectCreatorInit<CDrivesFolderEnum>(hwndOwner, dwFlags, pRegEnumerator, IID_PPV_ARG(IEnumIDList, ppEnumIDList));
}
/**************************************************************************
pidl, pbcReserved, shdebugstr_guid(&riid), ppvOut);
if (_ILIsSpecialFolder(pidl))
- return SHELL32_BindToGuidItem(pidlRoot, pidl, pbcReserved, riid, ppvOut);
+ return m_regFolder->BindToObject(pidl, pbcReserved, riid, ppvOut);
+
+ CHAR* pchDrive = _ILGetDataPointer(pidl)->u.drive.szDriveName;
+
+ PERSIST_FOLDER_TARGET_INFO pfti = {0};
+ pfti.dwAttributes = -1;
+ pfti.csidl = -1;
+ pfti.szTargetParsingName[0] = *pchDrive;
+ pfti.szTargetParsingName[1] = L':';
+ pfti.szTargetParsingName[2] = L'\\';
+
+ HRESULT hr = SHELL32_BindToSF(pidlRoot,
+ &pfti,
+ pidl,
+ &CLSID_ShellFSFolder,
+ riid,
+ ppvOut);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
- return SHELL32_BindToFS(pidlRoot, NULL, pidl, riid, ppvOut);
+ return S_OK;
}
/**************************************************************************
HRESULT WINAPI CDrivesFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2)
{
+ HRESULT hres;
+
if (!pidl1 || !pidl2)
{
ERR("Got null pidl pointer (%Ix %p %p)!\n", lParam, pidl1, pidl2);
}
if (_ILIsSpecialFolder(pidl1) || _ILIsSpecialFolder(pidl2))
- return SHELL32_CompareGuidItems(this, lParam, pidl1, pidl2);
+ return m_regFolder->CompareIDs(lParam, pidl1, pidl2);
if (!_ILIsDrive(pidl1) || !_ILIsDrive(pidl2) || LOWORD(lParam) >= MYCOMPUTERSHELLVIEWCOLUMNS)
return E_INVALIDARG;
case 0: /* name */
{
result = stricmp(pszDrive1, pszDrive2);
- return MAKE_COMPARE_HRESULT(result);
+ hres = MAKE_COMPARE_HRESULT(result);
+ break;
}
- case 1: /* Type */
+ case 1: /* comments */
+ hres = MAKE_COMPARE_HRESULT(0);
+ break;
+ case 2: /* Type */
{
+ /* We want to return immediately because SHELL32_CompareDetails also compares children. */
return SHELL32_CompareDetails(this, lParam, pidl1, pidl2);
}
- case 2: /* Size */
- case 3: /* Size Available */
+ case 3: /* Size */
+ case 4: /* Size Available */
{
ULARGE_INTEGER Drive1Available, Drive1Total, Drive2Available, Drive2Total;
Drive2Available.QuadPart = Drive2Total.QuadPart = 0;
LARGE_INTEGER Diff;
- if (lParam == 2) /* Size */
+ if (lParam == 3) /* Size */
Diff.QuadPart = Drive1Total.QuadPart - Drive2Total.QuadPart;
else /* Size available */
Diff.QuadPart = Drive1Available.QuadPart - Drive2Available.QuadPart;
- return MAKE_COMPARE_HRESULT(Diff.QuadPart);
+ hres = MAKE_COMPARE_HRESULT(Diff.QuadPart);
+ break;
}
+ default:
+ return E_INVALIDARG;
}
- return E_INVALIDARG;
+
+ if (HRESULT_CODE(hres) == 0)
+ return SHELL32_CompareChildren(this, lParam, pidl1, pidl2);
+
+ return hres;
}
/**************************************************************************
}
else if (IsEqualIID(riid, IID_IContextMenu))
{
- WARN("IContextMenu not implemented\n");
- hr = E_NOTIMPL;
+ HKEY hKeys[16];
+ UINT cKeys = 0;
+ AddClassKeyToArray(L"Directory\\Background", hKeys, &cKeys);
+
+ DEFCONTEXTMENU dcm;
+ dcm.hwnd = hwndOwner;
+ dcm.pcmcb = this;
+ dcm.pidlFolder = pidlRoot;
+ dcm.psf = this;
+ dcm.cidl = 0;
+ dcm.apidl = NULL;
+ dcm.cKeys = cKeys;
+ dcm.aKeys = hKeys;
+ dcm.punkAssociationInfo = NULL;
+ hr = SHCreateDefaultContextMenu(&dcm, riid, ppvOut);
}
else if (IsEqualIID(riid, IID_IShellView))
{
- hr = CDefView_Constructor(this, riid, ppvOut);
+ SFV_CREATE sfvparams = {sizeof(SFV_CREATE), this};
+ hr = SHCreateShellFolderView(&sfvparams, (IShellView**)ppvOut);
}
TRACE ("-- (%p)->(interface=%p)\n", this, ppvOut);
return hr;
else if (_ILIsControlPanel(apidl[i]))
*rgfInOut &= dwControlPanelAttributes;
else if (_ILIsSpecialFolder(*apidl))
- SHELL32_GetGuidItemAttributes(this, apidl[i], rgfInOut);
+ m_regFolder->GetAttributesOf(1, &apidl[i], rgfInOut);
else
ERR("Got unknown pidl type!\n");
}
UINT cidl, PCUITEMID_CHILD_ARRAY apidl,
REFIID riid, UINT *prgfInOut, LPVOID *ppvOut)
{
- LPITEMIDLIST pidl;
- IUnknown *pObj = NULL;
+ LPVOID pObj = NULL;
HRESULT hr = E_INVALIDARG;
TRACE("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n", this,
if (IsEqualIID (riid, IID_IContextMenu) && (cidl >= 1))
{
- hr = CDefFolderMenu_Create2(pidlRoot, hwndOwner, cidl, apidl, (IShellFolder*)this, NULL, 0, NULL, (IContextMenu**)&pObj);
+ if (_ILIsDrive(apidl[0]))
+ hr = CDrivesContextMenu_CreateInstance(pidlRoot, hwndOwner, cidl, apidl, static_cast<IShellFolder*>(this), (IContextMenu**)&pObj);
+ else
+ hr = m_regFolder->GetUIObjectOf(hwndOwner, cidl, apidl, riid, prgfInOut, &pObj);
}
else if (IsEqualIID (riid, IID_IDataObject) && (cidl >= 1))
{
hr = IDataObject_Constructor (hwndOwner,
pidlRoot, apidl, cidl, (IDataObject **)&pObj);
}
- else if (IsEqualIID (riid, IID_IExtractIconA) && (cidl == 1))
- {
- pidl = ILCombine (pidlRoot, apidl[0]);
- pObj = IExtractIconA_Constructor (pidl);
- SHFree (pidl);
- hr = S_OK;
- }
- else if (IsEqualIID (riid, IID_IExtractIconW) && (cidl == 1))
- {
- pidl = ILCombine (pidlRoot, apidl[0]);
- pObj = IExtractIconW_Constructor (pidl);
- SHFree (pidl);
- hr = S_OK;
- }
- else if (IsEqualIID (riid, IID_IDropTarget) && (cidl >= 1))
+ else if ((IsEqualIID (riid, IID_IExtractIconA) || IsEqualIID (riid, IID_IExtractIconW)) && (cidl == 1))
{
- IDropTarget * pDt = NULL;
- hr = this->QueryInterface(IID_PPV_ARG(IDropTarget, &pDt));
- pObj = pDt;
+ if (_ILIsDrive(apidl[0]))
+ hr = CDrivesExtractIcon_CreateInstance(this, apidl[0], riid, &pObj);
+ else
+ hr = m_regFolder->GetUIObjectOf(hwndOwner, cidl, apidl, riid, prgfInOut, &pObj);
}
- else if ((IsEqualIID(riid, IID_IShellLinkW) ||
- IsEqualIID(riid, IID_IShellLinkA)) && (cidl == 1))
+ else if (IsEqualIID (riid, IID_IDropTarget) && (cidl == 1))
{
- pidl = ILCombine (pidlRoot, apidl[0]);
- hr = IShellLink_ConstructFromFile(NULL, riid, pidl, (LPVOID*) &pObj);
- SHFree (pidl);
+ CComPtr<IShellFolder> psfChild;
+ hr = this->BindToObject(apidl[0], NULL, IID_PPV_ARG(IShellFolder, &psfChild));
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+
+ return psfChild->CreateViewObject(NULL, riid, ppvOut);
}
else
hr = E_NOINTERFACE;
{
return SHELL32_GetDisplayNameOfChild(this, pidl, dwFlags, strRet);
}
- else if (!_ILIsDesktop(pidl) && _ILIsSpecialFolder(pidl))
+ else if (_ILIsSpecialFolder(pidl))
{
- return SHELL32_GetDisplayNameOfGUIDItem(this, L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}", pidl, dwFlags, strRet);
+ return m_regFolder->GetDisplayNameOf(pidl, dwFlags, strRet);
}
- else if (pidl->mkid.cb && !_ILIsDrive(pidl))
+ else if (!_ILIsDrive(pidl))
{
ERR("Wrong pidl type\n");
return E_INVALIDARG;
pszPath[0] = 0;
- if (!pidl->mkid.cb)
- {
- /* parsing name like ::{...} */
- pszPath[0] = ':';
- pszPath[1] = ':';
- SHELL32_GUIDToStringW(CLSID_MyComputer, &pszPath[2]);
- }
- else
+ _ILSimpleGetTextW(pidl, pszPath, MAX_PATH); /* append my own path */
+ /* long view "lw_name (C:)" */
+ if (!(dwFlags & SHGDN_FORPARSING))
{
- _ILSimpleGetTextW(pidl, pszPath, MAX_PATH); /* append my own path */
- /* long view "lw_name (C:)" */
- if (!(dwFlags & SHGDN_FORPARSING))
+ WCHAR wszDrive[18] = {0};
+ DWORD dwVolumeSerialNumber, dwMaximumComponentLength, dwFileSystemFlags;
+ static const WCHAR wszOpenBracket[] = {' ', '(', 0};
+ static const WCHAR wszCloseBracket[] = {')', 0};
+
+ lstrcpynW(wszDrive, pszPath, 4);
+ pszPath[0] = L'\0';
+ GetVolumeInformationW(wszDrive, pszPath,
+ MAX_PATH - 7,
+ &dwVolumeSerialNumber,
+ &dwMaximumComponentLength, &dwFileSystemFlags, NULL, 0);
+ pszPath[MAX_PATH-1] = L'\0';
+ if (!wcslen(pszPath))
{
- WCHAR wszDrive[18] = {0};
- DWORD dwVolumeSerialNumber, dwMaximumComponentLength, dwFileSystemFlags;
- static const WCHAR wszOpenBracket[] = {' ', '(', 0};
- static const WCHAR wszCloseBracket[] = {')', 0};
-
- lstrcpynW(wszDrive, pszPath, 4);
- pszPath[0] = L'\0';
- GetVolumeInformationW(wszDrive, pszPath,
- MAX_PATH - 7,
- &dwVolumeSerialNumber,
- &dwMaximumComponentLength, &dwFileSystemFlags, NULL, 0);
- pszPath[MAX_PATH-1] = L'\0';
- if (!wcslen(pszPath))
+ UINT DriveType, ResourceId;
+ DriveType = GetDriveTypeW(wszDrive);
+ switch(DriveType)
{
- UINT DriveType, ResourceId;
- DriveType = GetDriveTypeW(wszDrive);
- switch(DriveType)
- {
- case DRIVE_FIXED:
- ResourceId = IDS_DRIVE_FIXED;
- break;
- case DRIVE_REMOTE:
- ResourceId = IDS_DRIVE_NETWORK;
- break;
- case DRIVE_CDROM:
- ResourceId = IDS_DRIVE_CDROM;
- break;
- default:
- ResourceId = 0;
- }
- if (ResourceId)
- {
- dwFileSystemFlags = LoadStringW(shell32_hInstance, ResourceId, pszPath, MAX_PATH);
- if (dwFileSystemFlags > MAX_PATH - 7)
- pszPath[MAX_PATH-7] = L'\0';
- }
+ case DRIVE_FIXED:
+ ResourceId = IDS_DRIVE_FIXED;
+ break;
+ case DRIVE_REMOTE:
+ ResourceId = IDS_DRIVE_NETWORK;
+ break;
+ case DRIVE_CDROM:
+ ResourceId = IDS_DRIVE_CDROM;
+ break;
+ default:
+ ResourceId = 0;
+ }
+ if (ResourceId)
+ {
+ dwFileSystemFlags = LoadStringW(shell32_hInstance, ResourceId, pszPath, MAX_PATH);
+ if (dwFileSystemFlags > MAX_PATH - 7)
+ pszPath[MAX_PATH-7] = L'\0';
}
- wcscat (pszPath, wszOpenBracket);
- wszDrive[2] = L'\0';
- wcscat (pszPath, wszDrive);
- wcscat (pszPath, wszCloseBracket);
}
+ wcscat (pszPath, wszOpenBracket);
+ wszDrive[2] = L'\0';
+ wcscat (pszPath, wszDrive);
+ wcscat (pszPath, wszCloseBracket);
}
if (SUCCEEDED(hr))
return S_OK;
}
- return SHELL32_SetNameOfGuidItem(pidl, lpName, dwFlags, pPidlOut);
+ return m_regFolder->SetNameOf(hwndOwner, pidl, lpName, dwFlags, pPidlOut);
}
HRESULT WINAPI CDrivesFolder::GetDefaultSearchGUID(GUID * pguid)
return E_NOTIMPL;
}
-/* FIXME: drive size >4GB is rolling over */
HRESULT WINAPI CDrivesFolder::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *psd)
{
HRESULT hr;
{
psd->fmt = MyComputerSFHeader[iColumn].fmt;
psd->cxChar = MyComputerSFHeader[iColumn].cxChar;
- psd->str.uType = STRRET_CSTR;
- LoadStringA(shell32_hInstance, MyComputerSFHeader[iColumn].colnameid,
- psd->str.cStr, MAX_PATH);
- return S_OK;
+ return SHSetStrRet(&psd->str, MyComputerSFHeader[iColumn].colnameid);
}
- else if (_ILIsSpecialFolder(pidl))
+ else if (!_ILIsDrive(pidl))
{
- return SHELL32_GetDetailsOfGuidItem(this, pidl, iColumn, psd);
+ return m_regFolder->GetDetailsOf(pidl, iColumn, psd);
}
else
{
- char szPath[MAX_PATH];
- ULARGE_INTEGER ulBytes;
+ ULARGE_INTEGER ulTotalBytes, ulFreeBytes;
+ CHAR* pszDrive = _ILGetDataPointer(pidl)->u.drive.szDriveName;
+ UINT DriveType = GetDriveTypeA(pszDrive);
+ if (DriveType > DRIVE_RAMDISK)
+ DriveType = DRIVE_FIXED;
- psd->str.cStr[0] = 0x00;
- psd->str.uType = STRRET_CSTR;
switch (iColumn)
{
case 0: /* name */
hr = GetDisplayNameOf(pidl, SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str);
break;
- case 1: /* type */
- _ILGetFileType(pidl, psd->str.cStr, MAX_PATH);
+ case 1: /* FIXME: comments */
+ hr = SHSetStrRet(&psd->str, "");
break;
- case 2: /* total size */
- _ILSimpleGetText (pidl, szPath, MAX_PATH);
- if (GetVolumeInformationA(szPath, NULL, 0, NULL, NULL, NULL, NULL, 0))
- {
- GetDiskFreeSpaceExA(szPath, NULL, &ulBytes, NULL);
- StrFormatByteSize64A(ulBytes.QuadPart, psd->str.cStr, MAX_PATH);
- }
+ case 2: /* type */
+ hr = SHSetStrRet(&psd->str, iDriveTypeIds[DriveType]);
break;
- case 3: /* free size */
- _ILSimpleGetText (pidl, szPath, MAX_PATH);
- if (GetVolumeInformationA(szPath, NULL, 0, NULL, NULL, NULL, NULL, 0))
+ case 3: /* total size */
+ case 4: /* free size */
+ psd->str.cStr[0] = 0x00;
+ psd->str.uType = STRRET_CSTR;
+ if (GetVolumeInformationA(pszDrive, NULL, 0, NULL, NULL, NULL, NULL, 0))
{
- GetDiskFreeSpaceExA(szPath, &ulBytes, NULL, NULL);
- StrFormatByteSize64A(ulBytes.QuadPart, psd->str.cStr, MAX_PATH);
+ GetDiskFreeSpaceExA(pszDrive, &ulFreeBytes, &ulTotalBytes, NULL);
+ if (iColumn == 3)
+ StrFormatByteSize64A(ulTotalBytes.QuadPart, psd->str.cStr, MAX_PATH);
+ else
+ StrFormatByteSize64A(ulFreeBytes.QuadPart, psd->str.cStr, MAX_PATH);
}
+ hr = S_OK;
break;
}
- hr = S_OK;
}
return hr;
*/
HRESULT WINAPI CDrivesFolder::Initialize(LPCITEMIDLIST pidl)
{
- TRACE ("(%p)->(%p)\n", this, pidl);
-
- if (pidlRoot)
- SHFree((LPVOID)pidlRoot);
-
- pidlRoot = ILClone(pidl);
return S_OK;
}
/**************************************************************************
* CDrivesFolder::GetCurFolder
*/
-HRESULT WINAPI CDrivesFolder::GetCurFolder(LPITEMIDLIST *pidl)
+HRESULT WINAPI CDrivesFolder::GetCurFolder(PIDLIST_ABSOLUTE *pidl)
{
TRACE("(%p)->(%p)\n", this, pidl);
if (!pidl)
- return E_POINTER;
+ return E_INVALIDARG; /* xp doesn't have this check and crashes on NULL */
*pidl = ILClone(pidlRoot);
return S_OK;
}
+
+/************************************************************************/
+/* IContextMenuCB interface */
+
+HRESULT WINAPI CDrivesFolder::CallBack(IShellFolder *psf, HWND hwndOwner, IDataObject *pdtobj, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ if (uMsg != DFM_MERGECONTEXTMENU && uMsg != DFM_INVOKECOMMAND)
+ return S_OK;
+
+ /* no data object means no selection */
+ if (!pdtobj)
+ {
+ if (uMsg == DFM_INVOKECOMMAND && wParam == 1) // #1
+ {
+ // "System" properties
+ ShellExecuteW(hwndOwner,
+ NULL,
+ L"rundll32.exe",
+ L"shell32.dll,Control_RunDLL sysdm.cpl",
+ NULL,
+ SW_SHOWNORMAL);
+ }
+ else if (uMsg == DFM_MERGECONTEXTMENU)
+ {
+ QCMINFO *pqcminfo = (QCMINFO *)lParam;
+ HMENU hpopup = CreatePopupMenu();
+ _InsertMenuItemW(hpopup, 0, TRUE, 0, MFT_SEPARATOR, NULL, MFS_ENABLED); // #0
+ _InsertMenuItemW(hpopup, 1, TRUE, 1, MFT_STRING, MAKEINTRESOURCEW(IDS_PROPERTIES), MFS_ENABLED); // #1
+ Shell_MergeMenus(pqcminfo->hmenu, hpopup, pqcminfo->indexMenu++, pqcminfo->idCmdFirst, pqcminfo->idCmdLast, MM_ADDSEPARATOR);
+ DestroyMenu(hpopup);
+ }
+
+ return S_OK;
+ }
+
+ if (uMsg != DFM_INVOKECOMMAND || wParam != DFM_CMD_PROPERTIES)
+ return S_OK;
+
+ return Shell_DefaultContextMenuCallBack(this, pdtobj);
+}