3

我一直在尝试使用 c++/cxStorageFile::ReadAsync()读取商店应用程序中的文件,但无论如何它总是返回无效的参数异常

// "file" are returned from FileOpenPicker
IRandomAccessStream^ reader = create_task(file->OpenAsync(FileAccessMode::Read)).get();
if (reader->CanRead)
{
    BitmapImage^ b = ref new BitmapImage();
    const int count = 1000000;
    Streams::Buffer^ bb = ref new Streams::Buffer(count);
    create_task(reader->ReadAsync(bb, 1, Streams::InputStreamOptions::None)).get();
}

我已经打开了所有清单功能,并为声明添加了“文件打开选择器”+“文件类型关联”。有任何想法吗 ?谢谢!

ps:我发现的大多数解决方案都是针对C#的,但是代码结构相似......

4

2 回答 2

5

如果此代码在 UI 线程(或任何其他单线程单元或 STA)上执行,则.get()如果任务尚未完成,则调用将抛出,因为调用.get()会阻塞线程。您不得阻塞 UI 线程或任何其他 STA,并且在启用 C++/CX 支持的情况下进行编译时,库会强制执行此操作。

如果您在调试器中打开第一次机会异常处理(Debug -> Exceptions...,选中 C++ Exceptions 复选框),您应该invalid_operation从以下行中看到要抛出的第一个异常是异常<ppltasks.h>

// In order to prevent Windows Runtime STA threads from blocking the UI, calling
// task.wait() task.get() is illegal if task has not been completed.
if (!_IsCompleted() && !_IsCanceled())
{
  throw invalid_operation("Illegal to wait on a task in a Windows Runtime STA");
}

您报告的“无效参数”是此异常到达 ABI 边界时导致的致命错误:通知调试器应用程序即将终止,因为此异常未处理。

您需要重组代码以使用continuations, using task::then,如文章Asynchronous Programming in C++ Using PPL中所述

于 2012-11-28T22:55:03.493 回答
1

只是为了确保您了解异步模式,您的代码中发生的事情是您调用 create_task 并在该任务开始后立即尝试使用 .get() 获取结果。如果任务仍在运行或找不到文件,对 .get() 的调用将立即抛出。因此,构建此任务的正确方法是在文件任务上使用 .then,确保在开始下一个任务之前获得此任务的结果。

create_task(file->OpenAsync(FileAccessMode::Read)).then([](IRandomAccessStream^ reader)
{
    //do stuff with the reader
});

此时阅读器可用,因此您可以做任何您想做的事情,甚至开始一项新任务。

此外,对 OpenAsync 的调用可能会失败,因为文件为空,我会在上一个任务(获取文件的任务)中添加一个 try catch 块,以确保这不是问题。

于 2013-05-18T20:27:19.220 回答