📄 ftpdrop.cpp
字号:
}
/*****************************************************************************\
FUNCTION: _FireChangeNotify
DESCRIPTION:
asd
\*****************************************************************************/
HRESULT _FireChangeNotify(HINTPROCINFO * phpi, LPCOPYONEHDROPINFO pcohi)
{
HRESULT hr = S_OK;
WIN32_FIND_DATA wfd;
HANDLE handle = FindFirstFile(pcohi->pszFSSource, &wfd);
TraceMsg(TF_WININET_DEBUG, "_FireChangeNotify() FtpPutFileEx(%s -> %s) succeeded", pcohi->pszFSSource, pcohi->pszFtpDest);
if (handle != INVALID_HANDLE_VALUE)
{
ULARGE_INTEGER uliFileSize;
FTP_FIND_DATA ffd;
CWireEncoding * pwe = pcohi->pff->GetCWireEncoding();
uliFileSize.LowPart = wfd.nFileSizeLow;
uliFileSize.HighPart = wfd.nFileSizeHigh;
pcohi->progInfo.uliBytesCompleted.QuadPart += uliFileSize.QuadPart;
hr = pwe->UnicodeToWireBytes(pcohi->pmlc, wfd.cFileName, (phpi->pfd->IsUTF8Supported() ? WIREENC_USE_UTF8 : WIREENC_NONE), ffd.cFileName, ARRAYSIZE(ffd.cFileName));
if (EVAL(SUCCEEDED(hr)))
{
LPITEMIDLIST pidlFtpFile;
SYSTEMTIME st;
FILETIME ftUTC;
ffd.dwFileAttributes = wfd.dwFileAttributes;
ffd.dwReserved0 = wfd.dwReserved0;
ffd.dwReserved1 = wfd.dwReserved1;
ffd.nFileSizeHigh = wfd.nFileSizeHigh;
ffd.nFileSizeLow = wfd.nFileSizeLow;
// wfd.ft*Time is in UTF and FtpItemID_CreateReal wants
// it in LocalTime, so we need to convert here.
GetSystemTime(&st);
SystemTimeToFileTime(&st, &ftUTC);
FileTimeToLocalFileTime(&ftUTC, &ffd.ftLastWriteTime); // UTC->LocalTime
ffd.ftCreationTime = ffd.ftLastWriteTime;
ffd.ftLastAccessTime = ffd.ftLastWriteTime;
hr = FtpItemID_CreateReal(&ffd, pcohi->pszFtpDest, &pidlFtpFile);
if (SUCCEEDED(hr))
{
// Note that we created the mapped name
// PERF: Note that we give the time/date stamp to SHChangeNotify that comes from the source
// file, not from the FTP server, so it may be inforrect. However, it's perf prohibitive
// to do the right thing.
FtpChangeNotify(phpi->hwnd, SHCNE_CREATE, pcohi->pff, phpi->pfd, pidlFtpFile, NULL, pcohi->fIsRoot);
ILFree(pidlFtpFile);
}
}
FindClose(handle);
}
return hr;
}
#define CCH_SIZE_ERROR_MESSAGE 6*1024
/*****************************************************************************\
FtpCopyFile
Callback procedure that copies a single hdrop / map.
Should I try to make the name unique in case of collision?
Naah, just prompt, but! no way to tell if destination is case-sensitive...
\*****************************************************************************/
HRESULT FtpCopyFile(HINTERNET hint, HINTPROCINFO * phpi, LPCOPYONEHDROPINFO pcohi)
{
HRESULT hr = S_OK;
if (pcohi->dwOperation != COHDI_FILESIZE_COUNT)
{
WIRECHAR wWireName[MAX_PATH];
EVAL(SUCCEEDED(pcohi->pff->GetCWireEncoding()->UnicodeToWireBytes(pcohi->pmlc, pcohi->pszFtpDest, (pcohi->pff->IsUTF8Supported() ? WIREENC_USE_UTF8 : WIREENC_NONE), wWireName, ARRAYSIZE(wWireName))));
if (phpi->psb)
phpi->psb->SetStatusMessage(IDS_COPYING, pcohi->pszFSSource);
if (pcohi->progInfo.ppd)
{
EVAL(SUCCEEDED(UpdateCopyProgressInfo(pcohi->progInfo.ppd, pcohi->pszFtpDest)));
EVAL(SUCCEEDED(pcohi->progInfo.ppd->SetProgress64(pcohi->progInfo.uliBytesCompleted.QuadPart, pcohi->progInfo.uliBytesTotal.QuadPart)));
}
pcohi->progInfo.dwCompletedInCurFile = 0;
pcohi->progInfo.dwLastDisplayed = 0;
// BUGBUG: We need to pass the FTP_TRANSFER_TYPE (_ASCII vs. _BINARY)
hr = FtpPutFileExWrap(hint, TRUE, pcohi->pszFSSource, wWireName, FTP_TRANSFER_TYPE_UNKNOWN, (DWORD_PTR)&(pcohi->progInfo));
if (SUCCEEDED(hr))
{
// We don't fire change notify on browser only if we
// are replacing a file because ChangeNotify really
// just hacks ListView and doen't know how to handle
// duplicates (file replace).
if (pcohi->fFireChangeNotify)
hr = _FireChangeNotify(phpi, pcohi);
}
else
{
if (HRESULT_FROM_WIN32(ERROR_INTERNET_OPERATION_CANCELLED) == hr)
{
// Clean up the file.
EVAL(SUCCEEDED(phpi->pfd->WithHint(NULL, phpi->hwnd, DeleteOneFileCB, pcohi, NULL, pcohi->pff)));
hr = HRESULT_FROM_WIN32(ERROR_CANCELLED);
}
else
{
// We still want to delete the file, but we need to save the error message
// so the dialog is correct.
CHAR szErrorMsg[CCH_SIZE_ERROR_MESSAGE];
WCHAR wzErrorMsg[CCH_SIZE_ERROR_MESSAGE];
DWORD cchSize = ARRAYSIZE(szErrorMsg);
InternetGetLastResponseInfoWrap(TRUE, NULL, szErrorMsg, &cchSize);
HRESULT hrOrig = hr;
CWireEncoding * pwe = phpi->pfd->GetFtpSite()->GetCWireEncoding();
pwe->WireBytesToUnicode(NULL, szErrorMsg, WIREENC_NONE, wzErrorMsg, ARRAYSIZE(wzErrorMsg));
// Does it already exist? This may fail.
SUCCEEDED(phpi->pfd->WithHint(NULL, phpi->hwnd, DeleteOneFileCB, pcohi, NULL, pcohi->pff));
// No, so it was a real error, now display the error message with the original
// server response.
DisplayWininetErrorEx(phpi->hwnd, TRUE, HRESULT_CODE(hrOrig), IDS_FTPERR_TITLE_ERROR, IDS_FTPERR_FILECOPY, IDS_FTPERR_WININET, MB_OK, pcohi->progInfo.ppd, wzErrorMsg);
hr = HRESULT_FROM_WIN32(ERROR_CANCELLED);
}
}
}
else
{
// Just get the file size.
WIN32_FIND_DATA wfd;
HANDLE handle = FindFirstFile(pcohi->pszFSSource, &wfd);
if (handle && (handle != INVALID_HANDLE_VALUE))
{
ULARGE_INTEGER uliFileSize;
uliFileSize.LowPart = wfd.nFileSizeLow;
uliFileSize.HighPart = wfd.nFileSizeHigh;
pcohi->progInfo.uliBytesTotal.QuadPart += uliFileSize.QuadPart;
FindClose(handle);
}
}
//TraceMsg(TF_FTPOPERATION, "FtpPutFileA(From=%ls, To=%s) hr=%#08lX", pcohi->pszFSSource, pcohi->pszFtpDest, hr);
return hr;
}
/*****************************************************************************\
_EnumOneHdropW
Handle one hdrop and corresponding filemap.
This is annoying because we need to convert from UNICODE to ANSI.
\*****************************************************************************/
#define OleStrToStrA(a, b) OleStrToStrN(a, ARRAYSIZE(a), b, -1)
HRESULT _EnumOneHdropW(LPCWSTR * ppwzzFSSources, LPCWSTR * ppwzzFtpDest, LPTSTR pszFSSourceOut, DWORD cchFSSourceOut, LPTSTR pszFtpDestOut, DWORD cchFtpDestOut)
{
HRESULT hres;
int cwch;
if (*ppwzzFSSources && (*ppwzzFSSources)[0])
{
cwch = SHUnicodeToTChar(*ppwzzFSSources, pszFSSourceOut, cchFSSourceOut);
if (EVAL(cwch))
{
*ppwzzFSSources += cwch;
if (EVAL((*ppwzzFtpDest)[0]))
{
cwch = SHUnicodeToTChar(*ppwzzFtpDest, pszFtpDestOut, cchFtpDestOut);
if (EVAL(cwch))
{
*ppwzzFtpDest += cwch;
hres = S_OK; // Both strings converted okay
}
else
hres = E_UNEXPECTED; // File name too long
}
else
hres = E_UNEXPECTED; // Premature EOF in map
}
else
hres = E_UNEXPECTED; // File name too long
}
else
hres = S_FALSE; // End of buffer
return hres;
}
/*****************************************************************************\
_EnumOneHdropA
Handle one hdrop and corresponding filemap.
\*****************************************************************************/
HRESULT _EnumOneHdropA(LPCSTR * ppszzFSSource, LPCSTR * ppszzFtpDest, LPTSTR pszFSSourceOut, DWORD cchFSSourceOut, LPTSTR pszFtpDestOut, DWORD cchFtpDestOut)
{
HRESULT hres;
if ((*ppszzFSSource)[0])
{
SHAnsiToTChar(*ppszzFSSource, pszFSSourceOut, cchFSSourceOut);
*ppszzFSSource += lstrlenA(*ppszzFSSource) + 1;
if (EVAL((*ppszzFtpDest)[0]))
{
SHAnsiToTChar(*ppszzFtpDest, pszFtpDestOut, cchFtpDestOut);
*ppszzFtpDest += lstrlenA(*ppszzFtpDest) + 1;
hres = S_OK; // No problemo
}
else
hres = E_UNEXPECTED; // Premature EOF in map
}
else
hres = S_FALSE; // No more files
return hres;
}
/*****************************************************************************\
ConfirmCopy
Callback procedure that checks if this file really ought to be
copied.
Returns S_OK if the file should be copied.
Returns S_FALSE if the file should not be copied.
- If the user cancelled, then say S_FALSE from now on.
- If the user said Yes to All, then say S_OK.
- If there is no conflict, then say S_OK.
- If the user said No to All, then say S_FALSE.
- Else, ask the user what to do.
Note that the order of the tests above means that if you say
"Yes to All", then we don't waste our time doing overwrite checks.
_GROSS_: NOTE! that we don't try to uniquify the name, because
WinINet doesn't support the STOU (store unique) command, and
there is no way to know what filenames are valid on the server.
\*****************************************************************************/
HRESULT ConfirmCopy(LPCWSTR pszLocal, LPCWSTR pszFtpName, OPS * pOps, HWND hwnd, CFtpFolder * pff, CFtpDir * pfd, DROPEFFECT * pde, int nObjs, BOOL * pfFireChangeNotify)
{
HRESULT hr = S_OK;
*pfFireChangeNotify = TRUE;
if (*pOps == opsCancel)
hr = S_FALSE;
else
{
HANDLE hfind;
WIN32_FIND_DATA wfdSrc;
hfind = FindFirstFile(pszLocal, &wfdSrc);
if (hfind != INVALID_HANDLE_VALUE)
{
FindClose(hfind);
// Is it a file? We don't care about confirming the replacement
// of directories.
if (!(FILE_ATTRIBUTE_DIRECTORY & wfdSrc.dwFileAttributes))
{
FTP_FIND_DATA wfd;
hr = pfd->GetFindDataForDisplayPath(hwnd, pszFtpName, &wfd, pff);
if (*pOps == opsYesToAll)
{
// If the file exists (S_OK) and it's browser only,
// then don't fire the change notify.
if ((S_OK == hr) && (SHELL_VERSION_NT5 != GetShellVersion()))
*pfFireChangeNotify = FALSE;
hr = S_OK;
}
else
{
switch (hr)
{
case S_OK: // File exists; worry
if (*pOps == opsNoToAll)
hr = S_FALSE;
else
{
FILETIME ftUTC = wfdSrc.ftLastWriteTime;
FileTimeToLocalFileTime(&ftUTC, &wfdSrc.ftLastWriteTime); // UTC->LocalTime
// BUGBUG/TODO: Do we need to set modal?
switch (FtpConfirmReplaceDialog(hwnd, &wfdSrc, &wfd, nObjs, pff))
{
case IDC_REPLACE_YESTOALL:
*pOps = opsYesToAll;
// FALLTHROUGH
case IDC_REPLACE_YES:
// pre-NT5 doesn't work
if (SHELL_VERSION_NT5 != GetShellVersion())
*pfFireChangeNotify = FALSE;
hr = S_OK;
break;
case IDC_REPLACE_NOTOALL:
*pOps = opsNoToAll;
// FALLTHROUGH
case IDC_REPLACE_NO:
hr = S_FALSE;
break;
default:
ASSERT(0); // Huh?
// FALLTHROUGH
case IDC_REPLACE_CANCEL:
if (pde)
*pde = 0;
*pOps = opsCancel;
hr = HRESULT_FROM_WIN32(ERROR_CANCELLED);
break;
}
}
break;
case S_FALSE:
default:
// Assume the file doesn't exist; no problemo
hr = S_OK;
break;
}
}
}
}
else
{ // File doesn't exist
hr = S_OK; // The open will raise the error
}
}
//TraceMsg(TF_FTPDRAGDROP, "ConfirmCopy(%s) -> %08x", pszFtpName, hr);
return hr;
}
/*****************************************************************************\
CLASS: CDropOperation
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -