2013-08-29 35 views
7

Lưu ý: Giải pháp làm việc cuối cùng là sau khi chỉnh sửa!Chuyển cấu trúc từ C++ không được quản lý đến C#

Tôi hy vọng ai đó có thể giúp tôi giải quyết vấn đề tôi đã cố gắng giải quyết trong vài ngày qua.

Tôi đang cố chuyển cấu trúc từ một tệp DLL C++ không được quản lý sang tập lệnh C#. Đây là những gì tôi có cho đến nay:

C++

EXPORT_API uchar *detectMarkers(...) { 
    struct markerStruct { 
      int id; 
    } MarkerInfo; 

    uchar *bytePtr = (uchar*) &MarkerInfo; 

    ... 

    MarkerInfo.id = 3; 
    return bytePtr; 
} 

C#

[DllImport ("UnmanagedDll")] 
    public static extern byte[] detectMarkers(...); 

... 

[StructLayout(LayoutKind.Explicit, Size = 16, Pack = 1)] 
public struct markerStruct 
{ 
    [MarshalAs(UnmanagedType.U4)] 
    [FieldOffset(0)] 
    public int Id; 
} 

... 

markerStruct ByteArrayToNewStuff(byte[] bytes){ 
    GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned); 
    markerStruct stuff = (markerStruct)Marshal.PtrToStructure(
     handle.AddrOfPinnedObject(), typeof(markerStruct)); 
    handle.Free(); 
    return stuff; 
} 

... 

print(ByteArrayToNewStuff (detectMarkers(d, W, H, d.Length)).Id); 

Vấn đề là làm việc này, nhưng giá trị in là hoàn toàn tắt (đôi khi nó in khoảng 400, đôi khi giá trị int tối đa).

Tôi đoán rằng có điều gì đó sai với cách tôi sắp xếp cấu trúc trong C#. Bất kỳ ý tưởng?

Edit:

Đây là giải pháp làm việc sử dụng ref:

C++

struct markerStruct { 
    int id; 
}; 

... 

EXPORT_API void detectMarkers(... , markerStruct *MarkerInfo) { 
    MarkerInfo->id = 3; 
    return; 
} 

C#

[DllImport ("ArucoUnity")] 
    public static extern void detectMarkers(... , 
     [MarshalAs(UnmanagedType.Struct)] ref MarkerStruct markerStruct); 

... 

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] 
public struct MarkerStruct 
{ 
    public int Id; 
} 

... 

detectMarkers (d, W, H, d.Length, ref markerInfo);  
print(markerInfo.Id); 

Trả lời

5

Bạn đang trả về một con trỏ tới biến cục bộ đã bị hủy trước khi .NET có thể đọc nó. Đó là một ý tưởng tồi trong C++ thuần túy và một ý tưởng tồi với p/invoke.

Thay vào đó, có C# thông qua một con trỏ đến một cấu trúc (chỉ sử dụng từ khóa ref) và C++ chỉ điền vào

+0

Tôi đã cố gắng sử dụng ref, nhưng tôi vẫn chưa quản lý để có được giá trị đúng ra ... Bạn có thể có thể có một cái nhìn tại câu hỏi đã chỉnh sửa của tôi? – mkolarek

+0

@kolarek: Giống như tôi đã nói trong câu trả lời của tôi, khi bạn sử dụng từ khóa 'ref' hoặc' out' C# sẽ thực sự vượt qua một con trỏ. Vì vậy, sử dụng 'void detectMarkers (/*...*/ markerStruct * MarkerInfo)' trên phía C++, và sau đó là 'MarkerInfo-> id = 3;'. Ngoài ra, loại bỏ thuộc tính 'In' trong ký tự p/invoke, điều đó có nghĩa là không lấy lại dữ liệu từ C++, mà rõ ràng là ngược lại với những gì bạn muốn. –

+0

Cảm ơn bạn rất nhiều, tôi đã có nó và chạy! – mkolarek

3

Các MarkerInfo biến là loc al và đi ra khỏi phạm vi khi hàm trả về. Không trả lại con trỏ đến biến cục bộ, các đối tượng mà chúng trỏ đến sẽ không tồn tại nữa.

+0

Cảm ơn! Bạn có gợi ý về những gì tôi nên làm thay vào đó không? – mkolarek

0

. Đi để cung cấp cho một whirl này ... thx cho bài ...

// new struct and generic return for items to 
struct _itemStruct 
{ 
    unsigned int id; // 0 by default, so all lists should start at 1, 0 means unassigned 
    wchar_t *Name; 
}; 

// for DLL lib precede void with the following... 
// EXPORT_API 
void getItems(std::vector<_itemStruct *> *items) 
{ 
    // set item list values here 


    //unsigned char *bytePtr = (unsigned char*)&items; // manual pointer return 

    return; 
}; 

/* // In theory c# code will be... 
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] 
public struct _itemStruct 
{ 
    public unsigned int Id; 
    public string Name; 
} 

[DllImport ("ListOfItems")] // for ListOfItems.DLL 
public static extern void getItems(
[MarshalAs(UnmanagedType.Struct)] ref List<_itemStruct> items); 
// */ 
Các vấn đề liên quan