「デリゲートをアンマネージ コードに渡すとき、デリゲートは 2 度と呼び出されないことが確実になるまでマネージ アプリケーションによって維持されなければなりません。」エラーが発生する - C#

「デリゲートをアンマネージ コードに渡すとき、デリゲートは 2 度と呼び出されないことが確実になるまでマネージ アプリケーションによって維持されなければなりません。」エラーが発生する場合の対処法です。

エラーメッセージ

以下のメッセージが表示されます。
追加情報:コールバックが、型 '(型名)::Invoke' のガベージ コレクションされたデリゲートで行われました。これは、アプリケーションのクラッシュ、破損、およびデータの損失を発生させる可能性があります。デリゲートをアンマネージ コードに渡すとき、デリゲートは 2 度と呼び出されないことが確実になるまでマネージ アプリケーションによって維持されなければなりません。
英語では以下です。
Message: A callback was made on a garbage collected delegate of type '(型名)::Invoke'. This may cause application crashes, corruption and data loss. When passing delegates to unmanaged code, they must be kept alive by the managed application until it is guaranteed that they will never be called.

原因

デリゲートを格納している変数が解放されてしまったため、コールバックがnullになった可能性があります。

エラーの起きるコード例

以下のコードではエラーが発生します。
public class LowLevelWavePlay
{
  public delegate void WaveOutProc(IntPtr hdrvr, WaveOutMessage uMsg, int dwUser,
    IntPtr wavhdr, int dwParam2);

  public void OpenWaveOutHandle()
  {
    WaveOutProc m_BufferProc = new WaveOutProc(WaveOutProcCallback);
    MMRESULT rc = waveOutOpen(ref WaveOutHandle, WAVE_MAPPER, ref WaveFormatEx,
      m_BufferProc, IntPtr.Zero, CALLBACK_FUNCTION);
  }
}

解説

デリゲートを格納する変数 m_BufferProc をOpenWaveOutHandle()メソッド内にローカル変数で宣言しています。このため、関数を抜けた後はガベージコレクションによって任意のタイミングで解放されてしまうため、コールバック関数が呼び出される時点での存在が保証されなくなります。

修正コード例

以下の修正をします。
public class LowLevelWavePlay
{
  public delegate void WaveOutProc(IntPtr hdrvr, WaveOutMessage uMsg, int dwUser,
    IntPtr wavhdr, int dwParam2);
  private WaveOutProc m_BufferProc;

  public void OpenWaveOutHandle()
  {
    m_BufferProc = new WaveOutProc(WaveOutProcCallback);
    MMRESULT rc = waveOutOpen(ref WaveOutHandle, WAVE_MAPPER, ref WaveFormatEx,
      m_BufferProc, IntPtr.Zero, CALLBACK_FUNCTION);
  }
}

解説

デリゲートを格納する変数 m_BufferProc をクラスのメンバ変数として宣言します。メンバ変数で宣言すれば、OpenWaveOutHandle()メソッドを抜けてもm_BufferProc 変数の内容は解放されず保持され続けるため、コールバック関数が正しく呼び出されます。
著者
iPentecのメインプログラマー
C#, ASP.NET の開発がメイン、少し前まではDelphiを愛用
最終更新日: 2017-10-02
作成日: 2015-04-10
iPentec all rights reserverd.