How to update progress in UI using IAsyncOperationWithProgress from within a callback

73 Views Asked by At

I have following code structure:

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;

    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;
            hFile = CreateFileW(str.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
            if (INVALID_HANDLE_VALUE == hFile)
            {
                gle = GetLastError();
                hr = THR(HRESULT_FROM_WIN32(gle));
            }
            else
            {
                BOOL b = GetFileSizeEx(hFile, &li);
                if (!b)
                {
                    gle = GetLastError();
                    hr = THR(HRESULT_FROM_WIN32(gle));
                }
                else
                {
                    if (0 != li.HighPart)
                    {
                        hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
                    }
                    else
                    {
                        m_progress.Status = TransferStatus::InProgress;
                        f_taskProgress.set_result(m_progress.Status);
                        _cbSize = li.LowPart;

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

                        hr = THR(session.PutObject(
                            _szFilename, NULL, hFile, _cbSize, &s_StatusCallback /*s_StatusCallback*/, this));
                    }
                }
                CloseHandle(hFile);
                hFile = NULL;
            }
            if (FAILED(hr))
            {
                break;
            }
            else
            {
                m_progress.FilesSentSuccessfully += 1;
            }
        }

        f_taskProgress(m_progress);

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

HRESULT
TransferClient::s_StatusCallback(LPVOID pvIn, ULONG cbTransmittedIn)
{
    TransferClient* pthis = (TransferClient*)pvIn;

    return pthis->StatusCallback(cbTransmittedIn);

}


HRESULT
TransferClient::StatusCallback(ULONG cbTransmittedIn)
{
    m_progress.BytesSent = cbTransmittedIn;

    // Not able to access f_taskProgress
    // since it is a local variable to the above async function
    f_taskProgress(m_progress);
    HRETURN(S_OK);
}

The problem is function PutObject takes a C style callback function pointer. It calls this callback when some bytes are transferred and I want that progress to update in UI. So I created a static function on the class and pass that. But now, I cannot access my progress token inside this callback even when I have this pointer. I cannot store it on class since its type is auto. I tried with local struct within TransferAsync and static method but it will not be a C-style function pointer that PutObject is expecting. PutObject is not mine so cannot modify it. So, how do I update the progress from the callback?

0

There are 0 best solutions below