You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C风格回调中通过IAsyncOperationWithProgress更新UI进度

解决C++/WinRT异步函数中通过C风格回调更新UI进度的问题

问题核心

第三方PutObject函数仅支持C风格回调,字节传输时触发回调更新进度,但异步函数TransferAsync内的进度token(f_taskProgress)是局部变量,且类型为auto无法直接存储为类成员,导致回调无法访问该token更新UI进度。


解决方案思路

将进度token与类实例指针封装为上下文结构体,通过PutObject的用户参数传递给回调,确保回调能获取到进度token。同时用智能指针管理上下文生命周期,避免悬空指针问题。


具体实现代码

winrt::Windows::Foundation::IAsyncOperationWithProgress<Transfer::TransferStatus, Transfer::TransferProgress> Windows::TransferClient::TransferAsync(winrt::Windows::Foundation::Collections::IVector<hstring> filesToSend)
{
    co_await winrt::resume_background();
    auto f_taskProgress{ co_await winrt::get_progress_token() };
    f_taskProgress.set_result(m_progress.Status);
    m_progress.FilesSentSuccessfully = 0;

    // 定义上下文结构体,保存进度token和类实例指针
    struct CallbackContext
    {
        decltype(f_taskProgress) progressToken;
        TransferClient* client;
    };
    // 用shared_ptr确保上下文生命周期覆盖异步操作与回调
    auto context = std::make_shared<CallbackContext>();
    context->progressToken = std::move(f_taskProgress);
    context->client = this;

    // 适配C风格的静态回调函数
    auto staticCallback = [](LPVOID pvIn, ULONG cbTransmittedIn) -> HRESULT {
        auto ctxPtr = static_cast<std::shared_ptr<CallbackContext>*>(pvIn);
        auto& progressToken = (*ctxPtr)->progressToken;
        auto client = (*ctxPtr)->client;

        client->m_progress.BytesSent = cbTransmittedIn;
        progressToken(client->m_progress);
        return S_OK;
    };

    try
    {
        uint32_t listSize = filesToSend.Size();
        m_progress.TotalFilesToSend = listSize;
        for (uint32_t i = 0; i < listSize; i++)
        {
            hstring file = filesToSend.GetAt(i);
            std::wstring str(file.c_str());

            m_progress.FileName = file;
            HANDLE hFile = CreateFileW(str.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
            if (INVALID_HANDLE_VALUE == hFile)
            {
                DWORD gle = GetLastError();
                HRESULT hr = HRESULT_FROM_WIN32(gle);
                THR(hr);
            }
            else
            {
                LARGE_INTEGER li{};
                BOOL b = GetFileSizeEx(hFile, &li);
                if (!b)
                {
                    DWORD gle = GetLastError();
                    HRESULT hr = HRESULT_FROM_WIN32(gle);
                    THR(hr);
                }
                else
                {
                    if (0 != li.HighPart)
                    {
                        HRESULT hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
                        THR(hr);
                    }
                    else
                    {
                        m_progress.Status = TransferStatus::InProgress;
                        context->progressToken.set_result(m_progress.Status);
                        DWORD _cbSize = li.LowPart;

                        WCHAR _szFilename[MAX_PATH];
                        StringCchCopy(_szFilename, ARRAYSIZE(_szFilename), file.c_str());

                        // 传入上下文指针,供回调使用
                        HRESULT hr = THR(session.PutObject(
                            _szFilename, NULL, hFile, _cbSize, staticCallback, &context));
                    }
                }
                CloseHandle(hFile);
            }
            if (FAILED(THR_GetLast()))
            {
                break;
            }
            else
            {
                m_progress.FilesSentSuccessfully += 1;
            }
        }

        context->progressToken(m_progress);
        m_progress.Status = TransferStatus::Completed;
        context->progressToken.set_result(m_progress.Status);
        co_return m_progress.Status;
    }
    catch (...)
    {
        std::wcout << winrt::to_message().c_str() << std::endl;
        co_return TransferStatus::Unknown;
    }
}

关键注意事项

  • 生命周期管理:必须用std::shared_ptr管理上下文,确保异步操作和回调执行期间上下文不会被销毁,避免悬空指针。
  • 回调兼容性:staticCallback采用空捕获lambda,可隐式转换为C风格函数指针,符合PutObject的参数要求。
  • 变量冲突:代码中调整了局部变量(如hFile、gle)的声明,避免与类成员变量冲突,实际使用时需结合自身类定义调整。

内容的提问来源于stack exchange,提问作者rsp

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 02:35:16