2010-02-25 41 views
7

Tôi đã một dll không quản lý mà xuất khẩu chức năng folowing:con trỏ Trở về từ không được quản lý để quản lý mã

SomeData* test(); 

Giả sử SomeData như:

typedef struct _Data Data; 
struct _Data{ 
    int a; 
    int b; 
} 

Bây giờ tôi muốn gọi chức năng này từ C# mã. Tôi bắt đầu để xác định C# Cơ cấu cần thiết để marshaling tùy chỉnh như thế này:

[StructLayout(LayoutKind.Sequential)] 
public class SomeData 
{ 
    public Int32 a; 
    public Int32 b; 
} 

Và bây giờ, tôi tuyên bố các chức năng quản lý:

[DllImport("DynamicLibrary.dll", CharSet=CharSet.Auto)] 
[return: MarshalAs(UnmanagedType.LPStruct)] 
public static extern SomeData test(); 

Và trong hàm chính tôi có:

IntPtr ptr = test(); 

Thực hiện việc này, tôi nhận được giá trị trả về của MarchalDirectiveException: "Không thể so sánh": Kết hợp kiểu không được quản lý/không được quản lý (Int/UInt phải được ghép nối với SysInt hoặc SysUInt). "

Tôi đã không cấp phát bộ nhớ cho SomeData trong C# vì tôi mong đợi bộ nhớ này được cấp phát trong hàm C và chúng tôi sẽ sử dụng Marshal.Copy để chuyển nó vào bộ nhớ được quản lý.

Bất kỳ ý tưởng nào? Cảm ơn

------------------------ CHỈNH SỬA SAU JaredPar TRẢ LỜI ----------------- ---

Thực tế, tôi đã phạm sai lầm khi đối chiếu mã cho câu hỏi của mình. Chữ ký thực quản lý tôi đã được sử dụng là:

[DllImport ("DynamicLibrary.dll", charset = CharSet.Auto)]
[trở lại: MarshalAs (UnmanagedType.LPStruct)]
công extern tĩnh kiểm tra IntPtr();

Câu trả lời của JaredPar vẫn có liên quan. Để có được hành vi đúng, tôi có 2 lựa chọn:

1) Sử dụng 'kiểm tra IntPtr tĩnh công cộng bên ngoài();' (không có thuộc tính MarshalAs) chữ ký và sau đó truy cập con trỏ trả về như JaredPar được đề xuất.

2) Sử dụng 'thử nghiệm cục bộ công khai bên ngoài SomeData();' (với thuộc tính MarshalAs) và sau đó chỉ cần sử dụng SomeData sd = test();

Trả lời

10

Khi khai báo hàm được quản lý, bạn cần phải đối sánh các loại con trỏ với giá trị tham chiếu hoặc IntPtr giá trị. Trong trường hợp này, công cụ sửa đổi LPStruct sẽ không giúp ích gì. Giải pháp đơn giản nhất là chuyển đổi giá trị trả về của thử nghiệm thành IntPtr thay vì SomeData vì phương thức gốc trả về giá trị con trỏ. Sau đó, bạn có thể viết trình bao bọc sau

[DllImport("DynamicLibrary.dll", CharSet=CharSet.Auto)] 
public static extern IntPtr test(); 

public static SomeData testWrapper() { 
    var ptr = test(); 
    try { 
    return (SomeData)Marshal.PtrToStructure(ptr, typeof(SomeData)); 
    } finally { 
    // Free the pointer here if it's allocated memory 
    } 
} 
+0

Như bạn có thể thấy trong chỉnh sửa của mình, tôi đã nhầm lẫn khi tôi viết câu hỏi. Câu trả lời của bạn hữu ích và hiệu quả nhưng tôi thích sử dụng lựa chọn 2) của phần chỉnh sửa của tôi. Cảm ơn –

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