原因是您正在从 UI 线程调用 concurrency::task.wait() 或 concurrency::task.get() !该框架会引发异常以防止您冻结应用程序。请参阅:在 C++ 中为 Metro 风格的应用程序创建异步操作,底部有三个警告。最后一个警告说:
不要在 STA 上运行的延续主体中调用 concurrency::task::wait。否则,运行时会抛出 concurrency::invalid_operation,因为此方法会阻塞当前线程并可能导致应用程序无响应。
我编写了一个测试应用程序并验证我可以通过从单独的线程调用我的 WinRT 组件来使一切正常!
详情如下:
我的测试应用程序是 C# XAML Metro 应用程序,它调用 WinRT 组件以从文件中加载字符串。它有一个按钮和一个文本块。
资源加载器如下所示:
class WstringCaselessLess : std::binary_function< std::wstring, std::wstring, bool >
{
public:
bool operator()( const std::wstring& s1, const std::wstring& s2 )
{
return _wcsicmp( s1.c_str(), s2.c_str() ) < 0;
}
};
public ref class ComponentResourceLoader sealed
{
public:
Platform::String^ GetStringResource( Platform::String^ uri )
{
auto key = std::wstring( uri->Data(), uri->Length() );
auto findit = m_resourceMap.find( key );
if ( findit != std::end( m_resourceMap ) )
return ref new Platform::String( findit->second.c_str() );
auto uriObj = ref new Windows::Foundation::Uri( uri );
auto fileOp = Windows::Storage::StorageFile::GetFileFromApplicationUriAsync( uriObj );
return concurrency::create_task( fileOp )
.then( [this, &key]( Windows::Storage::StorageFile^ file )
-> Windows::Foundation::IAsyncOperation< Windows::Storage::Streams::IBuffer^ >^
{
return Windows::Storage::FileIO::ReadBufferAsync( file );
} )
.then( [this, &key]( Windows::Storage::Streams::IBuffer^ buffer )
-> Platform::String^
{
auto reader = Windows::Storage::Streams::DataReader::FromBuffer( buffer );
auto str = reader->ReadString( buffer->Length );
this->m_resourceMap[key] = std::wstring( str->Data(), str->Length() );
return str;
} ).get();
}
private:
std::map< std::wstring, std::wstring, WstringCaselessLess > m_resourceMap;
};
损坏的按钮单击处理程序如下所示:
private void WinRT_Click_1(object sender, RoutedEventArgs e)
{
TextContent.Text = m_loader.GetStringResource(@"ms-appx:///Assets/Hello.xml");
}
如果我更改按钮处理程序以将字符串加载到单独的线程中,它会起作用:
private async void WinRT_Click_1(object sender, RoutedEventArgs e)
{
var text = await Task.Run<string>(() => RunWinrtLoader());
TextContent.Text = text;
}
private string RunWinrtLoader()
{
return m_loader.GetStringResource(@"ms-appx:///Assets/Hello.xml");
}
希望这对某人有帮助!这确实让我很生气一段时间,因为没有迹象表明从错误到真正的问题。