P /调用多个级别的联合

时间:2013-11-15 08:03:56

标签: c# c struct pinvoke

我试图将pjsip_event包装到C#中,结构的顶层似乎是正确的但是子部分似乎直接指向未知的内存。

尝试换行的结构:

struct pjsip_event
{
/** This is necessary so that we can put events as a list. */
PJ_DECL_LIST_MEMBER(struct pjsip_event);

/** The event type, can be any value of \b pjsip_event_id_e.
 */
pjsip_event_id_e type; //ENUM

/**
 * The event body as union, which fields depends on the event type.
 * By convention, the first member of each struct in the union must be
 * the pointer which is relevant to the event.
 */
union
{
    /** Timer event. */
    struct
    {
        pj_timer_entry *entry;      /**< The timer entry.           */
    } timer;

    /** Transaction state has changed event. */
    struct
    {
        union
        {
            pjsip_rx_data   *rdata; /**< The incoming message.      */
            pjsip_tx_data   *tdata; /**< The outgoing message.      */
            pj_timer_entry  *timer; /**< The timer.                 */
            pj_status_t      status;/**< Transport error status.    */
            void            *data;  /**< Generic data.              */
        } src;
        pjsip_transaction   *tsx;   /**< The transaction.           */
            int                              prev_state; /**< Previous state.    */
        pjsip_event_id_e     type;  /**< Type of event source:      
                                     *      - PJSIP_EVENT_TX_MSG
                                     *      - PJSIP_EVENT_RX_MSG,
                                     *      - PJSIP_EVENT_TRANSPORT_ERROR
                                     *      - PJSIP_EVENT_TIMER
                                     *      - PJSIP_EVENT_USER
                                     */
    } tsx_state;

    /** Message transmission event. */
    struct
    {
        pjsip_tx_data       *tdata; /**< The transmit data buffer.  */

    } tx_msg;

    /** Transmission error event. */
    struct
    {
        pjsip_tx_data       *tdata; /**< The transmit data.         */
        pjsip_transaction   *tsx;   /**< The transaction.           */
    } tx_error;

    /** Message arrival event. */
    struct
    {
        pjsip_rx_data       *rdata; /**< The receive data buffer.   */
    } rx_msg;

    /** User event. */
    struct
    {
        void                *user1; /**< User data 1.               */
        void                *user2; /**< User data 2.               */
        void                *user3; /**< User data 3.               */
        void                *user4; /**< User data 4.               */
    } user;

} body;
};

#define PJ_DECL_LIST_MEMBER(type)                       \
                                   /** List @a prev. */ \
                                   type *prev;          \
                                   /** List @a next. */ \
                                   type *next 

我的托管c#结构看起来像这样:

using System;
using System.Runtime.InteropServices;

namespace Interop.Enum {
    [StructLayout(LayoutKind.Sequential)]
    public struct pjsip_event {
        public IntPtr prev;
        public IntPtr next;

        public pjsip_event_id_e type; //ENUM

        public pjsip_event__body body;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct pjsip_event__body {
        public pjsip_event__body__timer timer;

        public pjsip_event__body__tsx_state tsx_state;
        public pjsip_event__body__tx_msg tx_msg;
        public pjsip_event__body__tx_error tx_error;
        public pjsip_event__body__rx_msg rx_msg;
        public pjsip_event__body__user user;

    }

    [StructLayout(LayoutKind.Sequential)]
    public struct pjsip_event__body__timer {
        public IntPtr entry;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct pjsip_event__body__tsx_state {
        public pjsip_event__body__tsx_state__src src;
        public IntPtr tsx;
        public int prev_state;
        public pjsip_event_id_e type;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct pjsip_event__body__tsx_state__src {
        public IntPtr rdata;
        public IntPtr tdata;
        public IntPtr timer;
        public int status;
        public IntPtr data;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct pjsip_event__body__tx_msg {
        public IntPtr tdata;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct pjsip_event__body__tx_error {
        public IntPtr tdata;
        public IntPtr tsx;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct pjsip_event__body__rx_msg {
        public IntPtr rdata;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct pjsip_event__body__user {
        public IntPtr user1;
        public IntPtr user2;
        public IntPtr user3;
        public IntPtr user4;
    }
}

我调用以下方法来获取指向此结构的指针:

[UnmanagedFunctionPointer(CallingConvention.StdCall)]
unsafe public delegate void pjsua_callback_on_call_state(int call_id, pjsip_event* evnt);

如果我删除

public pjsip_event__body__tsx_state__src src;

pjsip_event_ body _tsx_state__src的其余部分似乎有正确的值,否则只是随机的东西。

任何想法在这个阶段都会有所帮助

1 个答案:

答案 0 :(得分:2)

联盟将每个成员覆盖在同一个内存位置。在C#中,您需要使用LayoutKind.Explicit,并为每个成员指定零FieldOffset。例如:

[StructLayout(LayoutKind.Explicit)]
public struct pjsip_event__body__tsx_state__src {
    [FieldOffset(0)]
    public IntPtr rdata;
    [FieldOffset(0)]
    public IntPtr tdata;
    [FieldOffset(0)]
    public IntPtr timer;
    [FieldOffset(0)]
    public int status;
    [FieldOffset(0)]
    public IntPtr data;
}