2012-02-05 9 views
8

Nếu tôi sắp xếp cấu trúc này với StructureToPtr và sau đó unmarshal nó một lần nữa với PtrToStructure, nút đầu tiên của tôi có y = {1,2} trong khi nút thứ hai của tôi có y = {1,0}.Marshal.StructureToPtr không thành công với mảng kích thước bool và cố định?

Tôi không biết tại sao, có lẽ cấu trúc của tôi là xấu bằng cách nào đó? Loại bỏ các bool từ cấu trúc làm cho nó hoạt động.

using System; 
using System.Runtime.InteropServices; 

namespace csharp_test 
{ 
    unsafe class Program 
    { 
     [StructLayout(LayoutKind.Sequential)] 
     public struct Node 
     { 
      public bool boolVar; 
      public fixed int y[2]; 
     } 

     unsafe static void Main(string[] args) 
     { 
      Node node = new Node(); 

      node.y[0] = 1; 
      node.y[1] = 2; 
      node.boolVar = true; 

      int size = sizeof(Node); 
      IntPtr ptr = Marshal.AllocHGlobal(size); 
      Marshal.StructureToPtr(node, ptr, false); 
      Node node2 = (Node)Marshal.PtrToStructure(ptr, typeof(Node)); 
      Marshal.FreeHGlobal(ptr); 
     } 
    } 
} 
+0

Có lẽ nó phải làm điều gì đó với 'bool' được so sánh dưới dạng 4 byte (' BOOL') chứ không phải 1 byte? Nhưng tôi không thể nghĩ ra lý do chính xác ... – Mehrdad

+0

Hơn nữa, nó bỏ qua bất kỳ phần tử mảng nào sau phần tử đầu tiên (viết chúng dưới dạng số không vào bộ nhớ không được quản lý). Nó cũng không quan trọng nếu 'bool' đến trước mảng hoặc sau trong cấu trúc. – GSerg

Trả lời

9

Điều này thực sự sai. Đó là cuộc gọi StructureToPtr() không sao chép đủ byte. Bạn có thể thấy điều này bằng cách sử dụng Debug + Windows + Memory + Memory1 và đặt "ptr" vào hộp địa chỉ. Sử dụng toán tử sizeof isn't correct nhưng không thực sự là nguồn gốc của vấn đề. Chỉ phần tử đầu tiên của mảng được sao chép, bất kể độ dài mảng. Không chắc chắn nguyên nhân gây ra sự cố này, tôi không bao giờ sử dụng cố định bằng pinvoke. Tôi chỉ có thể giới thiệu cách pinvoke truyền thống hoạt động tốt:

unsafe class Program { 
    [StructLayout(LayoutKind.Sequential)] 
    public struct Node { 
     public bool boolVar; 
     [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] 
     public int[] y; 
    } 

    unsafe static void Main(string[] args) { 
     Node node = new Node(); 
     node.y = new int[2]; 

     node.y[0] = 1; 
     node.y[1] = 2; 
     node.boolVar = true; 

     int size = Marshal.SizeOf(node); 
     IntPtr ptr = Marshal.AllocHGlobal(size); 
     Marshal.StructureToPtr(node, ptr, false); 
     Node node2 = (Node)Marshal.PtrToStructure(ptr, typeof(Node)); 
     Marshal.FreeHGlobal(ptr); 
    } 

Bạn có thể đăng bài để kết nối.microsoft.com nếu bạn muốn đưa sự chú ý của các chủ độ tương tác CLR.

+0

cảm ơn, nhận xét trong liên kết bạn đăng thực sự giải thích vấn đề, mặc dù thực sự câu trả lời thực sự là tôi không nên sử dụng bộ đệm có kích thước cố định và chỉ nên sử dụng thuộc tính MarshalAs, như bạn minh họa. Tôi đã biết rằng bạn không nên sử dụng sizeof(), tôi không chắc liệu trong thế giới thực có tạo ra sự khác biệt nào không. Nhưng dù sao, tôi đã thay đổi mã của tôi để sử dụng Marshal.SizeOf bất kể. – junichiro

+0

@Có một nhận xét trong liên kết của bạn bị thiếu ☹ –

+0

Chỉ cần thêm vào đây: PtrToStructure() cũng sẽ chỉ sao chép byte đầu tiên của mảng cố định, ngay cả khi vị trí bộ nhớ chứa nhiều thông tin hơn. Ngay cả khi cấu trúc sử dụng LayoutKind.Explicit nó vẫn thất bại: ( –

0

Bạn cũng nên đóng gói cấu trúc hoặc lớp trước khi sử dụng. Điều đó phù hợp với tôi, gần như tốt như memcpy

[StructLayout(LayoutKind.Sequential, Pack = 1)] 
public class SomeClass 
{ 
}