diff --git a/dll/win32/shdocvw/CNSCBand.cpp b/dll/win32/shdocvw/CNSCBand.cpp index 636425e5433..a2ecb4830ef 100644 --- a/dll/win32/shdocvw/CNSCBand.cpp +++ b/dll/win32/shdocvw/CNSCBand.cpp @@ -87,6 +87,7 @@ CNSCBand::~CNSCBand() ImageList_Destroy(m_hToolbarImageList); m_hToolbarImageList = NULL; } + SHFree(m_OriginalRename); SHDOCVW_UnlockModule(); } @@ -132,10 +133,10 @@ SFGAOF CNSCBand::_GetAttributesOfItem(_In_ CItemData *pData, _In_ SFGAOF Query) return Attributes & Query; } -HRESULT CNSCBand::_GetNameOfItem(IShellFolder *pSF, PCUITEMID_CHILD pidl, PWSTR Name) +HRESULT CNSCBand::_GetNameOfItem(IShellFolder *pSF, PCUITEMID_CHILD pidl, UINT Flags, PWSTR Name) { STRRET strret; - HRESULT hr = pSF->GetDisplayNameOf(pidl, SHGDN_INFOLDER, &strret); + HRESULT hr = pSF->GetDisplayNameOf(pidl, Flags, &strret); if (FAILED_UNEXPECTEDLY(hr)) return hr; hr = StrRetToBufW(&strret, pidl, Name, MAX_PATH); @@ -144,6 +145,11 @@ HRESULT CNSCBand::_GetNameOfItem(IShellFolder *pSF, PCUITEMID_CHILD pidl, PWSTR return hr; } +HRESULT CNSCBand::_GetNameOfItem(IShellFolder *pSF, PCUITEMID_CHILD pidl, PWSTR Name) +{ + return _GetNameOfItem(pSF, pidl, SHGDN_NORMAL | SHGDN_INFOLDER, Name); +} + static HRESULT SHDOCVW_GetCurrentLocationFromView(_In_ IShellView& View, _In_ PIDLIST_ABSOLUTE *ppidl) { @@ -798,23 +804,31 @@ LRESULT CNSCBand::OnBeginLabelEdit(_In_ LPNMTVDISPINFO dispInfo) CComPtr pParent; LPCITEMIDLIST pChild; HRESULT hr; + HWND hWndEdit = TreeView_GetEditControl(dispInfo->hdr.hwndFrom); + SHFree(m_OriginalRename); + m_OriginalRename = NULL; CItemData *info = _GetItemData(dispInfo->item.hItem); - if (!info) - return FALSE; + if (!info || !hWndEdit) + return TRUE; hr = SHBindToParent(info->absolutePidl, IID_PPV_ARG(IShellFolder, &pParent), &pChild); if (FAILED_UNEXPECTEDLY(hr)) - return FALSE; + return TRUE; hr = pParent->GetAttributesOf(1, &pChild, &dwAttr); if (SUCCEEDED(hr) && (dwAttr & SFGAO_CANRENAME)) { + WCHAR szName[MAX_PATH]; + if (SUCCEEDED(_GetNameOfItem(pParent, pChild, SHGDN_FOREDITING | SHGDN_INFOLDER, szName))) + { + ::SetWindowTextW(hWndEdit, szName); + SHStrDupW(szName, &m_OriginalRename); + } m_isEditing = TRUE; m_oldSelected = NULL; return FALSE; } - return TRUE; } @@ -861,6 +875,15 @@ LRESULT CNSCBand::OnEndLabelEdit(_In_ LPNMTVDISPINFO dispInfo) if (!dispInfo->item.pszText) return FALSE; + if (m_OriginalRename) + { + BOOL same = !lstrcmpW(m_OriginalRename, dispInfo->item.pszText); // Case-sensitive + SHFree(m_OriginalRename); + m_OriginalRename = NULL; + if (same) + return FALSE; + } + CComPtr pParent; LPCITEMIDLIST pidlChild; BOOL RenamedCurrent = _IsCurrentLocation(info->absolutePidl) == S_OK; @@ -1297,7 +1320,8 @@ STDMETHODIMP CNSCBand::HasFocusIO() STDMETHODIMP CNSCBand::TranslateAcceleratorIO(LPMSG lpMsg) { - if (lpMsg->message == WM_KEYDOWN && lpMsg->wParam == VK_F2 && !m_isEditing) + BOOL SkipAccelerators = m_isEditing || (!IsChild(lpMsg->hwnd) && lpMsg->hwnd != m_hWnd); + if (lpMsg->message == WM_KEYDOWN && lpMsg->wParam == VK_F2 && !SkipAccelerators) { if (HTREEITEM hItem = m_hwndTreeView.GetNextItem(NULL, TVGN_CARET)) { @@ -1310,7 +1334,7 @@ STDMETHODIMP CNSCBand::TranslateAcceleratorIO(LPMSG lpMsg) } } - if (lpMsg->message == WM_SYSKEYDOWN && lpMsg->wParam == VK_RETURN && !m_isEditing) + if (lpMsg->message == WM_SYSKEYDOWN && lpMsg->wParam == VK_RETURN && !SkipAccelerators) { CItemData *pItem = _GetItemData(TVGN_CARET); if (pItem && _GetAttributesOfItem(pItem, SFGAO_HASPROPSHEET)) diff --git a/dll/win32/shdocvw/CNSCBand.h b/dll/win32/shdocvw/CNSCBand.h index 52efb83efb9..bb686bc4823 100644 --- a/dll/win32/shdocvw/CNSCBand.h +++ b/dll/win32/shdocvw/CNSCBand.h @@ -44,6 +44,7 @@ public: CItemData* _GetItemData(_In_ HTREEITEM hItem); CItemData* _GetItemData(_In_ UINT ItemSpec = TVGN_CARET); SFGAOF _GetAttributesOfItem(_In_ CItemData *pData, _In_ SFGAOF Query); + HRESULT _GetNameOfItem(IShellFolder *pSF, PCUITEMID_CHILD pidl, UINT Flags, PWSTR Name); HRESULT _GetNameOfItem(IShellFolder *pSF, PCUITEMID_CHILD pidl, PWSTR Name); // *** IOleWindow methods *** @@ -147,6 +148,7 @@ protected: HTREEITEM m_oldSelected = NULL; DWORD m_adviseCookie = 0; ULONG m_shellRegID = 0; + PWSTR m_OriginalRename = NULL; // *** Drop target information *** CComPtr m_pDropTarget; diff --git a/dll/win32/shell32/CDefView.cpp b/dll/win32/shell32/CDefView.cpp index 0833e5c38fc..66b8fb8dc70 100644 --- a/dll/win32/shell32/CDefView.cpp +++ b/dll/win32/shell32/CDefView.cpp @@ -2781,45 +2781,45 @@ LRESULT CDefView::OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandl break; case LVN_BEGINLABELEDITW: { - DWORD dwAttr = SFGAO_CANRENAME; - pidl = _PidlByItem(lpdi->item); - TRACE("-- LVN_BEGINLABELEDITW %p\n", this); - - m_pSFParent->GetAttributesOf(1, &pidl, &dwAttr); - if (SFGAO_CANRENAME & dwAttr) + HWND hEdit = ListView_GetEditControl(m_ListView); + pidl = _PidlByItem(lpdi->item); + DWORD fAttr = pidl ? GetItemAttributes(pidl, SFGAO_CANRENAME | SFGAO_FOLDER | SFGAO_FILESYSTEM) : 0; + if (!hEdit || !(fAttr & SFGAO_CANRENAME)) { - HWND hEdit = reinterpret_cast(m_ListView.SendMessage(LVM_GETEDITCONTROL)); - SHLimitInputEdit(hEdit, m_pSFParent); - - // smartass-renaming: See CORE-15242 - if (!(dwAttr & SFGAO_FOLDER) && (dwAttr & SFGAO_FILESYSTEM) && - (lpdi->item.mask & LVIF_TEXT) && !SelectExtOnRename()) - { - WCHAR szFullPath[MAX_PATH]; - PIDLIST_ABSOLUTE pidlFull = ILCombine(m_pidlParent, pidl); - SHGetPathFromIDListW(pidlFull, szFullPath); - - INT cchLimit = 0; - _DoFolderViewCB(SFVM_GETNAMELENGTH, (WPARAM)pidlFull, (LPARAM)&cchLimit); - if (cchLimit) - ::SendMessageW(hEdit, EM_SETLIMITTEXT, cchLimit, 0); - - if (!SHELL_FS_HideExtension(szFullPath)) - { - LPWSTR pszText = lpdi->item.pszText; - LPWSTR pchDotExt = PathFindExtensionW(pszText); - ::PostMessageW(hEdit, EM_SETSEL, 0, pchDotExt - pszText); - ::PostMessageW(hEdit, EM_SCROLLCARET, 0, 0); - } - - ILFree(pidlFull); - } - - m_isEditing = TRUE; - return FALSE; + MessageBeep(0xffffffff); + return TRUE; } - return TRUE; + + WCHAR szName[MAX_PATH], *pszText = lpdi->item.pszText; + if (SUCCEEDED(Shell_DisplayNameOf(m_pSFParent, pidl, SHGDN_FOREDITING | SHGDN_INFOLDER, + szName, _countof(szName)))) + { + pszText = szName; + ::SetWindowText(hEdit, pszText); + } + + // smartass-renaming: See CORE-15242 + if (!(fAttr & SFGAO_FOLDER) && (fAttr & SFGAO_FILESYSTEM) && + (lpdi->item.mask & LVIF_TEXT) && !SelectExtOnRename()) + { + CComHeapPtr pidlFull(ILCombine(m_pidlParent, pidl)); + WCHAR szFullPath[MAX_PATH]; + if (SHGetPathFromIDListW(pidlFull, szFullPath) && !SHELL_FS_HideExtension(szFullPath)) + { + LPWSTR pchDotExt = PathFindExtensionW(pszText); + ::PostMessageW(hEdit, EM_SETSEL, 0, pchDotExt - pszText); + ::PostMessageW(hEdit, EM_SCROLLCARET, 0, 0); + } + } + + INT cchLimit = 0; + _DoFolderViewCB(SFVM_GETNAMELENGTH, (WPARAM)pidl, (LPARAM)&cchLimit); + if (cchLimit) + ::SendMessageW(hEdit, EM_SETLIMITTEXT, cchLimit, 0); + SHLimitInputEdit(hEdit, m_pSFParent); + m_isEditing = TRUE; + return FALSE; } case LVN_ENDLABELEDITW: { diff --git a/dll/win32/shell32/dialogs/drvdefext.cpp b/dll/win32/shell32/dialogs/drvdefext.cpp index a56efd13c2b..fe470dbd08e 100644 --- a/dll/win32/shell32/dialogs/drvdefext.cpp +++ b/dll/win32/shell32/dialogs/drvdefext.cpp @@ -573,11 +573,15 @@ CDrvDefExt::GeneralPageProc( if (lppsn->hdr.code == PSN_APPLY) { CDrvDefExt *pDrvDefExt = reinterpret_cast(GetWindowLongPtr(hwndDlg, DWLP_USER)); - WCHAR wszBuf[256]; - if (GetDlgItemTextW(hwndDlg, 14000, wszBuf, _countof(wszBuf))) - SetVolumeLabelW(pDrvDefExt->m_wszDrive, wszBuf); - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR); + HRESULT hr = E_FAIL; + HWND hLabel = GetDlgItem(hwndDlg, 14000); + WCHAR wszBuf[256]; + *wszBuf = UNICODE_NULL; + if (GetWindowTextW(hLabel, wszBuf, _countof(wszBuf)) || GetWindowTextLengthW(hLabel) == 0) + hr = CDrivesFolder::SetDriveLabel(hwndDlg, pDrvDefExt->m_wszDrive, wszBuf); + + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, FAILED(hr) ? PSNRET_INVALID : PSNRET_NOERROR); return TRUE; } } diff --git a/dll/win32/shell32/folders/CDrivesFolder.cpp b/dll/win32/shell32/folders/CDrivesFolder.cpp index df2f591b8bc..9d82c5ce8e9 100644 --- a/dll/win32/shell32/folders/CDrivesFolder.cpp +++ b/dll/win32/shell32/folders/CDrivesFolder.cpp @@ -78,6 +78,27 @@ static const CLSID* IsRegItem(PCUITEMID_CHILD pidl) return NULL; } +static INT8 GetDriveNumber(PCUITEMID_CHILD pidl) +{ + if (!_ILIsDrive(pidl)) + return -1; + BYTE letter = ((PIDLDATA*)pidl->mkid.abID)->u.drive.szDriveName[0]; + BYTE number = (letter | 32) - 'a'; + return number < 26 ? number : -1; +} + +template static T* GetDrivePath(PCUITEMID_CHILD pidl, T *Path) +{ + int number = GetDriveNumber(pidl); + if (number < 0) + return NULL; + Path[0] = 'A' + number; + Path[1] = ':'; + Path[2] = '\\'; + Path[3] = '\0'; + return Path; +} + BOOL _ILGetDriveType(LPCITEMIDLIST pidl) { WCHAR szDrive[8]; @@ -409,7 +430,7 @@ getIconLocationForDrive(IShellFolder *psf, PCITEMID_CHILD pidl, UINT uFlags, } static HRESULT -getLabelForDrive(LPWSTR wszPath, LPWSTR wszLabel) +getLabelForDriveFromAutoRun(PCWSTR wszPath, LPWSTR szLabel, UINT cchMax) { WCHAR wszAutoRunInfPath[MAX_PATH]; WCHAR wszTemp[MAX_PATH]; @@ -423,13 +444,26 @@ getLabelForDrive(LPWSTR wszPath, LPWSTR wszLabel) if (GetPrivateProfileStringW(L"autorun", L"label", NULL, wszTemp, _countof(wszTemp), wszAutoRunInfPath) && wszTemp[0] != 0) { - StringCchCopyW(wszLabel, _countof(wszTemp), wszTemp); + StringCchCopyW(szLabel, cchMax, wszTemp); return S_OK; } return E_FAIL; } +static inline HRESULT GetRawDriveLabel(PCWSTR DrivePath, LPWSTR szLabel, UINT cchMax) +{ + if (GetVolumeInformationW(DrivePath, szLabel, cchMax, NULL, NULL, NULL, NULL, 0)) + return *szLabel ? S_OK : S_FALSE; + return HResultFromWin32(GetLastError()); +} + +static HRESULT GetDriveLabel(PCWSTR DrivePath, LPWSTR szLabel, UINT cchMax) +{ + HRESULT hr = getLabelForDriveFromAutoRun(DrivePath, szLabel, cchMax); + return hr == S_OK ? S_OK : GetRawDriveLabel(DrivePath, szLabel, cchMax); +} + BOOL IsDriveFloppyA(LPCSTR pszDriveRoot); HRESULT CDrivesExtractIcon_CreateInstance(IShellFolder * psf, LPCITEMIDLIST pidl, REFIID riid, LPVOID * ppvOut) @@ -562,6 +596,7 @@ static const DWORD dwDriveAttributes = CDrivesFolder::CDrivesFolder() { pidlRoot = NULL; + m_DriveDisplayMode = -1; } CDrivesFolder::~CDrivesFolder() @@ -947,8 +982,7 @@ HRESULT WINAPI CDrivesFolder::GetUIObjectOf(HWND hwndOwner, */ HRESULT WINAPI CDrivesFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet) { - LPWSTR pszPath; - HRESULT hr = S_OK; + WCHAR szDrive[8]; TRACE("(%p)->(pidl=%p,0x%08x,%p)\n", this, pidl, dwFlags, strRet); pdump (pidl); @@ -964,81 +998,76 @@ HRESULT WINAPI CDrivesFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFla { return m_regFolder->GetDisplayNameOf(pidl, dwFlags, strRet); } - else if (!_ILIsDrive(pidl)) + else if (!GetDrivePath(pidl, szDrive)) { ERR("Wrong pidl type\n"); return E_INVALIDARG; } - pszPath = (LPWSTR)CoTaskMemAlloc((MAX_PATH + 1) * sizeof(WCHAR)); + PWSTR pszPath = (LPWSTR)CoTaskMemAlloc((MAX_PATH + 1) * sizeof(WCHAR)); if (!pszPath) return E_OUTOFMEMORY; + pszPath[0] = UNICODE_NULL; + szDrive[0] &= ~32; // Always uppercase - pszPath[0] = 0; - - _ILSimpleGetTextW(pidl, pszPath, MAX_PATH); /* append my own path */ /* long view "lw_name (C:)" */ + BOOL bEditLabel = GET_SHGDN_RELATION(dwFlags) == SHGDN_INFOLDER && (dwFlags & SHGDN_FOREDITING); if (!(dwFlags & SHGDN_FORPARSING)) { - WCHAR wszDrive[18] = {0}; - - lstrcpynW(wszDrive, pszPath, 4); - pszPath[0] = L'\0'; - - if (!SUCCEEDED(getLabelForDrive(wszDrive, pszPath))) + if (m_DriveDisplayMode < 0) { - DWORD dwVolumeSerialNumber, dwMaximumComponentLength, dwFileSystemFlags; + DWORD err, type, data, cb = sizeof(data); + err = SHRegGetUSValueW(L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer", + L"ShowDriveLettersFirst", &type, &data, &cb, FALSE, NULL, 0); + m_DriveDisplayMode = (!err && type == REG_DWORD && cb == sizeof(data)) ? (BYTE)data : 0; + } + BOOL bRemoteFirst = m_DriveDisplayMode == 1; + BOOL bNoLetter = m_DriveDisplayMode == 2; + BOOL bAllFirst = m_DriveDisplayMode == 4; + PWSTR pszLabel = pszPath; - GetVolumeInformationW(wszDrive, pszPath, - MAX_PATH - 7, - &dwVolumeSerialNumber, - &dwMaximumComponentLength, &dwFileSystemFlags, NULL, 0); - pszPath[MAX_PATH-1] = L'\0'; + if (!bNoLetter && (bAllFirst || (bRemoteFirst && GetDriveTypeW(szDrive) == DRIVE_REMOTE))) + { + bNoLetter = TRUE; // Handling the letter now, don't append it again later + if (!bEditLabel) + pszLabel += wsprintfW(pszPath, L"(%c:) ", szDrive[0]); + } - if (!wcslen(pszPath)) + if (GetDriveLabel(szDrive, pszLabel, MAX_PATH - 7) != S_OK && !bEditLabel) + { + UINT ResourceId = 0; + switch (GetDriveTypeW(szDrive)) { - 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_REMOVABLE: ResourceId = IDS_DRIVE_REMOVABLE; break; // TODO: Floppy (cached) + case DRIVE_FIXED: ResourceId = IDS_DRIVE_FIXED; break; + case DRIVE_REMOTE: ResourceId = IDS_DRIVE_NETWORK; break; + case DRIVE_CDROM: ResourceId = IDS_DRIVE_CDROM; break; + } + if (ResourceId) + { + UINT len = LoadStringW(shell32_hInstance, ResourceId, pszLabel, MAX_PATH - 7); + if (len > MAX_PATH - 7) + pszLabel[MAX_PATH-7] = UNICODE_NULL; } } - wcscat(pszPath, L" ("); - wszDrive[2] = L'\0'; - wcscat(pszPath, wszDrive); - wcscat(pszPath, L")"); + + if (!*pszLabel && !bEditLabel) // No label nor fallback description, use SHGDN_FORPARSING + *pszPath = UNICODE_NULL; + else if (!bNoLetter && !bEditLabel) + wsprintfW(pszPath + wcslen(pszPath), L" (%c:)", szDrive[0]); } - if (SUCCEEDED(hr)) + if (!*pszPath && !bEditLabel) // SHGDN_FORPARSING or failure above (except editing empty label) { - strRet->uType = STRRET_WSTR; - strRet->pOleStr = pszPath; + if (GET_SHGDN_RELATION(dwFlags) == SHGDN_INFOLDER) + szDrive[2] = UNICODE_NULL; // Remove backslash + wcscpy(pszPath, szDrive); } - else - CoTaskMemFree(pszPath); + strRet->uType = STRRET_WSTR; + strRet->pOleStr = pszPath; TRACE("-- (%p)->(%s)\n", this, strRet->uType == STRRET_CSTR ? strRet->cStr : debugstr_w(strRet->pOleStr)); - return hr; + return S_OK; } /************************************************************************** @@ -1056,20 +1085,27 @@ HRESULT WINAPI CDrivesFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFla HRESULT WINAPI CDrivesFolder::SetNameOf(HWND hwndOwner, PCUITEMID_CHILD pidl, LPCOLESTR lpName, DWORD dwFlags, PITEMID_CHILD *pPidlOut) { - WCHAR szName[30]; - if (_ILIsDrive(pidl)) { - if (_ILSimpleGetTextW(pidl, szName, _countof(szName))) - SetVolumeLabelW(szName, lpName); + WCHAR szDrive[8]; + HRESULT hr = GetDrivePath(pidl, szDrive) ? SetDriveLabel(hwndOwner, szDrive, lpName) : E_FAIL; if (pPidlOut) - *pPidlOut = _ILCreateDrive(szName); - return S_OK; + *pPidlOut = SUCCEEDED(hr) ? _ILCreateDrive(szDrive) : NULL; + return hr; } - return m_regFolder->SetNameOf(hwndOwner, pidl, lpName, dwFlags, pPidlOut); } +HRESULT CDrivesFolder::SetDriveLabel(HWND hwndOwner, PCWSTR DrivePath, PCWSTR Label) +{ + HRESULT hr = SetVolumeLabelW(DrivePath, *Label ? Label : NULL) ? S_OK : HResultFromWin32(GetLastError()); + if (SUCCEEDED(hr)) + SHChangeNotify(SHCNE_RENAMEFOLDER, SHCNF_PATHW, DrivePath, DrivePath); // DisplayName changed + else if (hwndOwner) + SHELL_ErrorBox(hwndOwner, hr); + return hr; +} + HRESULT WINAPI CDrivesFolder::GetDefaultSearchGUID(GUID * pguid) { FIXME("(%p)\n", this); diff --git a/dll/win32/shell32/folders/CDrivesFolder.h b/dll/win32/shell32/folders/CDrivesFolder.h index a4222b88362..74cb2bef455 100644 --- a/dll/win32/shell32/folders/CDrivesFolder.h +++ b/dll/win32/shell32/folders/CDrivesFolder.h @@ -36,12 +36,15 @@ class CDrivesFolder : /* both paths are parsible from the desktop */ LPITEMIDLIST pidlRoot; /* absolute pidl */ CComPtr m_regFolder; + INT8 m_DriveDisplayMode; public: CDrivesFolder(); ~CDrivesFolder(); HRESULT WINAPI FinalConstruct(); + static HRESULT SetDriveLabel(HWND hwndOwner, PCWSTR DrivePath, PCWSTR Label); + // IShellFolder STDMETHOD(ParseDisplayName)(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName, DWORD *pchEaten, PIDLIST_RELATIVE *ppidl, DWORD *pdwAttributes) override; STDMETHOD(EnumObjects)(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList) override;