2016-10-11 11 views
0

ネイティブライブラリ用のC#ラッパーを作成しています。これは、このコールバック関数が含まれています構造体パラメータへのポインタを持つC#ネイティブコールバック

typedef application_event_result(*application_event_ptr)(application_request* request); 

パラメータは、このような次のように定義されますC#で

[UnmanagedFunctionPointer(CallingConvention.Cdecl)] 
    public delegate application_event_result application_event([MarshalAs(UnmanagedType.Struct)] 
     ref application_request request); 

構造:

typedef struct { 
    uint32_t query; 
    const char* client; 
    bool  isAuthenticated; 
    bool  isGuest; 
} application_request; 

私はこのようなC#のコールバックデリゲートを定義しています

[StructLayout(LayoutKind.Sequential)] 
public struct application_request 
{ 
    public UInt32 query; 

    [MarshalAs(UnmanagedType.LPStr)] 
    public string client; 

    [MarshalAs(UnmanagedType.I1)] 
    public bool isAuthenticated; 

    [MarshalAs(UnmanagedType.I1)] 
    public bool isGuest; 
} 

このすべてのと思われます。 C#のコールバックがトリガされ、構造体のメンバーは期待値を持ちます。

しかし、ネイティブコードに戻ると、ヒープ破損例外が発生します(0xc0000374)。

明らかに、私はそれを避けたいと思います。

"ref application_request"パラメータの代わりにIntPtrを使用するようにC#コールバックシグネチャを変更した後、次のコードを使用して手動でマーシャリングします。

var request = Marshal.PtrToStructure<application_request>(requestptr); 

しかし、署名をできるだけ正確にしたいと思い、マーシャラを自分で使用する必要はありません。

コールバックデリゲートのシグネチャを変更しても構わないので、.netは自動的に構造体を変換できますか?

+0

returnパラメータのサイズが一貫していないため、エラーが発生しています。 IntPtrは4バイトなので、C#で4バイトのリターンパラメータを宣言する必要があります。ポインターの位置は、cとC#コードが一緒に動作するためには、静的メモリースペース内にある必要があります。 IntPtrはアンマネージスタティックメモリ空間にあるため、動作します。 C#オブジェクトが管理され、アンマネージ空間に置かれた場合にエラーが発生します。 – jdweng

+0

問題は戻り値ではなく、ポインターから構造体への入力パラメーターを使用しています。それをマークしてアンマネージドスペースに入れる方法はありますか? – RasmusW

+0

@jdweng戻り値は列挙型のように見えませんか? –

答えて

1

char*のメンバーはstructです。 C#マーシャラは、そのメモリの割り当てを解除する責任があるとみなします。それはCoTaskMemFreeを呼び出すことによってそうする。私は、メモリがC#コードによってまったく破壊されるものではないことは明らかです。あなたがMarshal.PtrToStringAnsiを呼び出して、文字列の値を読み取ることができ、あなたのコールバックメソッド内

[StructLayout(LayoutKind.Sequential)] 
public struct application_request 
{ 
    public UInt32 query; 

    public IntPtr client; 

    [MarshalAs(UnmanagedType.I1)] 
    public bool isAuthenticated; 

    [MarshalAs(UnmanagedType.I1)] 
    public bool isGuest; 
} 

:そのメンバーの代わりにIntPtrとして

元帥。

メンバーを非公開にしてプロパティで公開することで、これをまとめています。これにより、ポインタから文字列への変換をカプセル化できます。

+0

素晴らしい、これは動作します。そして、変換を行うプロパティにIntPtrをラップすることをお勧めします。 public string Client => Marshal。PtrToStringAnsi(クライアント); 構造体のプロパティがプライベートであり、C#マーシャラがまだそれらを見つけることができないことがわかりました。 – RasmusW

関連する問題