echo("備忘録");

IT技術やプログラミング関連など、技術系の事を備忘録的にまとめています。

C#でコールバック関数を使う

今までManaged DirectXを扱ってきたけど、訳あってUnmanagedなコードも扱う必要が出てきた。
で、キャプチャデバイスの列挙のため「DirectSoundCaptureEnumerate」関数をコールする必要があったのだけど、MSDN見たら、

HRESULT WINAPI DirectSoundCaptureEnumerate(
  LPDSENUMCALLBACK lpDSEnumCallback,
  LPVOID lpContext
);


pDSEnumCallback
DSEnumCallback 関数のアドレス。この関数は、システムにインストールされている各 DirectSoundCapture オブジェクトに対して呼び出される。

pContext
ユーザー定義コンテキストのアドレス。列挙コールバック関数が呼び出されるたびに、このコンテキストが関数に渡される。

で、コールバック関数ってどう設定するの?
って事で調べたのでメモ。

と言っても、特別難しいわけではなかった。
…ていうか、MSDNにズバリそのまま書いてあった。
https://msdn.microsoft.com/ja-jp/library/843s5s5x(v=vs.110).aspx

まあざっくりと言ってしまえば、

手順1.デリゲートを宣言する
手順2.そのデリゲート型の変数を使用箇所で作成し
手順3.実際のコールバック関数の中身を作成し
手順4.コールバック関数(のポインタなど)を引数として必要とする関数(今回はDirectSoundCaptureEnumerate)に手順2で作成した変数を引数として渡す。

でOK。

コード:

using System;
using System.Runtime.InteropServices;   // これがデリゲート型宣言で必要	

// using Microsoft.DirectX;
// using Microsoft.DirectX.DirectSound;

namespace Sample
{
    public unsafe class SampleClass
    {
        [DllImport("dsound.dll")]
        private extern static int DirectSoundCaptureEnumerate(DSEnumCallback cb, void* lpContext);

        private delegate bool DSEnumCallback(Guid* guid, string desc, string module, void* lpContext); // 手順1

        public SampleClass()
        {
            DSEnumCallback myCallBack = new DSEnumCallback(SampleClass.deviceEnum);    // 手順2
            int retVal = DirectSoundCaptureEnumerate(myCallBack, (void*)0);            // 手順4
        }

        // DSEnumCallback関数は、デバイス列挙を続けるならtrue、終了するならfalseを返す。
        private static bool deviceEnum(Guid* guid, string desc, string module, void* lpContext)    // 手順3
        {
            if (null != guid) { return false; }
            return true;
        }
    }

…ていうか、やはりポインタやら何やら、嫌な言葉がいっぱい出てくるようになった。
これも、C++から逃げ続けてきたツケ、なのかも。