2013-08-29 27 views
7

注:最終的な解決策は編集後です!アンマネージC++からC#へ構造体を渡す

私が最後の数日間解決しようとしてきた問題を誰かが助けてくれることを願っています。

アンマネージC++ DLLの構造体をC#スクリプトに渡そうとしています。時々、

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

問題は、これが動作することですが、印刷された値が完全にオフになっている(時にはそれが400の周りに出力します。これは私がこれまでにしたものですmax int value)を返します。

私はC#で構造体をマーシャリングする方法に何か問題があると推測しています。何か案は?

編集:

これは、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); 

答えて

5

.NETが読み込む前に既に破棄されているローカル変数へのポインタを返しています。これは純粋なC++では悪い考えであり、p/invokeでは悪い考えです。

代わり

は、C#は構造(ちょうど refキーワードを使用)だけでそれを埋める。

+0

私はrefを使用しようとしましたが、私はまだ適切な価値を得ることができませんでした...私の編集した質問を見てもらえますか? – mkolarek

+0

@kolarek:私の答えで言ったように、 'ref'または' out'キーワードを使うとC#は実際にポインタを渡します。ですから、C++側で 'void detectMarkers(/*...*/markStruct * MarkerInfo)'を使い、 'MarkerInfo-> id = 3;'を使ってください。また、p/invokeシグネチャの 'In'属性を取り除きます。これは、C++からデータを取得しないことを意味します。これは明らかにあなたが望むものの反対です。 –

+0

ありがとう、私はそれを稼働している! – mkolarek

3

MarkerInfo変数は、LOCです関数が返ってくると範囲外になります。 ローカル変数へのポインタを返しません。ポインタが指すオブジェクトはもう存在しません。

+0

ありがとうございます!私は代わりに何をすべきかについての提案がありますか? – mkolarek

0

ポストについては、この旋回... THXを与えるつもりC++コードへのポインタを渡す持っています...

// 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); 
// */ 
関連する問題