实战经验:使用IFileOperationProgressSink接收文件操作通知

实战经验:使用IFileOperationProgressSink接收文件操作通知

作者:BlogUpdater |  时间:2018-11-04 |  浏览:5124 |  评论已关闭 条评论

思路

新版本的文件操作可以使用IFileOperation接口来实现,IFileOperation接口用来替代旧的SHFileOperation。SHFileOperation可以实现基本的文件操作,如复制,剪切,删除,重命名等,但缺乏文件操作进度通知这一特性。有时候,我们希望能得到文件的操作进度,进而在界面上进行操作进度的可视化呈现,那么,试试新的IFileOperation接口吧。

要想接收IFileOperation的通知,需要先实现IFileOperationProgressSink接口,该接口中的一些方法可以在文件操作的前后被IFileOpeation实例调用,例如复制前调用你实现的PreCopyItem方法,复制后则调用的是PostCopyItem方法。另外,如果想得到文件操作的进度通知,直接实现IFileOperationProgressSink的UpdateProgress方法就可以了,这样文件操作的进度更新时,我们的应用程序就可以知道了。

以下是示例代码

class CFileOperationSink : public IFileOperationProgressSink
{
public:
	CFileOperationSink(HWND hWndNotify = NULL);
	~CFileOperationSink(void);

public:
	// 实现IUnknown接口
	IFACEMETHODIMP QueryInterface(REFIID riid, void **ppv);
	IFACEMETHODIMP_(ULONG) AddRef();
	IFACEMETHODIMP_(ULONG) Release();

