Tat*_*ana 5 c# exception wpd access-violation windows-10
我正在尝试使用此代码段将内容传输到便携式设备
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);
}
Run Code Online (Sandbox Code Playgroud)
尝试执行targetStream.Write System.AccessViolationException时发生.
这仅适用于Windows 10,创建者更新1703.
你能告诉我我做错了什么吗?
提前致谢.
小智 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中调用) - >在尝试从此变量读取/写入之前,它不再检查pcbWritten是否为NULL - 相反,它总是尝试写入No Of Bytes写入此变量 - 如果使用此变量设置为NULL调用API,则将其设置为BARFS.我已经通过改变调用API的方式证明了纯本机代码的情况:
作品:
DWORD bytesWritten
IStream->Write(objectData, bytesRead, &bytesWritten)))
Run Code Online (Sandbox Code Playgroud)
失败:
IStream->Write(objectData, bytesRead, NULL))) <-- Note the NULL
Run Code Online (Sandbox Code Playgroud)
在.Net中,IStream.Write因此被编组:
void Write(byte[] pv,int cb,IntPtr pcbWritten)
Run Code Online (Sandbox Code Playgroud)
和演示代码(从我们所有人可能获得我们的实现!)是:
IntPtr pcbWritten = IntPtr.Zero //<--Eg NULL
IStream.Write(buffer, bytesRead, pcbWritten);
Run Code Online (Sandbox Code Playgroud)
建议的解决方案 - 将代码更改为:
IntPtr pcbWritten = Marshal.AllocHGlobal(4);
IStream.Write(buffer, bytesRead, pcbWritten);
Marshal.FreeHGlobal(pcbWritten);
Run Code Online (Sandbox Code Playgroud)
这解决了这个问题 - 希望MS能够修复它以避免我们所有人不得不重新分发我们的产品!整个代码包含在PortableDeviceApi.dll(也包括流内容)中,这可以解释为什么整个世界都没有抱怨这个问题以及为什么在测试期间没有找到它.注意:对于while循环中的多块副本,我怀疑alloc/free可以在没有问题的情况下在外面完成.如果MS确实修复了bug,也应该是安全的.
信用:Alistair Brown(在我们的办公室)钓鱼,并分配不需要分配的东西,从而找到问题.
奈杰尔
小智 1
在我为此苦恼了几天之后,在另一个线程上调用它解决了问题:
var t = Task.Run(() => { device.TransferContentToDevice(fileName, parent.Id); });
t.Wait();
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
630 次 |
| 最近记录: |