Search code examples
uwpc++-winrt

IVectorView of StorageFile becomes null after OpenReadAsync in a loop (possible winrt bug)


I am creating a runtime class inside the BlankApp project template that opens a IVectorView<StorageFile> that it receives by reference as a parameter. It then loops over the vector in order to read from the files. However when I try to use the vector after the call to read, it throws a read access violation.

The reason why I think this is a bug is because it only happens when I compile using the x64 configuration of the BlankApp project. In x86 the exception is not thrown.

This is pretty easy to reproduce so it would be nice if someone else could confirm if this happens to them.

//test_class.idl

[bindable]
[default_interface]
runtimeclass test_class
{
    test_class();

    Windows.Foundation.IAsyncAction read_files(Windows.Foundation.Collections.IVectorView<Windows.Storage.StorageFile> files);
}
//test_class.cpp
Windows::Foundation::IAsyncAction test_class::read_files(Windows::Foundation::Collections::IVectorView<Windows::Storage::StorageFile> const& files)
{
    for (auto& file : files)
    {
        auto res = files;
        auto stream = co_await file.OpenReadAsync();
        auto res2 = files; // read access violation. this->**m_ptr** was 0xFFFFFFFFFFFFFFFF.
    }

    co_return;
}
//MainPage.cpp
Windows::Foundation::IAsyncAction MainPage::onclick_button(Windows::Foundation::IInspectable const & sender, Windows::UI::Xaml::RoutedEventArgs const & args)
{
    BlankApp1::test_class m_test_class = winrt::make<BlankApp1::implementation::test_class>();

    Windows::Storage::Pickers::FileOpenPicker picker;
    picker.FileTypeFilter().Append(L".bmp");

    Windows::Foundation::Collections::IVectorView<Windows::Storage::StorageFile> files = co_await picker.PickMultipleFilesAsync();

    co_await m_test_class.read_files(files);
}

Solution

  • This is happening because you're passing an arg by reference to an asynchronous method. During the co_await, the calling function (onclick_button) may have cleaned up the objects your reference is referring to, basically resulting in a dangling reference. To avoid this, your coroutines should accept parameters by value, not by reference.

    See the following section for more details: https://learn.microsoft.com/en-us/windows/uwp/cpp-and-winrt-apis/concurrency#parameter-passing