📄 ftpdrop.cpp
字号:
DESCRIPTION:
DefView will cache the IDropTarget pointer (CFtpDrop) for a shell extension.
When it calls CFtpDrop::Drop(), the work needs to be done on a background
thread in order to not block the UI thread. The problem is that if the user
does another drag to the same Ftp Window, CFtpDrop::Drop() will be called again.
For this reasons, CFtpDrop::Drop() cannot have any state after it returns.
In order to accomplish this with the asynch background thread, we have
CFtpDrop::Drop() call CDropOperation_Create(), and then CDropOperation->DoOperation().
And then it will orphan (call Release()) the CDropOperation. The CDropOperation
will then destroy itself when the copy is finishes. This enables subsequent calls
to CFtpDrop::Drop() to spawn separate CDropOperation objects so each can maintain
the state for that specifc operation and CFtpDrop remains stateless.
\*****************************************************************************/
class CDropOperation : public IUnknown
{
public:
//////////////////////////////////////////////////////
// Public Interfaces
//////////////////////////////////////////////////////
// *** IUnknown ***
virtual STDMETHODIMP_(ULONG) AddRef(void);
virtual STDMETHODIMP_(ULONG) Release(void);
virtual STDMETHODIMP QueryInterface(REFIID riid, LPVOID * ppvObj);
public:
CDropOperation();
~CDropOperation(void);
// Public Member Functions
HRESULT DoOperation(BOOL fAsync);
static HRESULT CopyCB(HINTERNET hint, HINTPROCINFO * phpi, LPVOID pv, BOOL * pfReleaseHint);
// Friend Functions
friend HRESULT CDropOperation_Create(CFtpFolder * pff, HWND hwnd, LPCTSTR pszzFSSource, LPCTSTR pszzFtpDest, CDropOperation ** ppfdt, DROPEFFECT de, OPS ops, int cobj);
protected:
// Protected Member Variables
int m_cRef;
CFtpFolder * m_pff; // The owner
CFtpDir * m_pfd; // The FtpDir of the owner
HWND m_hwnd; // The window being drug over
DROPEFFECT m_de; // Effect being performed
OPS m_ops; // Overwrite prompting state
int m_cobj; // Number of objects being dropped
ULARGE_INTEGER m_uliBytesCompleted;
ULARGE_INTEGER m_uliBytesTotal;
// Private Member Functions
HRESULT _ConfirmCopy(LPCWSTR pszLocal, LPCWSTR psz, BOOL * pfFireChangeNotify);
HRESULT _CalcSizeOneHdrop(LPCWSTR pszFSSource, LPCWSTR pszFtpDest, IProgressDialog * ppd);
HRESULT _ThreadProcCB(void);
HRESULT _CopyOneHdrop(LPCWSTR pszFSSource, LPCWSTR pszFtpDest);
HRESULT _StartBackgroundInteration(void);
HRESULT _DoCopyIteration(void);
HRESULT _CalcUploadProgress(void);
private:
// Private Member Variables
IProgressDialog * m_ppd;
LPCWSTR m_pszzFSSource; // Paths
LPCWSTR m_pszzFtpDest; // Map
CMultiLanguageCache m_mlc; // Cache for fast str thunking.
static DWORD CALLBACK _ThreadProc(LPVOID pThis) {return ((CDropOperation *)pThis)->_ThreadProcCB();};
};
HRESULT CDropOperation_Create(CFtpFolder * pff, HWND hwnd, LPCTSTR pszzFSSource, LPCTSTR pszzFtpDest, CDropOperation ** ppfdt,
DROPEFFECT de, OPS ops, int cobj)
{
HRESULT hr = E_OUTOFMEMORY;
CDropOperation * pfdt = new CDropOperation();
*ppfdt = pfdt;
if (pfdt)
{
pfdt->m_hwnd = hwnd;
// Copy the CFtpFolder * value
pfdt->m_pff = pff;
if (pff)
pff->AddRef();
// Copy the CFtpDir * value
ASSERT(!pfdt->m_pfd);
pfdt->m_pfd = pff->GetFtpDir();
ASSERT(pfdt->m_pfd);
ASSERT(!pfdt->m_pszzFSSource);
pfdt->m_pszzFSSource = pszzFSSource;
ASSERT(!pfdt->m_pszzFtpDest);
pfdt->m_pszzFtpDest = pszzFtpDest;
pfdt->m_de = de; // Effect being performed
pfdt->m_ops = ops; // Overwrite prompting state
pfdt->m_cobj = cobj; // Number of objects being dropped
hr = S_OK;
}
ASSERT_POINTER_MATCHES_HRESULT(*ppfdt, hr);
return hr;
}
/****************************************************\
Constructor
\****************************************************/
CDropOperation::CDropOperation() : m_cRef(1)
{
DllAddRef();
// This needs to be allocated in Zero Inited Memory.
// Assert that all Member Variables are inited to Zero.
ASSERT(!m_pff);
ASSERT(!m_pfd);
ASSERT(!m_hwnd);
ASSERT(!m_cobj);
LEAK_ADDREF(LEAK_CDropOperation);
}
/****************************************************\
Destructor
\****************************************************/
CDropOperation::~CDropOperation()
{
// use ATOMICRELEASE
IUnknown_Set(&m_pff, NULL);
IUnknown_Set(&m_pfd, NULL);
IUnknown_Set((IUnknown **)&m_ppd, NULL);
Str_SetPtr((LPTSTR *) &m_pszzFSSource, NULL);
Str_SetPtr((LPTSTR *) &m_pszzFtpDest, NULL);
DllRelease();
LEAK_DELREF(LEAK_CDropOperation);
}
//===========================
// *** IUnknown Interface ***
//===========================
ULONG CDropOperation::AddRef()
{
m_cRef++;
return m_cRef;
}
ULONG CDropOperation::Release()
{
ASSERT(m_cRef > 0);
m_cRef--;
if (m_cRef > 0)
return m_cRef;
delete this;
return 0;
}
HRESULT CDropOperation::QueryInterface(REFIID riid, void **ppvObj)
{
if (IsEqualIID(riid, IID_IUnknown))
{
*ppvObj = SAFECAST(this, IUnknown*);
}
else
{
TraceMsg(TF_FTPQI, "CDropOperation::QueryInterface() failed.");
*ppvObj = NULL;
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
/****************************************************\
FUNCTION: _ThreadProcCB
DESCRIPTION:
\****************************************************/
HRESULT CDropOperation::_ThreadProcCB(void)
{
HRESULT hr;
HRESULT hrOleInit = SHCoInitialize();
// WARNING: Init OLE if you plan to do COM.
m_ppd = CProgressDialog_CreateInstance(IDS_COPY_TITLE, IDA_FTPUPLOAD);
if (EVAL(m_ppd))
{
ASSERT(m_hwnd);
// We give a NULL punkEnableModless because we don't want to go modal.
EVAL(SUCCEEDED(m_ppd->StartProgressDialog(m_hwnd, NULL, PROGDLG_AUTOTIME, NULL)));
}
hr = _CalcUploadProgress();
// Did we succeed creating the directories and counting the
// size we need to copy?
if (SUCCEEDED(hr))
{
if (m_ppd)
{
EVAL(SUCCEEDED(m_ppd->SetProgress64(m_uliBytesCompleted.QuadPart, m_uliBytesTotal.QuadPart)));
// Reset because _CalcUploadProgress() can take a long time and the estimated time
// is based on the time between ::StartProgressDialog() and the first
// ::SetProgress() call.
EVAL(SUCCEEDED(m_ppd->Timer(PDTIMER_RESET, NULL)));
}
hr = _DoCopyIteration();
}
if (m_ppd)
{
EVAL(SUCCEEDED(m_ppd->StopProgressDialog()));
ATOMICRELEASE(m_ppd);
}
SHCoUninitialize(hrOleInit);
Release();
return hr;
}
HRESULT CDropOperation::DoOperation(BOOL fAsync)
{
HRESULT hr = S_OK;
AddRef();
if (fAsync)
{
HANDLE hThread;
DWORD dwThreadId;
hThread = CreateThread(NULL, 0, CDropOperation::_ThreadProc, this, 0, &dwThreadId);
if (hThread)
CloseHandle(hThread);
else
{
TraceMsg(TF_ERROR, "CDropOperation::DoOperation() CreateThread() failed and GetLastError()=%lu.", GetLastError());
Release();
}
}
else
hr = _ThreadProcCB();
return hr;
}
/****************************************************\
FUNCTION: _CalcUploadProgress
DESCRIPTION:
\****************************************************/
HRESULT CDropOperation::_CalcUploadProgress(void)
{
HRESULT hr = S_OK;
LPCWSTR pszzFSSource = m_pszzFSSource;
LPCWSTR pszzFtpDest = m_pszzFtpDest;
WCHAR wzProgressDialogStr[MAX_PATH];
m_uliBytesCompleted.QuadPart = 0;
m_uliBytesTotal.QuadPart = 0;
// Tell the user we are calculating how long it will take.
if (EVAL(LoadStringW(HINST_THISDLL, IDS_PROGRESS_UPLOADTIMECALC, wzProgressDialogStr, ARRAYSIZE(wzProgressDialogStr))))
EVAL(SUCCEEDED(m_ppd->SetLine(2, wzProgressDialogStr, FALSE, NULL)));
while (S_OK == hr)
{
WCHAR szFSSource[MAX_PATH];
WCHAR szFtpDest[MAX_PATH];
hr = _EnumOneHdrop(&pszzFSSource, &pszzFtpDest, szFSSource, ARRAYSIZE(szFSSource), szFtpDest, ARRAYSIZE(szFtpDest));
if (S_OK == hr)
hr = _CalcSizeOneHdrop(szFSSource, szFtpDest, m_ppd);
}
if (FAILED(hr))
TraceMsg(TF_ALWAYS, "CDropOperation::_CalcUploadProgress() Calculating the upload time failed, but oh well.");
return hr;
}
HRESULT CDropOperation::_CalcSizeOneHdrop(LPCWSTR pszFSSource, LPCWSTR pszFtpDest, IProgressDialog * ppd)
{
HRESULT hr;
WCHAR wzTo[MAX_PATH];
EVAL(SUCCEEDED(m_pfd->GetDisplayPath(wzTo, ARRAYSIZE(wzTo))));
pszFtpDest = PathFindFileName(pszFtpDest);
COPYONEHDROPINFO cohi = {0};
cohi.pff = m_pff;
cohi.pszFSSource = pszFSSource;
cohi.pszFtpDest = pszFtpDest;
cohi.pszDir = wzTo;
cohi.dwOperation = COHDI_FILESIZE_COUNT;
cohi.ops = opsPrompt;
cohi.fIsRoot = TRUE;
cohi.pmlc = &m_mlc;
cohi.pidlServer = FtpCloneServerID(m_pff->GetPrivatePidlReference());
cohi.progInfo.ppd = ppd;
cohi.fFireChangeNotify = TRUE;
cohi.progInfo.uliBytesCompleted.QuadPart = m_uliBytesCompleted.QuadPart;
cohi.progInfo.uliBytesTotal.QuadPart = m_uliBytesTotal.QuadPart;
hr = m_pfd->WithHint(NULL, m_hwnd, CopyCB, &cohi, NULL, m_pff);
if (SUCCEEDED(hr))
{
m_uliBytesCompleted = cohi.progInfo.uliBytesCompleted;
m_uliBytesTotal = cohi.progInfo.uliBytesTotal;
}
ILFree(cohi.pidlServer);
return hr;
}
/****************************************************\
FUNCTION: CDropOperation
DESCRIPTION:
\****************************************************/
HRESULT CDropOperation::_DoCopyIteration()
{
HRESULT hr = S_OK;
LPCTSTR pszzFSSource = m_pszzFSSource;
LPCTSTR pszzFtpDest = m_pszzFtpDest;
m_ops = opsPrompt;
while (S_OK == hr)
{
WCHAR szFSSource[MAX_PATH];
WCHAR szFtpDest[MAX_PATH];
hr = _EnumOneHdrop(&pszzFSSource, &pszzFtpDest, szFSSource, ARRAYSIZE(szFSSource), szFtpDest, ARRAYSIZE(szFtpDest));
if (S_OK == hr)
{
szFSSource[lstrlenW(szFSSource)+1] = 0; // Double terminate for SHFileOperation(Delete) in move case
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -