我正在尝试直接在文件中写入/读取多字节数组,并建议使用PInvoke WriteFile/ReadFile。
基本上我的阅读代码现在看起来是这样的:
[DllImport("kernel32.dll", SetLastError = true)]
static extern unsafe int ReadFile(IntPtr handle, IntPtr bytes, uint numBytesToRead,
IntPtr numBytesRead, System.Threading.NativeOverlapped* overlapped);
..<cut>..
byte[,,] mb = new byte[1024,1024,1024];
fixed(byte * fb = mb)
{
FileStream fs = new FileStream(@"E:\SHARED\TEMP", FileMode.Open);
int bytesread = 0;
ReadFile(fs.SafeFileHandle.DangerousGetHandle(), (IntPtr)fb, Convert.ToUInt32(mb.Length), new IntPtr(bytesread), null);
fs.Close();
}这段代码抛出一个AccessViolationException。但是,以下代码不会:
[DllImport("kernel32.dll", SetLastError = true)]
static extern unsafe int ReadFile(IntPtr handle, IntPtr bytes, uint numBytesToRead,
ref int numBytesRead, System.Threading.NativeOverlapped* overlapped);
..<cut>..
byte[,,] mb = new byte[1024,1024,1024];
fixed(byte * fb = mb)
{
FileStream fs = new FileStream(@"E:\SHARED\TEMP", FileMode.Open);
int bytesread = 0;
ReadFile(fs.SafeFileHandle.DangerousGetHandle(), (IntPtr)fb, Convert.ToUInt32(mb.Length), ref bytesread, null);
fs.Close();
}不同之处在于我声明numBytesRead为ref int而不是IntPtr。
然而,无论我在哪里找到“如何将IntPtr转换为整数”的问题的答案,它都是这样的:
int x = 0;
IntPtr ptrtox = new IntPtr(x)那么,我做错了什么呢?为什么会发生访问冲突?
发布于 2012-12-13 21:38:28
你得到访问冲突的原因是因为新的IntPtr( x )创建了一个指针,它的地址是X的内容。所以当x=0时,你创建了一个空指针。
IntPtr构造函数未获取其参数的地址。它不等同于C/C++中的&运算符。
您希望对读取的字节使用ref参数;这是正确的方法。此外,您总是希望使用GCHandle来获取托管对象的地址,因此在您的mb数组上使用它,而不是固定的。只是不要长时间保留句柄,别忘了释放它。
-reilly。
发布于 2012-12-13 21:27:34
我认为访问冲突是因为bytesread是托管的,因此GC可能会移动它,使您传递的指针无效。
下面的方法可以工作吗?
int bytesread = 0;
var pin = GCHandle.Alloc(bytesread, GCHandleType.Pinned)
ReadFile(fs.SafeFileHandle.DangerousGetHandle(), (IntPtr)fb, Convert.ToUInt32(mb.Length), pin.AddrOfPinnedObject(), null);编辑我忘记了下一行:
pin.Free();双重编辑哦,天哪!我完全弄错了。我所说的更多地适用于在安全代码中处理堆中的托管数据。
@plinth是完全正确的,代码如下:
int x = 0;
IntPtr ptrtox = new IntPtr(x)创建一个值为x的指针,而不是指向x。在你的原始代码中,只需传递:
new IntPtr(&bytesread)或
(IntPtr)(&bytesread)发布于 2012-12-13 21:41:33
这很简单。看看你正在做的这一小段:
new IntPtr(bytesread)这并不是你所想的那样。你认为它会生成一个新的指针,指向你的变量bytesread。它不是这样做的,它会生成一个指针,指向一个字节读的地址,这个地址的值为0。非托管代码读取,然后尝试将一个数字写入空指针所指向的内存中,但失败了。
另一个版本之所以有效,是因为参数被声明为ref int,这将使编组程序传递一个指向bytesread的实际指针,而不是值。
https://stackoverflow.com/questions/13860591
复制相似问题