Асинхронные файловые операции 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‹TResult>::Completed::set»: невозможно преобразовать параметр 1 из «Windows::Foundation::AsyncOperationCompletedHandler‹TResult> ^» в «Windows::Foundation::AsyncOperationCompletedHandler‹ TРезультат> ^'

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

Любые идеи? Заранее спасибо.


person Jeff    schedule 31.03.2012    source источник
comment
Вероятно, вам следует использовать task<T> и его метод then() вместо того, что вы делаете. Это сделает ваш код короче и понятнее.   -  person svick    schedule 31.03.2012
comment
Согласен со svick: ppl — ваш друг.   -  person ReinstateMonica Larry Osterman    schedule 31.03.2012


Ответы (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. (не-Ex FindFirstFile использовать нельзя).

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

person James McNellis    schedule 31.03.2012
comment
Почему у нас есть и operation, и status? operation->Status равно status? - person Zingam; 25.11.2016

Гораздо более простое решение — использовать 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 для задача, чтобы указать лямбду, которая используется для асинхронного завершения.

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

person ReinstateMonica Larry Osterman    schedule 31.03.2012
comment
Я предпочитаю эту структуру. Спасибо за чаевые. - person Jeff; 03.04.2012
comment
Я только что разговаривал с экспертом по PPL (в соседнем офисе), и для этого есть лучшая форма. Обновлен мой ответ, чтобы отразить это. - person ReinstateMonica Larry Osterman; 03.04.2012
comment
Потрясающе, это выглядит великолепно. Спасибо еще раз. Жаль, что я не могу принять несколько ответов... - person Jeff; 03.04.2012