这是在 GitHub 上有小伙伴报的问题,在 WPF 中,不支持在调用 BitmapDecoder.Create 方法时,传入的 FileStream 是配置了 FileOptions.Asynchronous 选项的文件流。本质原因是 WIC 层不支持,和 WPF 没有关系。此问题我已修复,在 dotnet 7 或更高版本将不存在此问题
更新: 此问题已被我修复,合入到 dotnet 7 版本主干。在大于 .NET 7 版本下,对于在调用 BitmapDecoder.Create 方法时,传入的 FileStream 是配置了 FileOptions.Asynchronous 选项的文件流,将读取文件内容到内存,从而解决此问题。副作用是在传入的 FileStream 是配置了 FileOptions.Asynchronous 选项的文件流,将占用更多的内存
GitHub 链接: BitmapDecoder.Create does not handle FileStream with FileOptions.Asynchronous · Issue #4355 · dotnet/wpf
现象是传入 BitmapDecoder.Create 的 FileStream 配置了 FileOptions.Asynchronous 选项,代码如下
运行以上代码将会抛出 ArgumentException
而创建解码器失败
本质原因是 WIC 层不支持 FileStream 配置了 FileOptions.Asynchronous 选项。在 BitmapDecoder.Create 的底层,调用了 IWICImagingFactory_CreateDecoderFromFileHandle_Proxy function - Win32 apps 方法创建解码器,代码如下
也就是说最底层调用就是通过 CreateDecoderFromFileHandle 方法创建解码器,而 CreateDecoderFromFileHandle 的定义如下
从以上代码可以看到是在 WindowsCodecs.dll
也就是 WIC 层的 IWICImagingFactory_CreateDecoderFromFileHandle_Proxy
抛出失败的
在 FileStream 创建中,如果传入了 FileOptions.Asynchronous 参数,将会在 Windows 下,调用的是 CreateFileW function (fileapi.h) - Win32 apps 方法,在这个方法里面将会设置 FILE_FLAG_OVERLAPPED
参数。不过我没有从网上找到在设置了 FILE_FLAG_OVERLAPPED
参数的文件句柄将在 IWICImagingFactory_CreateDecoderFromFileHandle_Proxy
或 IWICImagingFactory::CreateDecoderFromFileHandle 方法不支持的知识
我写了一个简单的 demo 程序,用来测试是否 FileOptions.Asynchronous 参数的文件句柄将会在 WIC 层不支持
通过以上代码可以看到,如果 FileStream 的创建参数里面加上了 FileOptions.Asynchronous 那么将会在 CreateDecoderFromFileHandle 抛出错误
因此在 WPF 中,调用 BitmapDecoder.Create 方法,传入的带 FileOptions.Asynchronous 的 FileStream 抛出错误,不是 WPF 层的锅,而是 WIC 层不支持。在 GitHub 上报告的作者 Nikita Kazmin 给了一个我同意的建议是 WPF 在 BitmapDecoder.Create 方法里面应该判断一下,如果传入的 FileStream 是异步的,那么在 WPF 层抛出错误,这样方便开发者了解不能这样使用
我也有另一个想法,如果是 FileStream 是异步的,不如完全读取到内存里面,这样开发者也就可以不关注这部分的逻辑。我当前将此逻辑放入到 WPF 仓库中,当前已被合入,详细请看 https://github.com/dotnet/wpf/pull/4966
本文所有代码放在 github 和 gitee 欢迎小伙伴访问
当前的 WPF 在 https://github.com/dotnet/wpf 完全开源,使用友好的 MIT 协议,意味着允许任何人任何组织和企业任意处置,包括使用,复制,修改,合并,发表,分发,再授权,或者销售。在仓库里面包含了完全的构建逻辑,只需要本地的网络足够好(因为需要下载一堆构建工具),即可进行本地构建
原文链接: http://blog.lindexi.com/post/WPF-%E5%B7%B2%E7%9F%A5%E9%97%AE%E9%A2%98-BitmapDecoder.Create-%E4%B8%8D%E6%94%AF%E6%8C%81%E4%BC%A0%E5%85%A5-Asynchronous-%E7%9A%84%E6%96%87%E4%BB%B6%E6%B5%81
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。
欢迎转载、使用、重新发布,但务必保留文章署名 林德熙 (包含链接: https://blog.lindexi.com ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我 联系。