首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >获取指向已声明变量的正确IntPtr的C#

获取指向已声明变量的正确IntPtr的C#
EN

Stack Overflow用户
提问于 2012-12-13 21:12:36
回答 4查看 6.5K关注 0票数 0

我正在尝试直接在文件中写入/读取多字节数组,并建议使用PInvoke WriteFile/ReadFile。

基本上我的阅读代码现在看起来是这样的:

代码语言:javascript
复制
[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。但是,以下代码不会:

代码语言:javascript
复制
[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转换为整数”的问题的答案,它都是这样的:

代码语言:javascript
复制
int x = 0;
IntPtr ptrtox = new IntPtr(x)

那么,我做错了什么呢?为什么会发生访问冲突?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2012-12-13 21:38:28

你得到访问冲突的原因是因为新的IntPtr( x )创建了一个指针,它的地址是X的内容。所以当x=0时,你创建了一个空指针。

IntPtr构造函数未获取其参数的地址。它不等同于C/C++中的&运算符。

您希望对读取的字节使用ref参数;这是正确的方法。此外,您总是希望使用GCHandle来获取托管对象的地址,因此在您的mb数组上使用它,而不是固定的。只是不要长时间保留句柄,别忘了释放它。

-reilly。

票数 2
EN

Stack Overflow用户

发布于 2012-12-13 21:27:34

我认为访问冲突是因为bytesread是托管的,因此GC可能会移动它,使您传递的指针无效。

下面的方法可以工作吗?

代码语言:javascript
复制
int bytesread = 0;
var pin = GCHandle.Alloc(bytesread, GCHandleType.Pinned)
ReadFile(fs.SafeFileHandle.DangerousGetHandle(), (IntPtr)fb, Convert.ToUInt32(mb.Length), pin.AddrOfPinnedObject(), null);

编辑我忘记了下一行:

代码语言:javascript
复制
pin.Free();

双重编辑哦,天哪!我完全弄错了。我所说的更多地适用于在安全代码中处理堆中的托管数据。

@plinth是完全正确的,代码如下:

代码语言:javascript
复制
int x = 0;
IntPtr ptrtox = new IntPtr(x)

创建一个值为x的指针,而不是指向x。在你的原始代码中,只需传递:

代码语言:javascript
复制
new IntPtr(&bytesread)

代码语言:javascript
复制
(IntPtr)(&bytesread)
票数 0
EN

Stack Overflow用户

发布于 2012-12-13 21:41:33

这很简单。看看你正在做的这一小段:

代码语言:javascript
复制
new IntPtr(bytesread)

这并不是你所想的那样。你认为它会生成一个新的指针,指向你的变量bytesread。它不是这样做的,它会生成一个指针,指向一个字节读的地址,这个地址的为0。非托管代码读取,然后尝试将一个数字写入空指针所指向的内存中,但失败了。

另一个版本之所以有效,是因为参数被声明为ref int,这将使编组程序传递一个指向bytesread的实际指针,而不是值。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/13860591

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档