mirror of
https://github.com/reactos/reactos.git
synced 2026-05-30 05:51:26 +08:00
[SHELL32] Add SHFileOp error UI and use it for CFSFolder renaming (#7858)
This commit is contained in:
@@ -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
|
||||
{
|
||||
|
||||
@@ -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))
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user