📄 shlfileop.c
字号:
(bOnlySrc || (pszFiles2[0] != '\0')))
{
if (NULL == StrPBrkW(pszFiles1, wWildcardChars))
{
if (INVALID_FILE_ATTRIBUTES == GetFileAttributesW(pszFiles1))
return FALSE;
}
pszFiles1 += lstrlenW(pszFiles1) + 1;
if (!bOnlySrc)
pszFiles2 += lstrlenW(pszFiles2) + 1;
}
return ((pszFiles1[0] == '\0') && (bOnlySrc || (pszFiles2[0] == '\0')));
}
/*************************************************************************
*
* SHNameTranslate HelperFunction for SHFileOperationA
*
* Translates a list of 0 terminated ASCII strings into Unicode. If *wString
* is NULL, only the necessary size of the string is determined and returned,
* otherwise the ASCII strings are copied into it and the buffer is increased
* to point to the location after the final 0 termination char.
*/
DWORD SHNameTranslate(LPWSTR* wString, LPCWSTR* pWToFrom, BOOL more)
{
DWORD size = 0, aSize = 0;
LPCSTR aString = (LPCSTR)*pWToFrom;
if (aString)
{
do
{
size = lstrlenA(aString) + 1;
aSize += size;
aString += size;
} while ((size != 1) && more);
/* The two sizes might be different in the case of multibyte chars */
size = MultiByteToWideChar(CP_ACP, 0, aString, aSize, *wString, 0);
if (*wString) /* only in the second loop */
{
MultiByteToWideChar(CP_ACP, 0, (LPCSTR)*pWToFrom, aSize, *wString, size);
*pWToFrom = *wString;
*wString += size;
}
}
return size;
}
/*************************************************************************
* SHFileOperationA [SHELL32.@]
*
* Function to copy, move, delete and create one or more files with optional
* user prompts.
*
* PARAMS
* lpFileOp [I/O] pointer to a structure containing all the necessary information
*
* RETURNS
* Success: zero
* Failure: nonzero
*
* NOTES
* exported by name
*/
int WINAPI SHFileOperationA(LPSHFILEOPSTRUCTA lpFileOp)
{
SHFILEOPSTRUCTW nFileOp = *((LPSHFILEOPSTRUCTW)lpFileOp);
int retCode = 0;
DWORD size;
LPWSTR ForFree = NULL, /* we change wString in SHNameTranslate and can't use it for freeing */
wString = NULL; /* we change this in SHNameTranslate */
TRACE("\n");
if (FO_DELETE == (nFileOp.wFunc & FO_MASK))
nFileOp.pTo = NULL; /* we need a NULL or a valid pointer for translation */
if (!(nFileOp.fFlags & FOF_SIMPLEPROGRESS))
nFileOp.lpszProgressTitle = NULL; /* we need a NULL or a valid pointer for translation */
while (1) /* every loop calculate size, second translate also, if we have storage for this */
{
size = SHNameTranslate(&wString, &nFileOp.lpszProgressTitle, FALSE); /* no loop */
size += SHNameTranslate(&wString, &nFileOp.pFrom, TRUE); /* internal loop */
size += SHNameTranslate(&wString, &nFileOp.pTo, TRUE); /* internal loop */
if (ForFree)
{
retCode = SHFileOperationW(&nFileOp);
HeapFree(GetProcessHeap(), 0, ForFree); /* we cannot use wString, it was changed */
break;
}
else
{
wString = ForFree = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
if (ForFree) continue;
retCode = ERROR_OUTOFMEMORY;
nFileOp.fAnyOperationsAborted = TRUE;
SetLastError(retCode);
return retCode;
}
}
lpFileOp->hNameMappings = nFileOp.hNameMappings;
lpFileOp->fAnyOperationsAborted = nFileOp.fAnyOperationsAborted;
return retCode;
}
static const char * debug_shfileops_flags( DWORD fFlags )
{
return wine_dbg_sprintf( "%s%s%s%s%s%s%s%s%s%s%s%s%s",
fFlags & FOF_MULTIDESTFILES ? "FOF_MULTIDESTFILES " : "",
fFlags & FOF_CONFIRMMOUSE ? "FOF_CONFIRMMOUSE " : "",
fFlags & FOF_SILENT ? "FOF_SILENT " : "",
fFlags & FOF_RENAMEONCOLLISION ? "FOF_RENAMEONCOLLISION " : "",
fFlags & FOF_NOCONFIRMATION ? "FOF_NOCONFIRMATION " : "",
fFlags & FOF_WANTMAPPINGHANDLE ? "FOF_WANTMAPPINGHANDLE " : "",
fFlags & FOF_ALLOWUNDO ? "FOF_ALLOWUNDO " : "",
fFlags & FOF_FILESONLY ? "FOF_FILESONLY " : "",
fFlags & FOF_SIMPLEPROGRESS ? "FOF_SIMPLEPROGRESS " : "",
fFlags & FOF_NOCONFIRMMKDIR ? "FOF_NOCONFIRMMKDIR " : "",
fFlags & FOF_NOERRORUI ? "FOF_NOERRORUI " : "",
fFlags & FOF_NOCOPYSECURITYATTRIBS ? "FOF_NOCOPYSECURITYATTRIBS" : "",
fFlags & 0xf000 ? "MORE-UNKNOWN-Flags" : "");
}
static const char * debug_shfileops_action( DWORD op )
{
LPCSTR cFO_Name [] = {"FO_????","FO_MOVE","FO_COPY","FO_DELETE","FO_RENAME"};
return wine_dbg_sprintf("%s", cFO_Name[ op ]);
}
#define ERROR_SHELL_INTERNAL_FILE_NOT_FOUND 1026
#define HIGH_ADR (LPWSTR)0xffffffff
/* handle the complete deletion of `pTempFrom` */
static int shfileops_delete(WIN32_FIND_DATAW *wfd,SHFILEOPSTRUCTW nFileOp, LPWSTR pFromFile,LPWSTR pTempFrom,HANDLE *hFind)
{
LPWSTR lpFileName;
BOOL b_Mask = (NULL != StrPBrkW(&pFromFile[1], wWildcardChars));
int retCode = 0;
do
{
lpFileName = wfd->cAlternateFileName;
if (!lpFileName[0])
lpFileName = wfd->cFileName;
if (IsDotDir(lpFileName) ||
((b_Mask) && IsAttribDir(wfd->dwFileAttributes) && (nFileOp.fFlags & FOF_FILESONLY)))
continue;
SHFileStrCpyCatW(&pFromFile[1], lpFileName, NULL);
/* TODO: Check the SHELL_DeleteFileOrDirectoryW() function in shell32.dll */
if (IsAttribFile(wfd->dwFileAttributes))
{
if(SHNotifyDeleteFileW(pTempFrom) != ERROR_SUCCESS)
{
nFileOp.fAnyOperationsAborted = TRUE;
retCode = 0x78; /* value unknown */
}
}
else if(!SHELL_DeleteDirectoryW(pTempFrom, (!(nFileOp.fFlags & FOF_NOCONFIRMATION))))
{
nFileOp.fAnyOperationsAborted = TRUE;
retCode = 0x79; /* value unknown */
}
}
while (!nFileOp.fAnyOperationsAborted && FindNextFileW(*hFind,wfd));
FindClose(*hFind);
*hFind = INVALID_HANDLE_VALUE;
return retCode;
}
/*
* Summary of flags:
*
* implemented flags:
* FOF_MULTIDESTFILES, FOF_NOCONFIRMATION, FOF_FILESONLY
*
* unimplememented and ignored flags:
* FOF_CONFIRMMOUSE, FOF_SILENT, FOF_NOCONFIRMMKDIR,
* FOF_SIMPLEPROGRESS, FOF_NOCOPYSECURITYATTRIBS
*
* partially implemented, breaks if file exists:
* FOF_RENAMEONCOLLISION
*
* unimplemented and break if any other flag set:
* FOF_ALLOWUNDO, FOF_WANTMAPPINGHANDLE
*/
static int shfileops_check_flags(SHFILEOPSTRUCTW nFileOp)
{
FILEOP_FLAGS OFl = ((FILEOP_FLAGS)nFileOp.fFlags & 0xfff);
long FuncSwitch = (nFileOp.wFunc & FO_MASK);
long level= nFileOp.wFunc >> 4;
TRACE("%s level=%ld nFileOp.fFlags=0x%x\n",
debug_shfileops_action(FuncSwitch), level, nFileOp.fFlags);
/* OFl &= (-1 - (FOF_MULTIDESTFILES | FOF_FILESONLY)); */
/* OFl ^= (FOF_SILENT | FOF_NOCONFIRMATION | FOF_SIMPLEPROGRESS | FOF_NOCONFIRMMKDIR); */
OFl &= (~(FOF_MULTIDESTFILES | FOF_NOCONFIRMATION | FOF_FILESONLY)); /* implemented */
OFl ^= (FOF_SILENT | FOF_NOCONFIRMMKDIR | FOF_NOERRORUI | FOF_NOCOPYSECURITYATTRIBS); /* ignored, if one */
OFl &= (~FOF_SIMPLEPROGRESS); /* ignored, only with FOF_SILENT */
if (OFl)
{
if (OFl & (~(FOF_CONFIRMMOUSE | FOF_SILENT | FOF_RENAMEONCOLLISION |
FOF_NOCONFIRMMKDIR | FOF_NOERRORUI | FOF_NOCOPYSECURITYATTRIBS | FOF_ALLOWUNDO)))
{
FIXME("%s level=%ld lpFileOp->fFlags=0x%x not implemented, Aborted=TRUE, stub\n",
debug_shfileops_action(FuncSwitch), level, OFl);
return 0x403; /* 1027, we need an extension to shlfileop */
}
else
{
TRACE("%s level=%ld lpFileOp->fFlags=0x%x not fully implemented, stub\n",
debug_shfileops_action(FuncSwitch), level, OFl);
}
}
return 0;
}
static int shfileops_do_operation(WIN32_FIND_DATAW wfd,SHFILEOPSTRUCTW *nFileOp, LPWSTR pToFile, LPWSTR pFromFile)
{
LPWSTR lpFileName = wfd.cAlternateFileName;
if (!lpFileName[0])
lpFileName = wfd.cFileName;
if (IsDotDir(lpFileName) ||
(IsAttribDir(wfd.dwFileAttributes) && (nFileOp->fFlags & FOF_FILESONLY)))
return 0; /* next name in pTempFrom(dir) */
SHFileStrCpyCatW(&pToFile[1], lpFileName, NULL);
SHFileStrCpyCatW(&pFromFile[1], lpFileName, NULL);
return SHFileOperationW (nFileOp);
}
/* get attributes of the parent dir of pTemp and create the directory if it does not exists */
static DWORD shfileops_get_parent_attr2(LPWSTR pFile,LPWSTR pTemp,int flag,int *retCode)
{
DWORD PathAttr;
pFile[0] = '\0';
PathAttr = GetFileAttributesW(pTemp);
if ((PathAttr == INVALID_FILE_ATTRIBUTES) && flag)
{
/* create dir must be here, sample target D:\y\ *.* create with RC=10003 */
if (SHNotifyCreateDirectoryW(pTemp, NULL))
{
*retCode = 0x73;/* value unknown */
/*goto shfileop_end;*/
return PathAttr;
}
PathAttr = GetFileAttributesW(pTemp);
}
pFile[0] = '\\';
return PathAttr;
}
/* get attributes of the parent dir of pTemp without creating the directory if it does not exists */
static DWORD shfileops_get_parent_attr(LPWSTR pFile,LPWSTR pTemp)
{
/* less efficient:
return shfileops_get_parent_attr2(pFile,pTemp,0,NULL);
*/
DWORD PathAttr;
pFile[0] = '\0';
PathAttr = GetFileAttributesW(pTemp);
pFile[0] = '\\';
return PathAttr;
}
/*************************************************************************
* SHFileOperationW [SHELL32.@]
*
* See SHFileOperationA.
*/
int WINAPI SHFileOperationW(LPSHFILEOPSTRUCTW lpFileOp)
{
SHFILEOPSTRUCTW nFileOp = *(lpFileOp);
LPCWSTR pNextFrom = nFileOp.pFrom;
LPCWSTR pNextTo = nFileOp.pTo;
LPCWSTR pFrom = pNextFrom;
LPCWSTR pTo = NULL;
HANDLE hFind = INVALID_HANDLE_VALUE;
WIN32_FIND_DATAW wfd;
LPWSTR pTempFrom = NULL;
LPWSTR pTempTo = NULL;
LPWSTR pFromFile;
LPWSTR pToFile = NULL;
int retCode = 0;
DWORD ToAttr;
DWORD ToPathAttr;
BOOL b_Multi = (nFileOp.fFlags & FOF_MULTIDESTFILES);
BOOL b_MultiTo = (FO_DELETE != (lpFileOp->wFunc & FO_MASK));
BOOL b_MultiPaired = (!b_MultiTo);
BOOL b_MultiFrom = FALSE;
BOOL not_overwrite;
BOOL ask_overwrite;
BOOL b_SameRoot;
BOOL b_SameTailName;
BOOL b_ToInvalidTail = FALSE;
BOOL b_ToValid; /* for W98-Bug for FO_MOVE with source and target in same rootdrive */
BOOL b_Mask;
BOOL b_ToTailSlash = FALSE;
long FuncSwitch = (nFileOp.wFunc & FO_MASK);
long level= nFileOp.wFunc>>4;
/* default no error */
nFileOp.fAnyOperationsAborted = FALSE;
if ((FuncSwitch < FO_MOVE) || (FuncSwitch > FO_RENAME))
goto shfileop_end; /* no valid FunctionCode */
if (level == 0)
TRACE("%s: flags (0x%04x) : %s\n",
debug_shfileops_action(FuncSwitch), nFileOp.fFlags,
debug_shfileops_flags(nFileOp.fFlags) );
/* establish when pTo is interpreted as the name of the destination file
* or the directory where the Fromfile should be copied to.
* This depends on:
* (1) pTo points to the name of an existing directory;
* (2) the flag FOF_MULTIDESTFILES is present;
* (3) whether pFrom point to multiple filenames.
*
* Some experiments:
*
* destisdir 1 1 1 1 0 0 0 0
* FOF_MULTIDESTFILES 1 1 0 0 1 1 0 0
* multiple from filenames 1 0 1 0 1 0 1 0
* ---------------
* copy files to dir 1 0 1 1 0 0 1 0
* create dir 0 0 0 0 0 0 1 0
*/
retCode = shfileops_check_flags(nFileOp);
if (retCode)
goto shfileop_end;
if ((pNextFrom) && (!(b_MultiTo) || (pNextTo)))
{
nFileOp.pFrom = pTempFrom = HeapAlloc(GetProcessHeap(), 0, ((1 + 2 * (b_MultiTo)) * MAX_PATH + 6) * sizeof(WCHAR));
if (!pTempFrom)
{
retCode = ERROR_OUTOFMEMORY;
SetLastError(retCode);
goto shfileop_end;
}
if (b_MultiTo)
pTempTo = &pTempFrom[MAX_PATH + 4];
nFileOp.pTo = pTempTo;
ask_overwrite = (!(nFileOp.fFlags & FOF_NOCONFIRMATION) && !(nFileOp.fFlags & FOF_RENAMEONCOLLISION));
not_overwrite = (!(nFileOp.fFlags & FOF_NOCONFIRMATION) || (nFileOp.fFlags & FOF_RENAMEONCOLLISION));
}
else
{
retCode = ERROR_SHELL_INTERNAL_FILE_NOT_FOUND;
goto shfileop_end;
}
/* need break at error before change sourcepointer */
while(!nFileOp.fAnyOperationsAborted && (pNextFrom[0]))
{
nFileOp.wFunc = ((level + 1) << 4) + FuncSwitch;
nFileOp.fFlags = lpFileOp->fFlags;
if (b_MultiTo)
{
pTo = pNextTo;
pNextTo = &pNextTo[lstrlenW(pTo)+1];
b_MultiTo = (b_Multi && pNextTo[0]);
}
pFrom = pNextFrom;
pNextFrom = &pNextFrom[lstrlenW(pNextFrom)+1];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -