سؤال

I'm currently working on a metro app that requires a few textual resources. Part of the build process is copying all of these resources to a folder inside of the app's installation directory. What I'd like to do is gather a list of these resource files, and process each one accordingly. Unfortunately, my attempts to do so have been less than successful.

Since I'm building for WinRT, I can't use the very useful "FindFirstFile" and "FindNextFile" functions. I've been trying to get the job done using the WinRT Asynchronous file IO operations.

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
                }

            }

        });

    }

});

Which fails to compile:

error C2664: 'Windows::Foundation::IAsyncOperation<TResult>::Completed::set' : cannot convert parameter 1 from 'Windows::Foundation::AsyncOperationCompletedHandler<TResult> ^' to 'Windows::Foundation::AsyncOperationCompletedHandler<TResult> ^'

The error isn't making any sense to me. I've tried rewriting the above code so that the lambda handler functions are not inline, but it hasn't made a difference. I'm not sure what's wrong.

Any ideas? Thanks in advance.

هل كانت مفيدة؟

المحلول

[Note: I have omitted most namespace qualification from the code and error messages for brevity.]

The Visual Studio Error List pane only shows the first line of each error (this is a very useful feature, especially when programming in C++, because some error messages from the compiler are exceedingly long. You need to look at the Output window to see the rest of the error message:

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

This is still a bit confusing because all three templates use a parameter named TResult. To decipher the error, note that the order of the templates in the first line matches the order of the template argument lists in the rest of the line.

The issue here is that you are mixing usage of StorageFile and IStorageFile. On both of these lines, you need to use StorageFile (see carrots under lines for where IStorageFile is used):

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

Note that once you fix this issue, you'll get another pair of errors because your lambdas need to have two parameters; the second is an AsyncStatus. In the end, they should both be declared as:

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

Since I'm building for WinRT, I can't use the very useful FindFirstFile and FindNextFile functions.

Note that you can, in fact, use both FindFirstFileEx and FindNextFile in a Metro style app. (The non-Ex FindFirstFile is not usable).

You should use the asynchronous WinRT functions wherever you can and wherever it is practical, but that doesn't mean there isn't still a use for these other functions.

نصائح أخرى

A far simpler solution is to use PPL for your async operations. Instead of manually rolling the async operation, try:

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 
    } 
}); 

I'm not 100% on the syntax, this was written in the SO code editor, but it shows how PPL dramatically reduces the complexity of this kind of code - basically you use create_task to create a task, then use the .then method on the task to specify a lambda which is used for async completion.

EDIT: Updated to remove the nested lambda.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top