0

我目前正在研究一個需要幾個文本資源的metro應用程序。構建過程的一部分是將所有這些資源複製到應用程序安裝目錄內的文件夾中。我想要做的是收集這些資源文件的列表,並相應地處理每一個。不幸的是,我的嘗試並不成功。WinRT C++中的異步文件操作

由於我爲WinRT構建,我無法使用非常有用的「FindFirstFile」和「FindNextFile」函數。我一直在嘗試使用WinRT異步文件IO操作完成工作。

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: '視窗:基金會:: IAsyncOperation < TResult> ::完成::設置':無法從「視窗轉換參數1 ::基金會:: AsyncOperationCompletedHandler < TResult> ^」到 '視窗:基金會:: AsyncOperationCompletedHandler < TResult> ^'

該錯誤不作出任何意義,我。我試着重寫上面的代碼,以便lambda處理函數不是內聯的,但它沒有區別。我不確定有什麼問題。

任何想法?提前致謝。

+1

你應該使用的,而不是你做什麼任務''及其'然後()'方法。它會使你的代碼更簡潔更清晰。 – svick 2012-03-31 10:47:58

+0

同意svick:ppl是你的朋友。 – 2012-03-31 15:57:36

回答

5

[注:我已刪去最名稱空間限定從代碼和錯誤消息爲簡潔。]

在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的參數。要解密錯誤,請注意o f第一行中的模板與該行其餘部分中模板參數列表的順序相匹配。

這裏的問題是,您正在混合使用StorageFileIStorageFile。在這兩行的,你需要使用StorageFile(參見下線路胡蘿蔔在使用IStorageFile):

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

需要注意的是,一旦你解決這個問題,你會得到另一對錯誤的,因爲你需要lambda表達式有兩個參數;第二個是AsyncStatus。最終,他們都應該被聲明爲:

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

由於我建設WinRT的,我不能使用非常有用FindFirstFileFindNextFile功能。

需要注意的是,你可以,事實上,在Metro風格的應用程序同時使用FindFirstFileExFindNextFile。 (非ExFindFirstFile不可用)。

無論您應該儘可能使用異步WinRT的功能,無論是實際的,但是,這並不意味着沒有還爲這些其他功能的使用。

+0

爲什麼我們既有'操作'又有'狀態'? 「操作 - >狀態」等於「狀態」? – Zingam 2016-11-25 17:18:52

4

一個簡單得多的解決方案是使用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方法來指定用於異步完成的lambda。

編輯:更新,刪除嵌套的拉姆達。

+0

我更喜歡這種結構。謝謝你的提示。 – Jeff 2012-04-02 20:11:49

+1

我剛剛和一位PPL專家(在我旁邊的辦公室)交談過,這裏有一個更好的形式。更新我的回答以反映這一點。 – 2012-04-02 20:34:19

+0

太棒了,這看起來不錯。再次感謝。太糟糕了,我不能接受多個答案... – Jeff 2012-04-02 21:50:22