[SHELL32] Add SHFileOp error UI and use it for CFSFolder renaming (#7858)

This commit is contained in:
Whindmar Saksit
2025-04-04 20:34:52 +02:00
committed by GitHub
parent 774b3a6e1d
commit ac3ecb2b2d
10 changed files with 225 additions and 84 deletions

View File

@@ -2821,8 +2821,8 @@ LRESULT CDefView::OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandl
}
WCHAR szName[MAX_PATH], *pszText = lpdi->item.pszText;
if (SUCCEEDED(Shell_DisplayNameOf(m_pSFParent, pidl, SHGDN_FOREDITING | SHGDN_INFOLDER,
szName, _countof(szName))))
if (SUCCEEDED(DisplayNameOfW(m_pSFParent, pidl, SHGDN_FOREDITING | SHGDN_INFOLDER,
szName, _countof(szName))))
{
pszText = szName;
::SetWindowText(hEdit, pszText);
@@ -2875,6 +2875,7 @@ LRESULT CDefView::OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandl
ILFree(pidlNew);// A SHCNE has updated the item already
else if (!LV_UpdateItem(lpdi->item.iItem, pidlNew))
ILFree(pidlNew);
OnStateChange(CDBOSC_RENAME);
}
else
{

View File

@@ -622,7 +622,7 @@ HRESULT CFSDropTarget::_DoDrop(IDataObject *pDataObject,
// If the target is a virtual item, we ask for the friendly name because SHGDN_FORPARSING will return a GUID.
BOOL UseParsing = (att & (SFGAO_FILESYSTEM | SFGAO_FOLDER)) == SFGAO_FILESYSTEM;
DWORD ShgdnFor = UseParsing ? SHGDN_FORPARSING : SHGDN_FOREDITING;
hr = Shell_DisplayNameOf(psfFrom, apidl[i], ShgdnFor | SHGDN_INFOLDER, targetName, _countof(targetName));
hr = DisplayNameOfW(psfFrom, apidl[i], ShgdnFor | SHGDN_INFOLDER, targetName, _countof(targetName));
}
if (FAILED_UNEXPECTEDLY(hr))
{

View File

@@ -1558,11 +1558,14 @@ HRESULT WINAPI CFSFolder::SetNameOf(
PITEMID_CHILD *pPidlOut)
{
WCHAR szSrc[MAX_PATH + 1], szDest[MAX_PATH + 1], szNameBuf[MAX_PATH];
BOOL bIsFolder = _ILIsFolder (ILFindLastID (pidl));
BOOL bIsFolder = ItemIsFolder(ILFindLastID(pidl));
TRACE ("(%p)->(%p,pidl=%p,%s,%u,%p)\n", this, hwndOwner, pidl,
debugstr_w (lpName), dwFlags, pPidlOut);
if (pPidlOut)
*pPidlOut = NULL;
LPCWSTR pszName = GetItemFileName(pidl, szNameBuf, _countof(szNameBuf));
if (!pszName)
{
@@ -1595,16 +1598,11 @@ HRESULT WINAPI CFSFolder::SetNameOf(
if (pPidlOut)
hr = SHILClone(pidl, pPidlOut);
}
else if (MoveFileW(szSrc, szDest))
{
if (pPidlOut)
hr = ParseDisplayName(hwndOwner, NULL, PathFindFileNameW(szDest), NULL, pPidlOut, NULL);
SHChangeNotify(bIsFolder ? SHCNE_RENAMEFOLDER : SHCNE_RENAMEITEM, SHCNF_PATHW, szSrc, szDest);
}
else
{
hr = HResultFromWin32(GetLastError());
hr = SHELL_SingleFileOperation(hwndOwner, FO_RENAME, szSrc, szDest, FOF_SILENT | FOF_ALLOWUNDO, NULL);
if (SUCCEEDED(hr) && pPidlOut)
hr = ParseDisplayName(hwndOwner, NULL, PathFindFileNameW(szDest), NULL, pPidlOut, NULL);
}
return hr;
}

View File

@@ -510,34 +510,26 @@ fail:
typedef struct _FILEOPDATA
{
PCUITEMID_CHILD_ARRAY apidl;
UINT cidl, index;
BBITEMDATA *pItem;
UINT cidl;
} FILEOPDATA;
static HRESULT CALLBACK FileOpCallback(FILEOPCALLBACKEVENT Event, LPCWSTR Src, LPCWSTR Dst, UINT Attrib, HRESULT hrOp, void *CallerData)
{
FILEOPDATA &data = *(FILEOPDATA*)CallerData;
if (Event == FOCE_PREMOVEITEM || Event == FOCE_PREDELETEITEM)
if ((Event == FOCE_POSTDELETEITEM || Event == FOCE_POSTMOVEITEM) && SUCCEEDED(hrOp))
{
data.pItem = NULL;
for (UINT i = 0; i < data.cidl; ++i)
{
BBITEMDATA *pItem = ValidateItem(data.apidl[i]);
if (pItem && !_wcsicmp(Src, GetItemRecycledFullPath(*pItem)))
{
data.pItem = pItem;
data.index = i;
RECYCLEBINFILEIDENTITY identity = { pItem->DeletionTime, GetItemRecycledFullPath(*pItem) };
RemoveFromRecycleBinDatabase(&identity);
CRecycleBin_NotifyRemovedFromRecycleBin(data.apidl[i]);
break;
}
}
}
else if ((Event == FOCE_POSTDELETEITEM || Event == FOCE_POSTMOVEITEM) && SUCCEEDED(hrOp) && data.pItem)
{
RECYCLEBINFILEIDENTITY identity = { data.pItem->DeletionTime, GetItemRecycledFullPath(*data.pItem) };
RemoveFromRecycleBinDatabase(&identity);
CRecycleBin_NotifyRemovedFromRecycleBin(data.apidl[data.index]);
data.pItem = NULL;
}
else if (Event == FOCE_FINISHOPERATIONS)
{
CComHeapPtr<ITEMIDLIST> pidlBB(SHCloneSpecialIDList(NULL, CSIDL_BITBUCKET, FALSE));

View File

@@ -242,14 +242,6 @@ BOOL Shell_FailForceReturn(_In_ HRESULT hr);
EXTERN_C INT
Shell_ParseSpecialFolder(_In_ LPCWSTR pszStart, _Out_ LPWSTR *ppch, _Out_ INT *pcch);
HRESULT
Shell_DisplayNameOf(
_In_ IShellFolder *psf,
_In_ LPCITEMIDLIST pidl,
_In_ DWORD dwFlags,
_Out_ LPWSTR pszBuf,
_In_ UINT cchBuf);
EXTERN_C
HRESULT SHBindToObject(
_In_opt_ IShellFolder *psf,
@@ -331,11 +323,18 @@ typedef enum _FILEOPCALLBACKEVENT {
FOCE_FINISHOPERATIONS,
FOCE_PREMOVEITEM,
FOCE_POSTMOVEITEM,
FOCE_PRECOPYITEM,
FOCE_POSTCOPYITEM,
FOCE_PREDELETEITEM,
FOCE_POSTDELETEITEM
FOCE_POSTDELETEITEM,
FOCE_PRERENAMEITEM,
FOCE_POSTRENAMEITEM,
FOCE_PRENEWITEM,
FOCE_POSTNEWITEM
} FILEOPCALLBACKEVENT;
typedef HRESULT (CALLBACK *FILEOPCALLBACK)(FILEOPCALLBACKEVENT Event, LPCWSTR Source, LPCWSTR Destination,
UINT Attributes, HRESULT hr, void *CallerData);
int SHELL32_FileOperation(LPSHFILEOPSTRUCTW lpFileOp, FILEOPCALLBACK Callback, void *CallerData);
HRESULT SHELL_SingleFileOperation(HWND hWnd, UINT Op, PCWSTR Src, PCWSTR Dest, UINT Flags, PWSTR *ppNewName);
#endif /* _PRECOMP_H__ */

View File

@@ -466,3 +466,4 @@
754 stub -noname SHLimitInputEditWithFlags
755 stdcall -noname PathIsEqualOrSubFolder(wstr wstr)
756 stub -noname DeleteFileThumbnail
757 stdcall -version=0x600+ DisplayNameOfW(ptr ptr long ptr long)

View File

@@ -47,6 +47,8 @@ typedef struct
WCHAR szBuilderString[50];
FILEOPCALLBACK Callback;
void *CallerCallbackData;
HWND hWndOwner;
BOOL bHasDisplayedError;
} FILE_OPERATION;
#define ERROR_SHELL_INTERNAL_FILE_NOT_FOUND 1026
@@ -84,6 +86,45 @@ static DWORD move_files(FILE_OPERATION *op, BOOL multiDest, const FILE_LIST *flF
DWORD WINAPI _FileOpCountManager(FILE_OPERATION *op, const FILE_LIST *flFrom);
static BOOL _FileOpCount(FILE_OPERATION *op, LPWSTR pwszBuf, BOOL bFolder, DWORD *ticks);
static HRESULT SHELL32_FileOpErrorToHResult(int err, BOOL AnyOperationsAborted = FALSE)
{
enum { de_min = DE_SAMEFILE, de_max = 0xB7 /*DE_ERROR_MAX*/ };
const bool IsDeErr = (err & ~ERRORONDEST) >= de_min && (err & ~ERRORONDEST) <= de_max;
if (err == DE_OPCANCELLED || AnyOperationsAborted)
return HRESULT_FROM_WIN32(ERROR_CANCELLED);
if (err == DE_ACCESSDENIEDSRC)
return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
if (err == DE_FILENAMETOOLONG)
return HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE);
if (err == ERROR_SHELL_INTERNAL_FILE_NOT_FOUND)
return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
if (err == ERROR_ALREADY_EXISTS)
return HRESULT_FROM_WIN32(err);
return IsDeErr ? E_FAIL : HRESULT_FROM_WIN32(err);
}
static BOOL CanShowFileOpErrorUI(const SHFILEOPSTRUCTW &fos)
{
if ((fos.fFlags & FOF_SILENT) && !fos.hwnd)
return FALSE;
return !(fos.fFlags & FOF_NOERRORUI);
}
static void HandleDesktopIniOp(PCWSTR Path)
{
// Refresh the parent folder if somebody changes the desktop.ini inside
PCWSTR Name = PathFindFileNameW(Path);
if ((Name[0] | 32) != 'd' || _wcsicmp(Name, L"desktop.ini"))
return;
WCHAR Dir[MAX_PATH];
if (FAILED_UNEXPECTEDLY(StringCchCopyW(Dir, _countof(Dir), Path)))
return;
PathRemoveFileSpecW(Dir);
if (!(GetFileAttributesW(Dir) & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_READONLY)))
return;
SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATHW, Dir, NULL);
}
/* Confirm dialogs with an optional "Yes To All" as used in file operations confirmations
*/
struct confirm_msg_info
@@ -366,6 +407,19 @@ EXTERN_C HRESULT WINAPI SHIsFileAvailableOffline(LPCWSTR path, LPDWORD status)
static HRESULT FileOpCallback(FILE_OPERATION *op, FILEOPCALLBACKEVENT Event, LPCWSTR Source,
LPCWSTR Destination, UINT Attributes, HRESULT hrOp = S_OK)
{
if ((Attributes & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM)) == FILE_ATTRIBUTE_SYSTEM)
{
if (Event == FOCE_POSTDELETEITEM)
HandleDesktopIniOp(Source);
if (Event == FOCE_POSTCOPYITEM)
HandleDesktopIniOp(Destination);
if (Event == FOCE_POSTMOVEITEM || Event == FOCE_POSTRENAMEITEM)
{
HandleDesktopIniOp(Source);
HandleDesktopIniOp(Destination);
}
}
HRESULT hr = S_OK;
if (op->Callback)
{
@@ -398,7 +452,7 @@ BOOL SHELL_DeleteDirectoryW(FILE_OPERATION *op, LPCWSTR pszDir, BOOL bShowUI)
if (FAILED(FileOpCallback(op, FOCE_PREDELETEITEM, pszDir, NULL, wfd.dwFileAttributes)))
return FALSE;
if (!bShowUI || (ret = SHELL_ConfirmDialogW(op->req->hwnd, ASK_DELETE_FOLDER, pszDir, NULL)))
if (!bShowUI || (ret = SHELL_ConfirmDialogW(op->hWndOwner, ASK_DELETE_FOLDER, pszDir, NULL)))
{
do
{
@@ -699,8 +753,8 @@ static DWORD CheckForError(FILE_OPERATION *op, DWORD error, LPCWSTR src)
CStringW strTitle, strMask, strText;
LPWSTR lpMsgBuffer;
if (error == ERROR_SUCCESS || (op->req->fFlags & (FOF_NOERRORUI | FOF_SILENT)))
goto exit;
if (error == ERROR_SUCCESS || !CanShowFileOpErrorUI(*op->req))
return error;
strTitle.LoadStringW(op->req->wFunc == FO_COPY ? IDS_COPYERRORTITLE : IDS_MOVEERRORTITLE);
@@ -716,10 +770,9 @@ static DWORD CheckForError(FILE_OPERATION *op, DWORD error, LPCWSTR src)
PathFindFileNameW(src),
lpMsgBuffer);
MessageBoxW(op->req->hwnd, strText, strTitle, MB_ICONERROR);
MessageBoxW(op->hWndOwner, strText, strTitle, MB_ICONERROR);
LocalFree(lpMsgBuffer);
exit:
op->bHasDisplayedError++;
return error;
}
@@ -744,8 +797,11 @@ static DWORD SHNotifyMoveFileW(FILE_OPERATION *op, LPCWSTR src, LPCWSTR dest, BO
_SetOperationTexts(op, src, dest);
UINT attrib = isdir ? FILE_ATTRIBUTE_DIRECTORY : FILE_ATTRIBUTE_NORMAL;
if (FAILED(FileOpCallback(op, FOCE_PREMOVEITEM, src, dest, attrib)))
const BOOL IsRen = op->req->wFunc == FO_RENAME;
UINT attrib = GetFileAttributesW(src);
if (attrib == INVALID_FILE_ATTRIBUTES)
attrib = isdir ? FILE_ATTRIBUTE_DIRECTORY : FILE_ATTRIBUTE_NORMAL;
if (FAILED(FileOpCallback(op, IsRen ? FOCE_PRERENAMEITEM : FOCE_PREMOVEITEM, src, dest, attrib)))
return ERROR_CANCELLED;
ret = MoveFileWithProgressW(src, dest, SHCopyProgressRoutine, op, MOVEFILE_REPLACE_EXISTING);
@@ -753,30 +809,41 @@ static DWORD SHNotifyMoveFileW(FILE_OPERATION *op, LPCWSTR src, LPCWSTR dest, BO
/* MOVEFILE_REPLACE_EXISTING fails with dirs, so try MoveFile */
if (!ret)
ret = MoveFileW(src, dest);
DWORD LastError = GetLastError();
if (!ret)
{
DWORD dwAttr;
dwAttr = SHFindAttrW(dest, FALSE);
if (INVALID_FILE_ATTRIBUTES == dwAttr)
{
/* Source file may be write protected or a system file */
dwAttr = GetFileAttributesW(src);
if (IsAttrib(dwAttr, FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM))
if (SetFileAttributesW(src, dwAttr & ~(FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM)))
ret = MoveFileW(src, dest);
}
DWORD dwAttr = SHFindAttrW(dest, FALSE);
if (INVALID_FILE_ATTRIBUTES == dwAttr)
{
/* Source file may be write protected or a system file */
dwAttr = GetFileAttributesW(src);
if (IsAttrib(dwAttr, FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM))
{
if (SetFileAttributesW(src, dwAttr & ~(FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM)))
{
ret = MoveFileW(src, dest);
LastError = GetLastError();
SetFileAttributesW(ret ? dest : src, dwAttr);
}
}
}
}
FileOpCallback(op, FOCE_POSTMOVEITEM, src, dest, attrib, ret ? S_OK : E_FAIL);
FileOpCallback(op, IsRen ? FOCE_POSTRENAMEITEM : FOCE_POSTMOVEITEM, src, dest, attrib, ret ? S_OK : E_FAIL);
if (ret)
{
SHChangeNotify(isdir ? SHCNE_MKDIR : SHCNE_CREATE, SHCNF_PATHW, dest, NULL);
SHChangeNotify(isdir ? SHCNE_RMDIR : SHCNE_DELETE, SHCNF_PATHW, src, NULL);
if (IsRen)
{
SHChangeNotify(isdir ? SHCNE_RENAMEFOLDER : SHCNE_RENAMEITEM, SHCNF_PATHW, src, dest);
}
else
{
SHChangeNotify(isdir ? SHCNE_MKDIR : SHCNE_CREATE, SHCNF_PATHW, dest, NULL);
SHChangeNotify(isdir ? SHCNE_RMDIR : SHCNE_DELETE, SHCNF_PATHW, src, NULL);
}
return ERROR_SUCCESS;
}
return CheckForError(op, GetLastError(), src);
return CheckForError(op, LastError, src);
}
static BOOL SHIsCdRom(LPCWSTR path)
@@ -819,6 +886,9 @@ static DWORD SHNotifyCopyFileW(FILE_OPERATION *op, LPCWSTR src, LPCWSTR dest, BO
/* Destination file may already exist with read only attribute */
attribs = GetFileAttributesW(dest);
if (FAILED(FileOpCallback(op, FOCE_PRECOPYITEM, src, dest, attribs)))
return ERROR_CANCELLED;
if (IsAttrib(attribs, FILE_ATTRIBUTE_READONLY))
SetFileAttributesW(dest, attribs & ~FILE_ATTRIBUTE_READONLY);
@@ -832,7 +902,9 @@ static DWORD SHNotifyCopyFileW(FILE_OPERATION *op, LPCWSTR src, LPCWSTR dest, BO
}
ret = CopyFileExW(src, dest, SHCopyProgressRoutine, op, &op->bCancelled, bFailIfExists);
if (ret)
const DWORD error = ret ? 0 : GetLastError();
FileOpCallback(op, FOCE_POSTCOPYITEM, src, dest, attribs, HRESULT_FROM_WIN32(error));
if (!error)
{
// We are copying from a CD-ROM volume, which is readonly
if (SHIsCdRom(src))
@@ -845,8 +917,7 @@ static DWORD SHNotifyCopyFileW(FILE_OPERATION *op, LPCWSTR src, LPCWSTR dest, BO
SHChangeNotify(SHCNE_CREATE, SHCNF_PATHW, dest, NULL);
return ERROR_SUCCESS;
}
return CheckForError(op, GetLastError(), src);
return CheckForError(op, error, src);
}
/*************************************************************************
@@ -1376,7 +1447,7 @@ static void copy_dir_to_dir(FILE_OPERATION *op, const FILE_ENTRY *feFrom, LPCWST
}
else if (!(op->req->fFlags & FOF_NOCONFIRMATION))
{
if (!SHELL_ConfirmDialogW(op->req->hwnd, ASK_OVERWRITE_FOLDER, feFrom->szFilename, op))
if (!SHELL_ConfirmDialogW(op->hWndOwner, ASK_OVERWRITE_FOLDER, feFrom->szFilename, op))
{
/* Vista returns an ERROR_CANCELLED even if user pressed "No" */
if (!op->bManyItems)
@@ -1417,7 +1488,7 @@ static BOOL copy_file_to_file(FILE_OPERATION *op, const WCHAR *szFrom, const WCH
}
else if (!(op->req->fFlags & FOF_NOCONFIRMATION))
{
if (!SHELL_ConfirmDialogW(op->req->hwnd, ASK_OVERWRITE_FILE, PathFindFileNameW(szTo), op))
if (!SHELL_ConfirmDialogW(op->hWndOwner, ASK_OVERWRITE_FILE, PathFindFileNameW(szTo), op))
return FALSE;
}
}
@@ -1629,7 +1700,7 @@ static HRESULT delete_files(FILE_OPERATION *op, const FILE_LIST *flFrom)
if (bTrash && SHELL_GetSetting(SSF_NOCONFIRMRECYCLE, fNoConfirmRecycle))
confirm = FALSE;
if (confirm || (!bTrash && op->req->fFlags & FOF_WANTNUKEWARNING))
if (!confirm_delete_list(op->req->hwnd, op->req->fFlags, bTrash, flFrom))
if (!confirm_delete_list(op->hWndOwner, op->req->fFlags, bTrash, flFrom))
{
op->req->fAnyOperationsAborted = TRUE;
return 0;
@@ -1669,7 +1740,7 @@ static HRESULT delete_files(FILE_OPERATION *op, const FILE_LIST *flFrom)
/* Note: Windows silently deletes the file in such a situation, we show a dialog */
if (!(op->req->fFlags & FOF_NOCONFIRMATION) || (op->req->fFlags & FOF_WANTNUKEWARNING))
bDelete = SHELL_ConfirmDialogW(op->req->hwnd, ASK_CANT_TRASH_ITEM, fileEntry->szFullPath, NULL);
bDelete = SHELL_ConfirmDialogW(op->hWndOwner, ASK_CANT_TRASH_ITEM, fileEntry->szFullPath, NULL);
else
bDelete = TRUE;
@@ -1762,7 +1833,7 @@ static BOOL move_file_to_file(FILE_OPERATION *op, const WCHAR *szFrom, const WCH
}
else if (!(op->req->fFlags & FOF_NOCONFIRMATION))
{
if (!SHELL_ConfirmDialogW(op->req->hwnd, ASK_OVERWRITE_FILE, PathFindFileNameW(szTo), op))
if (!SHELL_ConfirmDialogW(op->hWndOwner, ASK_OVERWRITE_FILE, PathFindFileNameW(szTo), op))
return FALSE;
}
}
@@ -1924,15 +1995,15 @@ static void check_flags(FILEOP_FLAGS fFlags)
#define GET_FILENAME(fe) ((fe)->szFilename[0] ? (fe)->szFilename : (fe)->szFullPath)
static DWORD
validate_operation(LPSHFILEOPSTRUCTW lpFileOp, FILE_LIST *flFrom, FILE_LIST *flTo)
validate_operation(FILE_OPERATION &op, FILE_LIST *flFrom, FILE_LIST *flTo)
{
DWORD i, k, dwNumDest;
WCHAR szFrom[MAX_PATH], szTo[MAX_PATH];
CStringW strTitle, strText;
const FILE_ENTRY *feFrom;
const FILE_ENTRY *feTo;
const SHFILEOPSTRUCTW *lpFileOp = op.req;
UINT wFunc = lpFileOp->wFunc;
HWND hwnd = lpFileOp->hwnd;
dwNumDest = flTo->dwNumFiles;
@@ -1956,7 +2027,7 @@ validate_operation(LPSHFILEOPSTRUCTW lpFileOp, FILE_LIST *flFrom, FILE_LIST *flT
if (lstrcmpiW(szFrom, szTo) == 0 &&
(wFunc == FO_MOVE || !(lpFileOp->fFlags & FOF_RENAMEONCOLLISION)))
{
if (!(lpFileOp->fFlags & (FOF_NOERRORUI | FOF_SILENT)))
if (CanShowFileOpErrorUI(*lpFileOp))
{
if (wFunc == FO_MOVE)
{
@@ -1972,7 +2043,8 @@ validate_operation(LPSHFILEOPSTRUCTW lpFileOp, FILE_LIST *flFrom, FILE_LIST *flT
strText.Format(IDS_COPYERRORSAME, GET_FILENAME(feFrom));
return ERROR_SUCCESS;
}
MessageBoxW(hwnd, strText, strTitle, MB_ICONERROR);
MessageBoxW(op.hWndOwner, strText, strTitle, MB_ICONERROR);
op.bHasDisplayedError++;
return DE_SAMEFILE;
}
return DE_OPCANCELLED;
@@ -1992,7 +2064,7 @@ validate_operation(LPSHFILEOPSTRUCTW lpFileOp, FILE_LIST *flFrom, FILE_LIST *flT
if (compare == 0)
{
if (!(lpFileOp->fFlags & (FOF_NOERRORUI | FOF_SILENT)))
if (CanShowFileOpErrorUI(*lpFileOp))
{
if (wFunc == FO_MOVE)
{
@@ -2004,7 +2076,8 @@ validate_operation(LPSHFILEOPSTRUCTW lpFileOp, FILE_LIST *flFrom, FILE_LIST *flT
strTitle.LoadStringW(IDS_COPYERRORTITLE);
strText.Format(IDS_COPYERRORSUBFOLDER, GET_FILENAME(feFrom));
}
MessageBoxW(hwnd, strText, strTitle, MB_ICONERROR);
MessageBoxW(op.hWndOwner, strText, strTitle, MB_ICONERROR);
op.bHasDisplayedError++;
return DE_DESTSUBTREE;
}
return DE_OPCANCELLED;
@@ -2049,8 +2122,9 @@ int SHELL32_FileOperation(LPSHFILEOPSTRUCTW lpFileOp, FILEOPCALLBACK Callback, v
op.bManyItems = (flFrom.dwNumFiles > 1);
op.Callback = Callback;
op.CallerCallbackData = CallerData;
op.hWndOwner = GetAncestor(lpFileOp->hwnd, GA_ROOT);
ret = validate_operation(lpFileOp, &flFrom, &flTo);
ret = validate_operation(op, &flFrom, &flTo);
if (ret)
goto cleanup;
@@ -2062,7 +2136,7 @@ int SHELL32_FileOperation(LPSHFILEOPSTRUCTW lpFileOp, FILEOPCALLBACK Callback, v
if (FAILED(ret))
goto cleanup;
op.progress->StartProgressDialog(op.req->hwnd, NULL, PROGDLG_NORMAL & PROGDLG_AUTOTIME, NULL);
op.progress->StartProgressDialog(op.hWndOwner, NULL, PROGDLG_NORMAL & PROGDLG_AUTOTIME, NULL);
_SetOperationTitle(&op);
_FileOpCountManager(&op, &flFrom);
}
@@ -2103,8 +2177,15 @@ cleanup:
if (ret == ERROR_CANCELLED)
lpFileOp->fAnyOperationsAborted = TRUE;
if (ret == ERROR_SHELL_INTERNAL_FILE_NOT_FOUND && LOBYTE(GetVersion()) >= 6)
ret = ERROR_FILE_NOT_FOUND;
FileOpCallback(&op, FOCE_FINISHOPERATIONS, NULL, NULL, 0, HRESULT_FROM_WIN32(ret));
HRESULT hr = SHELL32_FileOpErrorToHResult(ret);
TRACE("SHFO FINISHOPERATIONS %#x (%d)\n", hr, ret);
FileOpCallback(&op, FOCE_FINISHOPERATIONS, NULL, NULL, 0, hr);
if (FAILED(hr) && CanShowFileOpErrorUI(*op.req) && !op.bHasDisplayedError)
SHELL_ErrorBox(op.hWndOwner, hr);
CoUninitialize();
@@ -2350,6 +2431,59 @@ EXTERN_C HRESULT WINAPI SHPathPrepareForWriteA(HWND hwnd, IUnknown *modless, LPC
return SHPathPrepareForWriteW(hwnd, modless, wpath, flags);
}
static PWSTR SHELL_DupSZZ(PCWSTR Input)
{
SIZE_T len = wcslen(Input), cb = (len + 2) * sizeof(*Input);
PWSTR Output = (PWSTR)SHAlloc(cb);
if (Output)
{
CopyMemory(Output, Input, cb - sizeof(*Input));
Output[len + 1] = UNICODE_NULL;
}
return Output;
}
HRESULT SHELL_SingleFileOperation(HWND hWnd, UINT Op, PCWSTR Src, PCWSTR Dest, UINT Flags, PWSTR *ppNewName)
{
HRESULT hr = S_OK;
if ((Src = SHELL_DupSZZ(Src)) == NULL)
hr = E_OUTOFMEMORY;
if (Dest && (Dest = SHELL_DupSZZ(Dest)) == NULL)
hr = E_OUTOFMEMORY;
SHFILEOPSTRUCTW fos = { hWnd, Op, Src, Dest, (FILEOP_FLAGS)Flags };
if (ppNewName)
{
*ppNewName = NULL;
fos.fFlags |= FOF_WANTMAPPINGHANDLE;
}
if (SUCCEEDED(hr))
{
int err = SHFileOperationW(&fos);
hr = SHELL32_FileOpErrorToHResult(err, fos.fAnyOperationsAborted);
}
else if (CanShowFileOpErrorUI(fos))
{
SHELL_ErrorBox(hWnd, hr);
}
SHFree(const_cast<PWSTR>(Src));
SHFree(const_cast<PWSTR>(Dest));
if (fos.hNameMappings)
{
if (SUCCEEDED(hr) && ppNewName)
{
assert(DSA_GetItemCount((HDSA)fos.hNameMappings) == 1);
SHNAMEMAPPINGW *pMap = (SHNAMEMAPPINGW*)DSA_GetItemPtr((HDSA)fos.hNameMappings, 0);
if ((*ppNewName = SHELL_DupSZZ(pMap->pszNewPath)) == NULL)
hr = S_FALSE;
}
SHFreeNameMappings(fos.hNameMappings);
}
return hr;
}
/*
* The two following background operations were modified from filedefext.cpp

View File

@@ -402,8 +402,11 @@ SHELL_GetUIObjectOfAbsoluteItem(
return hr;
}
HRESULT
Shell_DisplayNameOf(
/***********************************************************************
* DisplayNameOfW [SHELL32.757] (Vista+)
*/
EXTERN_C HRESULT WINAPI
DisplayNameOfW(
_In_ IShellFolder *psf,
_In_ LPCITEMIDLIST pidl,
_In_ DWORD dwFlags,
@@ -492,7 +495,7 @@ SHGetNameAndFlagsW(
if (SUCCEEDED(hr))
{
if (pszText)
hr = Shell_DisplayNameOf(psfFolder, ppidlLast, dwFlags, pszText, cchBuf);
hr = DisplayNameOfW(psfFolder, ppidlLast, dwFlags, pszText, cchBuf);
if (SUCCEEDED(hr))
{

View File

@@ -1392,13 +1392,8 @@ Preview_Delete(PPREVIEW_DATA pData)
FileOp.pFrom = szCurFile;
FileOp.fFlags = GetKeyState(VK_SHIFT) < 0 ? 0 : FOF_ALLOWUNDO;
error = g_szFile[0] ? SHFileOperationW(&FileOp) : ERROR_FILE_NOT_FOUND;
if (error != 0)
{
enum { SHFO_FIRSTCUSTOMERROR = 0x71 /* DE_SAMEFILE */ };
if (!FileOp.fAnyOperationsAborted && error != ERROR_CANCELLED)
ErrorBox(FileOp.hwnd, error < SHFO_FIRSTCUSTOMERROR ? error : E_FAIL);
if (error)
return;
}
/* Reload the file list and go next file */
pFreeFileList(g_pCurrentFile);

View File

@@ -19,6 +19,15 @@
#ifndef __WINE_UNDOCSHELL_H
#define __WINE_UNDOCSHELL_H
#ifndef SHSTDAPI
#if defined(_SHELL32_) /* DECLSPEC_IMPORT disabled because of CORE-6504: */ || TRUE
#define SHSTDAPI_(type) type WINAPI
#else
#define SHSTDAPI_(type) EXTERN_C DECLSPEC_IMPORT type WINAPI
#endif
#define SHSTDAPI SHSTDAPI_(HRESULT)
#endif
#ifdef __cplusplus
extern "C" {
#endif /* defined(__cplusplus) */
@@ -78,6 +87,15 @@ BOOL WINAPI ILGetDisplayNameEx(
LPVOID path,
DWORD type);
#if (NTDDI_VERSION >= NTDDI_LONGHORN) || defined(_SHELL32_)
SHSTDAPI DisplayNameOfW(
_In_ IShellFolder *psf,
_In_ LPCITEMIDLIST pidl,
_In_ DWORD dwFlags,
_Out_ LPWSTR pszBuf,
_In_ UINT cchBuf);
#endif
LPITEMIDLIST WINAPI ILGlobalClone(LPCITEMIDLIST pidl);
void WINAPI ILGlobalFree(LPITEMIDLIST pidl);
LPITEMIDLIST WINAPI SHSimpleIDListFromPathA (LPCSTR lpszPath); //FIXME