2014-12-27 16 views
10

Tôi đã cố gắng tạo một xử lý cho một kiểu cấu trúc vì tôi cần một con trỏ được ghim vào nó, nhưng tôi gặp lỗi "Object chứa non-primitive or non- dữ liệu blittable "Làm cách nào để phân bổ GCHandle cho cấu trúc khi cấu trúc chứa bool

cấu trúc của tôi trông như thế này:

[StructLayout(LayoutKind.Sequential)] 
public struct MyStruct 
{ 
    [MarshalAs(UnmanagedType.U1)] 
    public bool Test; 
} 

Bây giờ, khi tôi gọi,

var mystruct = new MyStruct(); 
var handle = GCHandle.Alloc(mystruct, GCHandleType.Pinned); 

tôi nhận được lỗi" Object chứa dữ liệu phi nguyên thủy hoặc không blittable ". Bây giờ tôi hiểu rằng trường bool là một kiểu không thể blittable. Nhưng tôi đã có ấn tượng rằng bằng cách thêm thuộc tính MarshalAs, tôi có thể nói với marshaller cách chuyển đổi kiểu. (Tôi cũng đã thử UnmanagedType.Bool)

Cấu trúc này phải được xác định trên toàn cầu, bởi vì nó là cần thiết trong suốt lớp học của tôi. Lý do duy nhất tôi cần con trỏ là bởi vì tôi có một API không được quản lý phải vượt qua cấu trúc này như một con trỏ. Sau đó, tôi phải lấy cấu trúc đó trong một cuộc gọi lại và đọc/cập nhật thành viên.

Vì vậy, đây là kịch bản cơ bản.

  1. Cấu trúc được tạo ra trên toàn cầu trong một lớp học quản lý
  2. Con trỏ trỏ tới cấu trúc thu được
  3. Con trỏ trỏ tới cấu trúc được truyền vào API
  4. API gọi một phương thức callback tĩnh nơi tôi sau đó cần phải nhận được cấu trúc của tôi và đọc/cập nhật thành viên.

Tôi cố gắng sử dụng Marshal.StructureToPtr nhưng điều này chỉ tạo bản sao, vì vậy nếu trong lớp được quản lý tôi cập nhật thành viên, khi gọi lại được nâng lên, giá trị cập nhật không có.

Có ai biết cách tôi có thể lấy con trỏ được ghim vào cấu trúc của mình để tôi có thể đọc/sửa đổi các thành viên công khai và yêu cầu họ có sẵn trong cuộc gọi lại không?

Cảm ơn

+2

đây là danh sách các loại blittable http://msdn.microsoft.com/en-us/library/75dwhxf7.aspx – Mayank

Trả lời

13

Bạn có nhiều vấn đề ở đây. Việc sử dụng struct rất khó xử lý. Nó sẽ được đóng hộp trước cuộc gọi GCHandle.Alloc() và rằng đối tượng được đóng hộp được ghim. Bạn không thể thấy bất kỳ cập nhật nào cho thông qua biến số bí ẩn của bạn. Thay vào đó, hãy sử dụng một lớp lớp.

Và tránh bool, đây là loại không thể loại bỏ do triển khai có tính biến đổi cao. Nó là 4 byte trong C, 1 byte trong C++, 2 byte trong COM. Thay vào đó, chỉ cần đặt một mã là byte. Bạn có thể viết một thuộc tính để đưa nó trở lại một bool.

Vì vậy:

[StructLayout(LayoutKind.Sequential)] 
public class MyStruct 
{ 
    private byte _test; 
    public bool Test { 
     get { return _test != 0; } 
     set { _test = value ? 1 : 0; } 
    } 
} 
+0

Tôi thực sự đã thử nó như là một lớp học là tốt, nhưng tôi đã treo lên trên cố gắng để buộc nó để sử dụng một loại bool. Tôi đọc câu trả lời của @hvd, và anh ấy đúng. Có vẻ như MarshalAs không làm gì cả. Tôi đã thử nó như là một int chỉ để xem nếu tôi có thể tạo ra một 'GCHandle', và tôi có thể, nhưng tôi không thích ý tưởng của nó. Tôi đánh dấu câu trả lời này là câu trả lời, bởi vì tôi đã không xem xét việc sử dụng một tài sản để bọc thành viên. Tôi sẽ thử! Cảm ơn! –

+0

ECMA-335 11.7.4 cho biết "Boolean. Giá trị số nguyên 4 byte trong đó bất kỳ giá trị khác không đại diện cho TRUE và 0 đại diện cho FALSE." Điều đó không có vẻ gì khác với tôi. Tôi sẽ cho rằng đó là một sự giám sát hoặc có lẽ đã được quyết định bởi vì ngữ nghĩa khác với các loại số nguyên thường và không phải là một quyết định kỹ thuật. –

7

Bạn nói đúng mà bạn đang nói với marshaller làm thế nào để sắp xếp các loại.

Nhưng điều đó sẽ không làm bạn bất kỳ điều gì tốt khi bạn cố gắng bỏ qua trình gỡ băng.

Bạn cần quyết định xem bạn có muốn sử dụng trình gỡ rối hay không hoặc bạn có muốn mã không được quản lý ghi trực tiếp vào bộ nhớ được quản lý hay không.

Nếu bạn muốn sử dụng marshaller:

Nói chung, một cách tốt để xử lý này là để sử dụng nó trong cả hai hướng. Bạn có thể sử dụng Marshal.StructureToPtr (như bạn đã tìm thấy), gọi hàm bên ngoài, sau đó sử dụng Marshal.PtrToStructure để chuyển đổi lại thành đại diện được quản lý của bạn.

Hoặc bạn có thể sử dụng các phương pháp được thiết lập theo cách tự động hóa diễn ra tự động mà không cần phải chỉ định thủ công. Ví dụ: gọi phương thức gốc tham số ref MyStruct sẽ cho phép điều đó xảy ra.

Nếu bạn không muốn sử dụng trình so khớp:

Không sử dụng bất kỳ loại nào yêu cầu marshalling. Như ý kiến ​​của Hans Passant, sử dụng một loại khác thay vào đó, byte có lẽ sẽ là một lựa chọn tốt.

(Tôi sẽ kiềm chế không bình luận về những ưu điểm và nhược điểm của việc sử dụng cấu trúc ở đây, ngoại trừ các điểm đã được thực hiện về nó là rất đáng đọc và hiểu biết.)

Các vấn đề liên quan