将IntPtr转换为byte数组时抛出AccessViolationException的原因
AccessViolationException触发原因
你对Marshal.Copy的用法存在逻辑误解:Marshal.Copy(IntPtr source, byte[] destination, int startIndex, int length)重载的执行逻辑是从source指向的非托管内存首地址开始,读取length个字节的连续内存数据,写入托管字节数组。这个方法要求传入的source必须是指向当前进程可访问、已分配的非托管内存块的起始地址,方法运行时会直接解引用这个指针去读对应内存的内容。
你的代码中传入的hWnd是窗口句柄,本质是一个作为系统对象标识的整数值,不是可读取的非托管内存块首地址。当Marshal.Copy尝试把hWnd存储的数值当作内存地址去读取数据时,要么该地址未被进程分配,要么属于受系统保护的不可读内存段,自然会触发访问违例异常。
正确实现方案
你的需求是把IntPtr变量本身存储的整数值转为字节数组,不需要解引用指针去读它指向的内存,可直接通过以下方式实现:
IntPtr hWnd = this.Handle; int ptrSize = IntPtr.Size; byte[] managedArray = new byte[ptrSize]; // 实现1:通过BitConverter直接转换整数值 if (ptrSize == 4) { BitConverter.GetBytes(hWnd.ToInt32()).CopyTo(managedArray, 0); } else { BitConverter.GetBytes(hWnd.ToInt64()).CopyTo(managedArray, 0); } // 实现2:通过Marshal直接拷贝结构体值(不需要解引用IntPtr指向的内存) GCHandle handle = GCHandle.Alloc(managedArray, GCHandleType.Pinned); try { Marshal.StructureToPtr(hWnd, handle.AddrOfPinnedObject(), false); } finally { handle.Free(); }
核心区分:
- 要拷贝指针指向的内存内容时,才使用
Marshal.Copy,且必须保证指针指向合法可访问的、长度满足要求的非托管内存- 要获取指针本身存储的地址值的字节表示时,不要解引用指针,直接对IntPtr存储的数值做转换即可
内容的提问来源于stack exchange,提问作者c00000fd
相关产品推荐
相关产品推荐

