如何:使用 IFileOperation 显示进度对话框

Posted

技术标签:

【中文标题】如何:使用 IFileOperation 显示进度对话框【英文标题】:HowTo: Display progress dialog using IFileOperation 【发布时间】:2016-01-06 13:40:09 【问题描述】:

我正在尝试在一些示例代码中为我的复制操作显示一个进度对话框。我使用 IFileOperation 是因为我发现如果文件已经复制到目标位置,使用 SHFileOperation显示进度对话框。我希望 IFileOperation 更复杂一点,可以处理这种情况。 这是我尝试过的示例代码……

CComPtr<IOperationsProgressDialog> opProgressDlg;
HRESULT hr = opProgressDlg.CoCreateInstance(CLSID_ProgressDialog);

CComPtr<IFileOperation> fileOp;
hr = fileOp.CoCreateInstance(CLSID_FileOperation);
hr = fileOp->SetOperationFlags(FOF_RENAMEONCOLLISION | FOFX_PRESERVEFILEEXTENSIONS | FOFX_NOMINIMIZEBOX);
hr = fileOp->SetProgressDialog(opProgressDlg);

hr = opProgressDlg->StartProgressDialog(m_hWnd, OPPROGDLG_DEFAULT);
hr = opProgressDlg->SetMode(PDM_DEFAULT);
hr = opProgressDlg->SetOperation(SPACTION_COPYING);
oldDirectory += _T("*.*");

CFileFind finder;
BOOL bWorking = finder.FindFile(oldDirectory);
while (bWorking)
    
    bWorking = finder.FindNextFile();
    if (finder.IsDots())
        continue;
    CString name = finder.GetFilePath();
    IShellItem *psiFrom = nullptr;
    hr = SHCreateItemFromParsingName(CT2CW(name), NULL, IID_PPV_ARGS(&psiFrom));
    IShellItem *psiTo = NULL;
    hr = SHCreateItemFromParsingName(CT2CW(newDirectory), NULL, IID_PPV_ARGS(&psiTo));
    hr = fileOp->CopyItem(psiFrom, psiTo, CT2CW(finder.GetFileName()), NULL);
    //hr = opProgressDlg->UpdateLocations(psiFrom, psiTo, psiTo);
    

opProgressDlg->StopProgressDialog();

hr = fileOp->PerformOperations();

示例正在尝试将所有文件和文件夹从一个位置 (oldDirectory) 复制到另一个位置 (newDirectory)。 复制操作会正确复制所有内容。我正在寻求帮助以在操作期间显示进度对话框。根据 IFileOperation,我应该可以通过IOperationsProgressDialog 设置进度对话框。这方面的文档非常薄。我还没有找到任何样本来展示如何将两者结合在一起。有人对这两个接口有经验吗?

【问题讨论】:

您不会自动获得进度对话框吗?无论如何,我自己没有玩过它,但IOperationsProgressDialog::StartProgressDialog 的文档说它应该在单独的线程上创建。 @JonathanPotter 你会认为是这样,但是,这不是我发现的。您需要为进度对话框建立一个额外的界面这一事实让我有点困惑。我当然可以在另一个线程中尝试它,但是,我觉得它不止于此。 【参考方案1】:

如果您只需要进度对话框,则删除对IOperationsProgressDialog的引用

CopyItem 只准备要复制的项目,因此IOperationsProgressDialog::Update... 不会更新任何 UI。实际复制在调用PerformOperations 时开始。

如果只有几个文件,UI 对话框将不会显示,因为它完成得太快了。也许您想删除 FOF_RENAMEONCOLLISION 以使其更易于测试。这应该与SHFileOperation 完全相同。

CString srcDir = L"c:\\test\\src";
CString dstDir = L"c:\\test\\dst";

CComPtr<IFileOperation> fileOp;
fileOp.CoCreateInstance(CLSID_FileOperation);
fileOp->SetOperationFlags(FOFX_SHOWELEVATIONPROMPT);

srcDir += L"\\*";
CFileFind finder;
BOOL next = finder.FindFile(srcDir);
while (next)

    next = finder.FindNextFile();
    if (finder.IsDots())
        continue;

    CComPtr<IShellItem> src, dst;
    if (S_OK != SHCreateItemFromParsingName(finder.GetFilePath(), NULL, IID_PPV_ARGS(&src)))
        continue;

    if (S_OK != SHCreateItemFromParsingName(dstDir, NULL, IID_PPV_ARGS(&dst)))
        continue;

    fileOp->CopyItem(src, dst, 0, NULL);


MessageBox(L"nothing copied so far...");
hr = fileOp->PerformOperations();
MessageBox(L"done...");

【讨论】:

您是否尝试过 FOF_SIMPLEPROGRESS 标志?我使用您的 cmets 重新编写了示例。进度对话框根本没有出现。 是的,我尝试了代码。 SHFileOperation 也可以。您可能只复制了几个文件,并且它设置为自动重命名文件,这就是为什么没有显示。 在对代码进行了更多研究后,我接受了您的回答。文件的数量确实会影响对话框是否会显示(并且,这是合乎逻辑的)。我复制了一个大(千兆字节)结构,它确实显示一致。但是,我确实不需要需要使用 FOF_SIMPLEPROGRESS 标志。 你是对的,FOF_SIMPLEPROGRESS 甚至不是一个有效的标志,它是为了SHFileOperation 我编辑了答案。您说主要问题是某些文件没有被复制,可能与 FOFX_SHOWELEVATIONPROMPT 之类的另一个标志有关。另外我添加了错误处理以确保 CopyItem 的参数有效。 与avoid shell extension hassles 无关但很重要,如果您是using this code from a service 更是如此:确保另外将FOFX_NO­COPY­HOOKS 传递给SetOperationFlags()

以上是关于如何:使用 IFileOperation 显示进度对话框的主要内容,如果未能解决你的问题,请参考以下文章

Delphi:如何使用进度条显示 CreateProcess 的进度?

如何使用 savefiledialog 在进度条上显示进度?

如何使用 swift 显示带有进度条的 AVAudioPlayer?

如何使用 C# HttpClient PostAsync 显示上传进度

如何使用逆时针动画显示自定义圆形进度条?

如何使用 Plotly Javascript 显示循环进度图