2013-08-29 17 views
7

Hinweis: Die endgültige Arbeitslösung ist nach der Bearbeitung!Passing Struktur von nicht verwalteten C++ C#

Ich hoffe, dass mir jemand mit einem Problem helfen kann ich für die letzten paar Tage zu lösen versucht habe.

Ich versuche, eine Struktur aus einem nicht verwalteten C++ DLL in eine C# Skript zu übergeben. Das ist, was ich habe, so weit:

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); 

Das Problem ist, dass dies funktioniert, aber der Wert gedruckt ist vollständig ausgeschaltet (manchmal druckt es rund 400, manchmal max int Wert).

Ich vermute, dass es etwas falsch mit, wie ich die Struktur in C# gemarshallt. Irgendwelche Ideen?

Edit:

Dies ist die Arbeitslösung mit 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); 

Antwort

5

Sie einen Zeiger auf eine lokale Variable zurückkehrt, die bereits zerstört wurde, bevor .NET es lesen kann. Das ist eine schlechte Idee in reinem C++ und eine schlechte Idee mit p/invoke. Statt

, haben C# einen Zeiger auf eine Struktur übergeben (nur verwenden, um die ref Schlüsselwort) und der C++ Code nur in füllen.

+0

Ich habe versucht, Ref zu verwenden, aber ich habe es immer noch nicht geschafft, den richtigen Wert herauszubekommen ... Könnten Sie sich vielleicht meine bearbeitete Frage ansehen? – mkolarek

+0

@kolarek: Wie ich in meiner Antwort sagte, wenn Sie das 'ref' oder' out' Schlüsselwort verwenden, wird C# tatsächlich einen Zeiger übergeben. Verwenden Sie 'void detectMarkers (/*...*/markerStruct * MarkerInfo)' auf der C++ - Seite und dann 'MarkerInfo-> id = 3;'. Entfernen Sie auch das 'In'-Attribut in der p/invoke-Signatur, das bedeutet, dass Sie keine Daten aus C++ zurückholen, was offensichtlich das Gegenteil von dem ist, was Sie wollen. –

+0

Vielen Dank, ich habe es am Laufen! – mkolarek

3

Die MarkerInfo Variable ist loc al und geht aus dem Geltungsbereich, wenn die Funktion zurückgibt. Geben Sie keine Zeiger auf lokale Variablen zurück, die Objekte, auf die sie zeigen, werden nicht mehr existieren.

+0

Dank! Hast du einen Vorschlag, was ich stattdessen tun soll? – mkolarek

0

gehen diese einen Wirbel ... thx für die Post geben ...

// 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); 
// */ 
Verwandte Themen