C # Platform-invoke, c-style union with reference and type values

I am trying to marshall the following structure

struct OpalMessage {
  OpalMessageType m_type;   ///< Type of message
  union {
    const char *             m_commandError;       ///< Used by OpalIndCommandError
    OpalParamGeneral         m_general;            ///< Used by OpalCmdSetGeneralParameters
    OpalParamProtocol        m_protocol;           ///< Used by OpalCmdSetProtocolParameters
    OpalParamRegistration    m_registrationInfo;   ///< Used by OpalCmdRegistration
    OpalStatusRegistration   m_registrationStatus; ///< Used by OpalIndRegistration
    OpalParamSetUpCall       m_callSetUp;          ///< Used by OpalCmdSetUpCall/OpalIndProceeding/OpalIndAlerting/OpalIndEstablished
    const char *             m_callToken;          ///< Used by OpalCmdHoldcall/OpalCmdRetrieveCall/OpalCmdStopRecording
    OpalStatusIncomingCall   m_incomingCall;       ///< Used by OpalIndIncomingCall
    OpalParamAnswerCall      m_answerCall;         ///< Used by OpalCmdAnswerCall/OpalCmdAlerting
    OpalStatusUserInput      m_userInput;          ///< Used by OpalIndUserInput/OpalCmdUserInput
    OpalStatusMessageWaiting m_messageWaiting;     ///< Used by OpalIndMessageWaiting
    OpalStatusLineAppearance m_lineAppearance;     ///< Used by OpalIndLineAppearance
    OpalStatusCallCleared    m_callCleared;        ///< Used by OpalIndCallCleared
    OpalParamCallCleared     m_clearCall;          ///< Used by OpalCmdClearCall
    OpalStatusMediaStream    m_mediaStream;        ///< Used by OpalIndMediaStream/OpalCmdMediaStream
    OpalParamSetUserData     m_setUserData;        ///< Used by OpalCmdSetUserData
    OpalParamRecording       m_recording;          ///< Used by OpalCmdStartRecording
    OpalStatusTransferCall   m_transferStatus;     ///< Used by OpalIndTransferCall
    OpalStatusIVR            m_ivrStatus;          ///< Used by OpalIndCompletedIVR
  } m_param;
};

to c #. The obvious problem is two lines, which will inevitably be reference types.

So, I tried this:

    [StructLayout(LayoutKind.Explicit)]
    public struct OpalMessageStrUnion
    {
      [FieldOffset(0)]
      [MarshalAs(UnmanagedType.LPStr)]
      public string m_commandError;       ///< Used by OpalIndCommandError

      [FieldOffset(0)]
      [MarshalAs(UnmanagedType.LPStr)]
      public string m_callToken;          ///< Used by OpalCmdHoldcall/OpalCmdRetrieveCall/OpalCmdStopRecording
    }

    [StructLayout(LayoutKind.Explicit)]
    public struct OpalMessageUnion
    {
      [FieldOffset(0)]      
      public OpalParamGeneral m_general;            ///< Used by OpalCmdSetGeneralParameters

      [FieldOffset(0)]
      public OpalParamProtocol m_protocol;           ///< Used by OpalCmdSetProtocolParameters

      [FieldOffset(0)]
      public OpalParamRegistration m_registrationInfo;   ///< Used by OpalCmdRegistration

      [FieldOffset(0)]
      public OpalStatusRegistration m_registrationStatus; ///< Used by OpalIndRegistration

      [FieldOffset(0)]
      public OpalParamSetUpCall m_callSetUp;          ///< Used by OpalCmdSetUpCall/OpalIndProceeding/OpalIndAlerting/OpalIndEstablished     

      [FieldOffset(0)]
      public OpalStatusIncomingCall m_incomingCall;       ///< Used by OpalIndIncomingCall

      [FieldOffset(0)]
      public OpalParamAnswerCall m_answerCall;         ///< Used by OpalCmdAnswerCall/OpalCmdAlerting

      [FieldOffset(0)]
      public OpalStatusUserInput m_userInput;          ///< Used by OpalIndUserInput/OpalCmdUserInput

      [FieldOffset(0)]
      public OpalStatusMessageWaiting m_messageWaiting;     ///< Used by OpalIndMessageWaiting

      [FieldOffset(0)]
      public OpalStatusLineAppearance m_lineAppearance;     ///< Used by OpalIndLineAppearance

      [FieldOffset(0)]
      public OpalStatusCallCleared m_callCleared;        ///< Used by OpalIndCallCleared

      [FieldOffset(0)]
      public OpalParamCallCleared m_clearCall;          ///< Used by OpalCmdClearCall

      [FieldOffset(0)]
      public OpalStatusMediaStream m_mediaStream;        ///< Used by OpalIndMediaStream/OpalCmdMediaStream

      [FieldOffset(0)]
      public OpalParamSetUserData m_setUserData;        ///< Used by OpalCmdSetUserData

      [FieldOffset(0)]
      public OpalParamRecording m_recording;          ///< Used by OpalCmdStartRecording

      [FieldOffset(0)]
      public OpalStatusTransferCall m_transferStatus;     ///< Used by OpalIndTransferCall

      [FieldOffset(0)]
      public OpalStatusIVR m_ivrStatus;          ///< Used by OpalIndCompletedIVR

    }

    /// <summary>
    /// Message to/from OPAL system.
    /// This is passed via the OpalGetMessage() or OpalSendMessage() functions.
    /// </summary> 
    [StructLayout(LayoutKind.Explicit)]
    public struct OpalMessage
    {
      //this guy is an enumeration b.t.w.
      /// <summary>
      /// type of message
      /// </summary> 
      [FieldOffset(0)]
      public OpalMessageType m_type;

      [FieldOffset(4)]
      public OpalMessageUnion m_param;

      [FieldOffset(4)]
      public OpalMessageStrUnion m_strParam;
    }

However, I still get a marshaling error telling me that this will not work, because I am mixing an object with non-object types in the same memory location. I now assume that the structures themselves (i.e. OpalParamGeneral, etc.) also cannot mix reference and value types, even if they are laid out sequentially?

Making a separate function call for each structure is, by the way, not an option. I would rather write a COM wrapper than doing this.

+1
1

[StructLayout (LayoutKind.Explicit)] , , . , , .

, . . , . , , , IntPtr .

CLR TypeLoadException, .

, , , . OpalXxx , . , IntPtr . blittable MSDN.

+4

Source: https://habr.com/ru/post/1523605/


All Articles