ftppl.cpp
来自「很好用的ftp源码」· C++ 代码 · 共 628 行 · 第 1/2 页
CPP
628 行
{
HRESULT hres = E_OUTOFMEMORY;
CFtpPidlList * pflpidl;
*ppflpidl = pflpidl = new CFtpPidlList();
if (pflpidl)
{
hres = pflpidl->_Fill(cpidl, rgpidl);
if (!EVAL(SUCCEEDED(hres)))
{
ASSERT(pflpidl->GetCount() == 0);
IUnknown_Set(ppflpidl, NULL);
}
}
return hres;
}
int CALLBACK PidlListDestroyCallback(LPVOID p, LPVOID pData)
{
ILFree((LPITEMIDLIST) p);
return 1;
}
/****************************************************\
Constructor
\****************************************************/
CFtpPidlList::CFtpPidlList() : m_cRef(1)
{
DllAddRef();
// This needs to be allocated in Zero Inited Memory.
// Assert that all Member Variables are inited to Zero.
ASSERT(!m_pfl);
CFtpList_Create(100, PidlListDestroyCallback, 100, &m_pfl);
ASSERT(m_pfl); // This sucks
UseCachedDirListings(FALSE);
LEAK_ADDREF(LEAK_CFtpPidlList);
}
/****************************************************\
Destructor
\****************************************************/
CFtpPidlList::~CFtpPidlList()
{
AssertSorted();
if (m_pfl)
m_pfl->Release();
DllRelease();
LEAK_DELREF(LEAK_CFtpPidlList);
}
//===========================
// *** IUnknown Interface ***
//===========================
ULONG CFtpPidlList::AddRef()
{
m_cRef++;
return m_cRef;
}
ULONG CFtpPidlList::Release()
{
ASSERT(m_cRef > 0);
m_cRef--;
if (m_cRef > 0)
return m_cRef;
delete this;
return 0;
}
HRESULT CFtpPidlList::QueryInterface(REFIID riid, void **ppvObj)
{
if (IsEqualIID(riid, IID_IUnknown))
{
*ppvObj = SAFECAST(this, IUnknown *);
}
else
{
TraceMsg(TF_FTPQI, "CFtpPidlList::QueryInterface() failed.");
*ppvObj = NULL;
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
////////////////////////////////////////////////////////////////////
// Pild List Enum Helpers
////////////////////////////////////////////////////////////////////
/*****************************************************************************\
FUNCTION: RecursiveProcessPidl
DESCRIPTION:
This function will will be called for each item in the initial Pidl List
(before the recursion occurs). This is a wrapper because the first list is
a list of pidls. The subsequent lists are of WIN32_FIND_DATA types.
\*****************************************************************************/
int RecursiveProcessPidl(LPVOID pvPidl, LPVOID pvInetEnum)
{
LPCITEMIDLIST pidl = (LPCITEMIDLIST) pvPidl;
INETENUM * pInetEnum = (INETENUM *) pvInetEnum;
LPITEMIDLIST pidlFull = ILCombine(pInetEnum->pidlRoot, pidl);
if (EVAL(pidlFull))
{
pInetEnum->hr = pInetEnum->pfnProcessItemCB((LPVOID) pInetEnum->pfnProcessItemCB, pInetEnum->hint, pidlFull, pInetEnum->pfValidhinst, pInetEnum->pvData);
ILFree(pidlFull);
}
return (SUCCEEDED(pInetEnum->hr) ? TRUE : FALSE);
}
/*****************************************************************************\
FUNCTION: _EnumFolderPrep
DESCRIPTION:
This function will step into the pszDir directory and enum all of it's
contents. For each item, it will call the callback function provided (pfnProcessItemCB).
That callback function can then call EnumFolder() again (recursively) if
there is a subfolder.
NOTE:
This function needs to first find all the items and then in a second
loop call the callback function. This is because the WININET FTP APIs
only allow one enum to occur at a time, which may not happen if half way through
enuming one dir, a recursive call starts enuming a sub dir.
\*****************************************************************************/
HRESULT _EnumFolderPrep(HINTERNET hint, LPCITEMIDLIST pidlFull, CFtpPidlList * pPidlList, CWireEncoding * pwe, LPITEMIDLIST * ppidlCurrFtpPath)
{
HRESULT hr = S_OK;
// 1. Get Current Directory (To restore later).
hr = FtpGetCurrentDirectoryPidlWrap(hint, TRUE, pwe, ppidlCurrFtpPath);
if (EVAL(SUCCEEDED(hr)))
{
CMultiLanguageCache cmlc;
CWireEncoding we;
if (!pwe)
pwe = &we;
// It's important that this is a relative CD.
// 2. Change Directory Into the subdirectory.
hr = FtpSetCurrentDirectoryWrap(hint, TRUE, FtpPidl_GetLastItemWireName(pidlFull));
if (SUCCEEDED(hr))
{
LPITEMIDLIST pidlItem;
HINTERNET hInetFind = NULL;
hr = FtpFindFirstFilePidlWrap(hint, TRUE, &cmlc, pwe, NULL, &pidlItem, pPidlList->m_dwInetFlags, NULL, &hInetFind);
if (hInetFind)
{
do
{
LPCWIRESTR pwireStr = FtpPidl_GetLastItemWireName(pidlFull);
if (IS_VALID_FILE(pwireStr))
{
// Store entire pidl (containing WIN32_FIND_DATA) so we can get
// the attributes and other info later. Seeing if it's a dir
// is one need...
pPidlList->InsertSorted(pidlItem);
}
ILFree(pidlItem);
hr = InternetFindNextFilePidlWrap(hInetFind, TRUE, &cmlc, pwe, &pidlItem);
}
while (SUCCEEDED(hr));
ILFree(pidlItem);
InternetCloseHandle(hInetFind);
}
if (ERROR_NO_MORE_FILES == HRESULT_CODE(hr))
hr = S_OK;
}
EVAL(SUCCEEDED(pwe->ReSetCodePages(&cmlc, pPidlList)));
}
return hr;
}
/*****************************************************************************\
FUNCTION: _GetPathDifference
DESCRIPTION:
This function will step into the pszDir directory and enum all of it's
contents. For each item, it will call the callback function provided (pfnProcessItemCB).
That callback function can then call EnumFolder() again (recursively) if
there is a subfolder.
NOTE:
This function needs to first find all the items and then in a second
loop call the callback function. This is because the WININET FTP APIs
only allow one enum to occur at a time, which may not happen if half way through
enuming one dir, a recursive call starts enuming a sub dir.
PARAMETERS:
pszBaseUrl - This needs to be escaped.
pszDir - This needs to be escaped.
*ppszUrlPathDiff - This will be UnEscaped.
\*****************************************************************************/
void _GetPathDifference(LPCTSTR pszBaseUrl, LPCTSTR pszDir, LPTSTR * ppszUrlPathDiff)
{
TCHAR szUrlPathDiff[MAX_URL_STRING];
TCHAR szFullUrl[MAX_URL_STRING];
DWORD cchSize = ARRAYSIZE(szFullUrl);
// This is needed for this case:
// pszBaseUrl="ftp://server/subdir1/", pszDir="/subdir1/subdir2/file.txt"
// So, szUrlPathDiff="subdir2/file.txt" instead of pszDir
//
// ICU_NO_ENCODE is needed because Download Dlg may have paths with
// spaces that can't be escaped.
InternetCombineUrl(pszBaseUrl, pszDir, szFullUrl, &cchSize, ICU_NO_ENCODE);
UrlGetDifference(pszBaseUrl, szFullUrl, szUrlPathDiff, ARRAYSIZE(szUrlPathDiff));
// We will now use szFullUrl to store the UnEscaped version since these buffers
// are so large.
UnEscapeString(szUrlPathDiff, szFullUrl, ARRAYSIZE(szFullUrl));
Str_SetPtr(ppszUrlPathDiff, szFullUrl);
}
/*****************************************************************************\
FUNCTION: EnumFolder
DESCRIPTION:
This function will step into the pszDir directory and enum all of it's
contents. For each item, it will call the callback function provided (pfnProcessItemCB).
That callback function can then call EnumFolder() again (recursively) if
there is a subfolder.
PARAMETERS:
(pszBaseUrl=ftp://server/dir1/, pszDir=dir2, DirToEnum=ftp://server/dir1/dir2/)
pszDir - This is the directory we are enumerating. (dir2) It is relative to pszBaseUrl.
hint - The current working directory will be set to pszBaseUrl. _EnumFolderPrep will make it go into pszDir.
NOTE:
This function needs to first find all the items and then in a second
loop call the callback function. This is because the WININET FTP APIs
only allow one enum to occur at a time, which may not happen if half way through
enuming one dir, a recursive call starts enuming a sub dir.
\*****************************************************************************/
HRESULT EnumFolder(LPFNPROCESSITEMCB pfnProcessItemCB, HINTERNET hint, LPCITEMIDLIST pidlFull, CWireEncoding * pwe, BOOL * pfValidhinst, LPVOID pvData)
{
CFtpPidlList * pPidlList;
BOOL fValidhinst = TRUE;
HRESULT hr = CFtpPidlList_Create(0, &pidlFull, &pPidlList);
if (SUCCEEDED(hr))
{
LPITEMIDLIST pidlCurrFtpPath = NULL;
hr = _EnumFolderPrep(hint, pidlFull, pPidlList, pwe, &pidlCurrFtpPath);
if (SUCCEEDED(hr))
{
hr = S_OK;
// 4. Process each file name, which may be recursive.
// This loop and the while loop above need to be
// separated because it's not possible to create
// more than one FTP Find File handle based on the
// same session.
for (int nIndex = 0; SUCCEEDED(hr) && (nIndex < pPidlList->GetCount()); nIndex++)
{
LPITEMIDLIST pidlNewFull = ILCombine(pidlFull, pPidlList->GetPidl(nIndex));
hr = pfnProcessItemCB(pfnProcessItemCB, hint, pidlNewFull, &fValidhinst, pvData);
ILFree(pidlNewFull);
}
// 5. Go back to original directory (from Step 2)
// The only time we don't want to return to the original directory is if
// the hinst was freed in an wininet callback function. We may cache the hinst
// so we need the directory to be valid later.
if (fValidhinst)
{
if (SUCCEEDED(hr))
{
// We still want to reset the directory but we don't want to over write
// the original error message.
hr = FtpSetCurrentDirectoryPidlWrap(hint, TRUE, pidlCurrFtpPath, TRUE, TRUE);
}
}
Pidl_Set(&pidlCurrFtpPath, NULL);
}
pPidlList->Release();
}
if (pfValidhinst)
*pfValidhinst = fValidhinst;
return hr;
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?