5

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

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。

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

提前致谢。

4

3 回答 3

5

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

进一步调查,问题出在低级本机 API:ISequentialStream::Write(IStream 继承)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 中调用)-> 在尝试从此变量读取/写入之前,它不再检查 pcbWritten 是否为 NULL - 相反,它总是尝试写入字节数写入此变量 - 如果在此变量设置为 NULL 的情况下调用 API,则它是 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 可以在 while 之外完成而不会出现问题。如果 MS 确实修复了该错误,也应该是安全的。

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

奈杰尔

于 2017-06-13T16:46:37.857 回答
1

经过几天的努力,在另一个线程上调用它解决了这个问题:

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

t.Wait();
于 2017-05-30T19:42:03.143 回答
0

我也有同样的问题,它看起来是 Windows 10 的 Creators Edition build 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

于 2017-06-13T13:19:52.550 回答