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. (Затем на- Ex
FindFirstFile
не используется).
Вы должны использовать асинхронные функции 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
метод на задании, чтобы указать лямбда, которая используется для асинхронного завершения.
РЕДАКТИРОВАТЬ: Обновлено, чтобы удалить вложенную лямбду.