	// 实现IFileOperationProgressSink接口
	IFACEMETHODIMP StartOperations();
	IFACEMETHODIMP FinishOperations(HRESULT hrResult);
	IFACEMETHODIMP PreRenameItem(DWORD /*dwFlags*/, IShellItem * /*psiItem*/, PCWSTR /*pszNewName*/);
	IFACEMETHODIMP PostRenameItem(DWORD /*dwFlags*/, IShellItem * /*psiItem*/, PCWSTR /*pszNewName*/, HRESULT /*hrRename*/, IShellItem * /*psiNewlyCreated*/);
	IFACEMETHODIMP PreMoveItem(DWORD /*dwFlags*/, IShellItem * /*psiItem*/, IShellItem * /*psiDestinationFolder*/, PCWSTR /*pszNewName*/);
	IFACEMETHODIMP PostMoveItem(DWORD /*dwFlags*/, IShellItem * /*psiItem*/,IShellItem * /*psiDestinationFolder*/, PCWSTR /*pszNewName*/, HRESULT /*hrNewName*/, IShellItem * /*psiNewlyCreated*/);
	IFACEMETHODIMP PreCopyItem(DWORD dwFlags, IShellItem *psiItem,IShellItem *psiDestinationFolder, PCWSTR pszNewName);
	IFACEMETHODIMP PostCopyItem(DWORD dwFlags, IShellItem *psiItem, IShellItem *psiDestinationFolder, PCWSTR pwszNewName, HRESULT hrCopy, IShellItem *psiNewlyCreated);
	IFACEMETHODIMP PreDeleteItem(DWORD /*dwFlags*/, IShellItem * /*psiItem*/);
	IFACEMETHODIMP PostDeleteItem(DWORD /*dwFlags*/, IShellItem * /*psiItem*/, HRESULT /*hrDelete*/, IShellItem * /*psiNewlyCreated*/);
	IFACEMETHODIMP PreNewItem(DWORD /*dwFlags*/, IShellItem * /*psiDestinationFolder*/, PCWSTR /*pszNewName*/);
	IFACEMETHODIMP PostNewItem(DWORD /*dwFlags*/, IShellItem * /*psiDestinationFolder*/,PCWSTR /*pszNewName*/, PCWSTR /*pszTemplateName*/, DWORD /*dwFileAttributes*/, HRESULT /*hrNew*/, IShellItem * /*psiNewItem*/);
	IFACEMETHODIMP UpdateProgress(UINT iWorkTotal, UINT iWorkSoFar);
	IFACEMETHODIMP ResetTimer();
	IFACEMETHODIMP PauseTimer();
	IFACEMETHODIMP ResumeTimer();

private:
	HWND m_hWndNotify;
};
HRESULT FileCopy(LPCTSTR pszFrom, LPCTSTR pszTo)
{
	HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
	if (FAILED(hr))
	{
		return hr;
	}

	IFileOperation * pfo = NULL;
	hr = CoCreateInstance(CLSID_FileOperation, NULL, CLSCTX_ALL, IID_PPV_ARGS(&pfo));
	if (FAILED(hr))
	{
		CoUninitialize();
		return hr;
	}

	CFileOperationSink * pSink = new CFileOperationSink();
	DWORD dwCookie = 0;
	hr = pfo->Advise(pSink, &dwCookie);
	if (FAILED(hr))
	{
		if (pfo != NULL)
		{
			pfo->Release();
			pfo = NULL;
		}
		CoUninitialize();
		return hr;
	}

	hr = pfo->SetOperationFlags(FOF_SILENT);
	if (FAILED(hr))
	{
		if (pfo != NULL)
		{
			pfo->Release();
			pfo = NULL;
		}
		CoUninitialize();
		return hr;
	}

	// Create an IShellItem from the supplied source path
	IShellItem * psiFrom = NULL;
	hr = SHCreateItemFromParsingName(pszFrom, NULL, IID_PPV_ARGS(&psiFrom));
	if (FAILED(hr))
	{
		if (pfo != NULL)
		{
			pfo->Release();
			pfo = NULL;
		}
		CoUninitialize();
		return hr;
	}

	// Create an IShellItem from the supplied destination path
	IShellItem * psiTo = NULL;
	hr = SHCreateItemFromParsingName(pszTo, NULL, IID_PPV_ARGS(&psiTo));
	if (FAILED(hr))
	{
		if (psiFrom != NULL)
		{
			psiFrom->Release();
			pszFrom = NULL;
		}
		if (pfo != NULL)
		{
			pfo->Release();
			pfo = NULL;
		}
		CoUninitialize();
		return hr;
	}

	hr = pfo->CopyItem(psiFrom, psiTo, NULL, NULL);
	if (FAILED(hr))
	{
		if (psiFrom != NULL)
		{
			psiFrom->Release();
			pszFrom = NULL;
		}
		if (psiTo != NULL)
		{
			psiTo->Release();
			psiTo = NULL;
		}
		if (pfo != NULL)
		{
			pfo->Release();
			pfo = NULL;
		}
		CoUninitialize();
		return hr;
	}

	hr = pfo->PerformOperations();
	if (FAILED(hr))
	{
		if (psiFrom != NULL)
		{
			psiFrom->Release();
			pszFrom = NULL;
		}
		if (psiTo != NULL)
		{
			psiTo->Release();
			psiTo = NULL;
		}
		if (pfo != NULL)
		{
			pfo->Release();
			pfo = NULL;
		}
		CoUninitialize();
		return hr;
	}

	if (psiFrom != NULL)
	{
		psiFrom->Release();
		pszFrom = NULL;
	}
	if (psiTo != NULL)
	{
		psiTo->Release();
		psiTo = NULL;
	}

	hr = pfo->Unadvise(dwCookie);

	if (pfo != NULL)
	{
		pfo->Release();
		pfo = NULL;
	}
	CoUninitialize();

	return hr;
}

总结
以上代码展示了如何通过一个类CFileOperationSink来实现IFileOperationProgressSink接口,也给出了IFileOperation的使用方法,但是需要注意的是,实际工程中,为了避免出现接口忘记释放或者重复释放的问题,推荐使用CComPtr智能指针进行接口操作。
关于COM智能指针的使用,请参考我的前一篇文章。

标签:

评论已关闭。