安装Windows 10创建者更新1703后,将数据复制到便携式设备时出现System.AccessViolationException

时间:2017-05-15 13:17:43

标签: c# exception windows-10 access-violation wpd

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

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。

这仅适用于Windows 10,创建者更新1703。

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

提前致谢。

3 个答案:

答案 0 :(得分:5)

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

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

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

MS在此API中引入了一个错误(在PortableDeviceApi.dll中调用) - &gt;在尝试从这个变量读取/写入之前,它不再检查pcbWritten是否为NULL - 相反,它总是尝试写入写入此变量的No Of Bytes - 如果调用API并将此变量设置为NULL然后它BARFS。我已经通过改变调用API的方式证明了纯本机代码的情况:

使用:

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

失败:

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

在.Net中,IStream.Write因此被编组:

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

和演示代码(我们都可能从中获得我们的实现!)是:

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

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

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

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

信用:Alistair Brown(在我们的办公室)钓鱼,并分配不需要分配的东西,从而找到问题。

答案 1 :(得分:1)

在敲了几天之后,在另一个线程上调用它解决了这个问题:

var t = Task.Run(() => { device.TransferContentToDevice(fileName, parent.Id); });

t.Wait();

答案 2 :(得分:0)

我也有同样的问题,它看起来是Windows 10的Creators Edition版本1703中的错误/功能。

此问题已通过Microsoft Connect上的“Visual Studio和.Net Framework”流报告:https://connect.microsoft.com/VisualStudio/Feedback/Details/3135829 (Windows 10没有特定区域)

我会鼓励任何有这个问题的人前往上面,并表明你也可以重现它。

我有一个简单的转发器,可以在这里下载:http://scratch.veletron.com/WPD_FAIL_REPEATER.ZIP