安装 Windows 10 创作者更新 1703 后将数据复制到便携式设备时出现 System.AccessViolationException [英] System.AccessViolationException when copying data to portable device after installing windows 10 creators update 1703

查看:19
本文介绍了安装 Windows 10 创作者更新 1703 后将数据复制到便携式设备时出现 System.AccessViolationException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用此代码段将内容传输到便携式设备

I am attempting to transfer content to portable device using this code snippet

IPortableDeviceValues values =
            GetRequiredPropertiesForContentType(fileName, parentObjectId);

        IStream tempStream;
        uint optimalTransferSizeBytes = 0;

        content.CreateObjectWithPropertiesAndData(
            values,
            out tempStream,
            ref optimalTransferSizeBytes,
            null);

        System.Runtime.InteropServices.ComTypes.IStream targetStream =
            (System.Runtime.InteropServices.ComTypes.IStream)tempStream;

        try
        {
            using (var sourceStream =
                   new FileStream(fileName, FileMode.Open, FileAccess.Read))
            {
                var buffer = new byte[optimalTransferSizeBytes];
                int bytesRead;
                do
                {
                    bytesRead = sourceStream.Read(
                        buffer, 0, (int)optimalTransferSizeBytes);
                    IntPtr pcbWritten = IntPtr.Zero;
                    if (bytesRead < (int)optimalTransferSizeBytes)
                    {
                        targetStream.Write(buffer, bytesRead, pcbWritten);
                    }
                    else
                    {
                        targetStream.Write(buffer, (int)optimalTransferSizeBytes, pcbWritten);
                    }

                } while (bytesRead > 0);
            }
            targetStream.Commit(0);
        }
        finally
        {
            System.Runtime.InteropServices.Marshal.ReleaseComObject(tempStream);
        }

尝试执行 targetStream.Write 时发生 System.AccessViolationException.

When trying to execute targetStream.Write System.AccessViolationException occuried.

这仅适用于 Windows 10,创作者更新 1703.

This is reproducible only for windows 10, creators update 1703.

你能告诉我我做错了什么吗?

Could you please tell me what I am doing wrong?

提前致谢.

推荐答案

--如果您只想修复,请跳至粗体文本!

--Skip to the text in bold if you just want a fix!

进一步调查,问题出在低级原生 API:ISequentialStream::Write(IStream 继承的)MSDN 页面是:https://msdn.microsoft.com/en-us/library/windows/desktop/aa380014%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396

Investigating further, the issue is in the low level native API: ISequentialStream::Write (which IStream Inherits) The MSDN page for this is: https://msdn.microsoft.com/en-us/library/windows/desktop/aa380014%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396

注意参数的文本:pcbWritten [out] 读取'指向 ULONG 变量的指针,此方法将实际写入流对象的字节数写入其中.调用者可以将此指针设置为 NULL,在这种情况下,此方法不提供实际写入的字节数.'

Note the text for the argument: pcbWritten [out] reads 'A pointer to a ULONG variable where this method writes the actual number of bytes written to the stream object. The caller can set this pointer to NULL, in which case this method does not provide the actual number of bytes written.'

MS 在此 API 中引入了一个错误(在 PortableDeviceApi.dll 中调用)--> 在尝试从此变量读取/写入之前不再检查 pcbWritten 是否为 NULL - 相反,它始终尝试写入写入此变量的字节数 - 如果在此变量设置为 NULL 的情况下调用 API,则它为 BARFS.我已经通过改变 API 的调用方式证明了纯原生代码就是这种情况:

MS introduced a bug into this API (as called in PortableDeviceApi.dll) --> it is no longer checking whether or not pcbWritten is NULL before attempting to read/write from this variable - rather, it ALWAYS attempts to write the No Of Bytes written into this variable - if the API is called with this variable set to NULL then it BARFS. I have proven this is the case in pure native code by changing the way the API is called:

作品:

DWORD bytesWritten
IStream->Write(objectData, bytesRead, &bytesWritten)))

失败:

IStream->Write(objectData, bytesRead, NULL))) <-- Note the NULL

在 .Net 中,IStream.Write 是这样编组的:

Up in .Net, IStream.Write is marshalled thus:

void Write(byte[] pv,int cb,IntPtr pcbWritten)

和演示代码(我们可能都从那里得到了我们的实现!)是:

and the demo code (from where we all likely got our implementations!) was:

 IntPtr pcbWritten = IntPtr.Zero  //<--Eg NULL
 IStream.Write(buffer, bytesRead, pcbWritten);

建议的解决方案 - 将代码更改为:

 IntPtr pcbWritten = Marshal.AllocHGlobal(4);
 IStream.Write(buffer, bytesRead, pcbWritten);
 Marshal.FreeHGlobal(pcbWritten);

这可以解决这个问题 - 希望微软能够修复它以避免我们所有人都不得不重新分发我们的产品!整个代码包含在 PortableDeviceApi.dll 中(也包括流的东西),这可以解释为什么整个世界都没有抱怨这个问题,以及为什么在测试过程中没有发现它.注意:对于 while 循环中的多块副本,我怀疑 alloc/free 可以在 while 之外完成而没有问题.如果 MS 确实修复了错误,也应该是安全的.

This works around the issue - Hopefully MS will fix it to avoid us all having to re-distribute our products! The entire code is contained in PortableDeviceApi.dll (also including the stream stuff), which would explain why the entire world is not moaning about this issue and why it was not found during test. NB: For multi block copies in while loop, I suspect the alloc/free can be done outside the while without issue. Should also be safe if MS does fix the bug.

致谢:Alistair Brown(在我们的办公室)寻找并分配不需要分配的内容,从而找到问题.

Credit: Alistair Brown (in our office) for fishing about, and allocating what should not need to be allocated and thus finding the issue.

奈杰尔

这篇关于安装 Windows 10 创作者更新 1703 后将数据复制到便携式设备时出现 System.AccessViolationException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