WinRT Асинхронные файловые операции в C++

В настоящее время я работаю над приложением метро, ​​которое требует нескольких текстовых ресурсов. Частью процесса сборки является копирование всех этих ресурсов в папку внутри установочного каталога приложения. Я хотел бы собрать список этих файлов ресурсов и обработать каждый из них соответствующим образом. К сожалению, мои попытки сделать это были менее чем успешными.

Поскольку я создаю для WinRT, я не могу использовать очень полезные функции "FindFirstFile" и "FindNextFile". Я пытался выполнить работу, используя асинхронные операции ввода-вывода файлов WinRT.

auto getResourceFolder = installedLocation->GetFolderFromPathAsync(  folderPath  );

getResourceFolder->Completed = ref new Windows::Foundation::AsyncOperationCompletedHandler< Windows::Storage::StorageFolder^ >( 
[this]( Windows::Foundation::IAsyncOperation< Windows::Storage::StorageFolder^ >^ operation ) {

    if( operation->Status == Windows::Foundation::AsyncStatus::Completed ) {

        auto resourceFolder = operation->GetResults();
        auto getResourceFiles = resourceFolder->GetFilesAsync();
        getResourceFiles->Completed = ref new Windows::Foundation::AsyncOperationCompletedHandler< IVectorView< Windows::Storage::IStorageFile^ >^ >( 
        [this]( Windows::Foundation::IAsyncOperation< IVectorView< Windows::Storage::IStorageFile^ >^ >^ operation ) {

            if( operation->Status == Windows::Foundation::AsyncStatus::Completed ) {

                auto resourceFiles = operation->GetResults();

                for( unsigned int i = 0; i < resourceFiles->Size; ++i ) {

                    // Process File
                }

            }

        });

    }

});

Который не компилируется:

ошибка C2664: "Windows:: Foundation:: IAsyncOperation:: Completed:: set": невозможно преобразовать параметр 1 из "Windows::Foundation::AsyncOperationCompletedHandler ^" в "Windows::Foundation::AsyncOperationCompletedHandler< TResult> ^ '

Ошибка не имеет никакого смысла для меня. Я попытался переписать приведенный выше код, чтобы лямбда-функции не были встроенными, но это не имело значения. Я не уверен, что не так.

Есть идеи? Заранее спасибо.

2 ответа

Решение

[Примечание: для краткости я опустил большинство квалификаций пространства имен в коде и сообщениях об ошибках.]

На панели "Список ошибок Visual Studio" отображается только первая строка каждой ошибки (это очень полезная функция, особенно при программировании на C++, поскольку некоторые сообщения об ошибках от компилятора очень длинные. Вам нужно посмотреть в окне "Вывод", чтобы увидеть Остальная часть сообщения об ошибке:

error C2664: 'IAsyncOperation<TResult>::Completed::set' : 
cannot convert parameter 1 
    from 'AsyncOperationCompletedHandler<TResult> ^'
    to   'AsyncOperationCompletedHandler<TResult> ^'
with
[
    TResult=IVectorView<StorageFile ^> ^ 
]
and
[
    TResult=IVectorView<IStorageFile ^> ^
]
and
[
    TResult=IVectorView<StorageFile ^> ^
]
No user-defined-conversion operator available, or
Types pointed to are unrelated;
conversion requires reinterpret_cast, C-style cast or function-style cast

Это все еще немного сбивает с толку, потому что все три шаблона используют параметр с именем TResult, Чтобы расшифровать ошибку, обратите внимание, что порядок шаблонов в первой строке соответствует порядку списков аргументов шаблона в оставшейся части строки.

Проблема в том, что вы смешиваете использование StorageFile а также IStorageFile, На обеих этих линиях вам нужно использовать StorageFile (см. морковь под строкой где IStorageFile используется):

getResourceFiles->Completed = ref new Windows::Foundation::AsyncOperationCompletedHandler< IVectorView< Windows::Storage::IStorageFile^ >^ >( 
                                                                                                                          ^
[this]( Windows::Foundation::IAsyncOperation< IVectorView< Windows::Storage::IStorageFile^ >^ >^ operation ) {
                                                                             ^

Обратите внимание, что как только вы исправите эту проблему, вы получите еще одну пару ошибок, потому что ваши лямбды должны иметь два параметра; второй является AsyncStatus, В конце они оба должны быть объявлены как:

// Namespaces omitted for brevity
[this](IAsyncOperation<StorageFolder^>^ operation, AsyncStatus status) { }

Так как я строю для WinRT, я не могу использовать очень полезный FindFirstFile а также FindNextFile функции.

Обратите внимание, что вы можете использовать оба FindFirstFileEx а также FindNextFile в приложении в стиле Metro. (Затем на- ExFindFirstFile не используется).

Вы должны использовать асинхронные функции WinRT везде, где это возможно и везде, где это возможно, но это не означает, что эти другие функции по-прежнему не используются.

Гораздо более простым решением является использование PPL для асинхронных операций. Вместо того, чтобы вручную выполнять асинхронную операцию, попробуйте:

create_task(installedLocation->GetFolderFromPathAsync(folderPath)
.then([this](Windows::Storage::StorageFolder^ folder) { 
    return folder->GetFilesAsync();
})
.then([this](IVectorView<Windows::Storage::StorageFile^ >^ files) { 
    for( unsigned int i = 0; i < files->Size; ++i ) { 
         // Process File 
    } 
}); 

Я не на 100% по синтаксису, это было написано в редакторе кода SO, но оно показывает, как PPL значительно снижает сложность такого рода кода - в основном вы используете create_task чтобы создать задачу, затем используйте .then метод на задании, чтобы указать лямбда, которая используется для асинхронного завершения.

РЕДАКТИРОВАТЬ: Обновлено, чтобы удалить вложенную лямбду.

Другие вопросы по тегам