1

次の構造をマーシャリングしようとしています

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

C# に移行します。明らかな問題は、必然的に参照型になる 2 つの文字列です。

だから、私はこれを試しました:

    [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;
    }

ただし、同じメモリ位置でオブジェクトと非オブジェクト型を混在させているため、これが機能しないことを示すマーシャリング エラーがまだ発生しています。構造自体 (つまり、OpalParamGeneral など) も、順番に配置されていても、参照型と値型を混在させることはできないと思いますか?

ちなみに、構造体ごとに個別の関数呼び出しを行うことはオプションではありません。それを行うよりも、COMラッパーを作成したいと思います。

4

1 に答える 1

4

[StructLayout(LayoutKind.Explicit)] 属性は珍しいもので、構造体がマーシャリングされるときだけでなく、マネージド バージョンの構造体のレイアウトにも影響します。これは非常に便利です。言語自体がサポートしていない場合でも、マネージ言語で共用体を実装できます。

それらは問題を引き起こしますが、ガベージコレクターには問題があります。参照型への参照を見つけることができる必要がありますが、共用体では確実に見つけることができません。どのタイプが参照されているかを正確に判断できないためです。これは信頼性の問題でもあります。たとえば、参照型を IntPtr とオーバーラップさせて、その方法でオブジェクトのアドレスを発見することができます。

CLR クラス ローダーはこの状態をチェックし、オーバーラップが発生した場合は TypeLoadException をスローします。

これに対する回避策は明らかです。blittable 型のみを使用するようにする必要があります。すべての OpalXxx 型は、それ自体が blittable 型のみを含む構造体である必要があります。文字列の回避策は、代わりに IntPtr として宣言し、Marshal クラスを使用して値を変換することです。blittable 型の詳細については、このMSDN ライブラリの記事 を参照してください。

于 2012-07-02T12:35:56.130 に答える