コールバック関数を作成する

Microsoft Office 2000/Visual Basic プログラマーズ ガイド   

DLL 関数にコールバック関数が必要かどうかは、引数、または関数のドキュメントを参照して確認します。コールバック関数へのポインタを取得する引数は long ポインタで、通常はプリフィックスの "lp" が付いています。また、多くの場合、引数名のサフィックスは、その引数が関数へのポインタを取得することを示す "Func" となります。たとえば、EnumWindows 関数の Declare ステートメントを例にとると、lpEnumFunc 引数は、この関数にコールバック関数が必要であることを示しています。

  Declare Function EnumWindows Lib "user32" (ByVal lpEnumFunc As Long, _
              ByVal lngParam As Long) As Long

コールバック関数を見分けるには、関数のドキュメントを参照します。各コールバック関数には異なる引数が含まれます。コールバックが必要な DLL 関数についての情報は Win32API.txt で参照できますが、コールバック関数の作成に関する情報は含まれていません。

Microsoft Developer Network の Web サイト (https://www.microsoft.com/japan/developer/) にある Microsoft Platform SDK には、コールバック関数が必要なすべての DLL 関数、およびその DLL 関数に対応するコールバック関数についての情報が含まれています。ただし、この情報を使用する際は、C/C++ のコードを解釈して VBA に変換する必要があります。

コールバック関数には任意の名前を付けることができます。通常、DLL 関数の名前の後に "Proc" を付けた名前を使用します。たとえば、EnumWindows 関数のコールバック関数の名前は、EnumWindowsProc となります。1 つの DLL 関数には複数のコールバック関数を関連付けることができます。

次は、EnumWindowsProc 関数の C/C++ 定義です。これは Platform SDK でも説明されています。

  BOOL CALLBACK EnumWindowsProc(
   HWND hwnd, // 親ウィンドウのハンドル
   LPARAM lParam // アプリケーションで定義された値
);

この関数が VBA に変換されると次のようになります。

  Function EnumWindowsProc(ByVal hwnd As Long, ByVal lParam As Long) As Long
End Function

hwnd 引数はウィンドウのハンドルです。lParam 引数は、さまざまなデータ型になり得る、アプリケーション定義の引数です。EnumWindows 関数の lParam 引数に渡す値は、EnumWindowsProc 関数の lParam 引数に渡す値でもあります。lParam を長整数型 (Long) として定義する必要はありません。たとえば、リスト ボックス (ListBox) コントロールや配列に渡す場合は、ほかのデータ型として定義します。また、IParam に値を渡す必要もありません。

通常、コールバック関数は長整数型の値を返します。ゼロ以外は成功、ゼロは失敗を意味します。列挙を継続するには、コールバック関数は True を返す必要があるため、関数内で戻り値を True に設定する必要があります。戻り値を False に設定すると列挙は中断します。関数は、列挙が完了するか、False を返すまで実行されます。

重要   コールバック関数を定義する際は、次の点に注意してください。必要な場所に ByVal キーワードを含め、関数の戻り値を含めます。また、関数はドキュメントに従って正確に宣言されている必要があります。関数を正しく定義していない場合、ソリューションを試行する際にアプリケーション エラーが発生する原因になります。

EnumWindows 関数を呼び出す際、この関数は、既存の各ウィンドウに対して VBA プロジェクトの EnumWindowsProc 関数を呼び出し、ウィンドウのハンドルおよび IParam 引数に含まれる値を渡します。コールバック関数には、任意のコードを追加することができます。

次の例は、EnumWindows 関数のコールバック関数を示しています。EnumWindodwsProc と呼ばれるこのコールバック関数は、表示可能な親ウィンドウを、ParentWindow オブジェクトのカスタム コレクションである ParentWindows コレクションに追加します。ウィンドウをコレクションに追加するために、コレクション オブジェクトは IParam 引数のコールバック関数に渡されます。プロシージャは、ほかに 2 つの関数を呼び出します。IsWindowVisible API 関数は、ウィンドウが表示されるかどうかを確認します。GetWindowCaption プロシージャは、それに対して GetWindowText API 関数を呼び出し、ウィンドウのキャプションを返します。

メモ   親ウィンドウはプライマリ アプリケーション ウィンドウであり、子ウィンドウは親ウィンドウ内に存在します。別の DLL 関数である EnumChildWindows 関数は、親ウィンドウ内の子ウィンドウを列挙するために存在します。EnumWindows.xls サンプル ファイルでは、両方の関数を参照することができます。

  Function EnumWindowsProc(ByVal hWnd As Long, ByVal lParam As Object) As Long
   ' 表示されているすべてのウィンドウを ParentWindows コレクションに追加します。
   ' これは EnumWindows に呼び出されるコールバック関数です。
   '
   ' コールバック関数が実行されるたびに、hWnd 引数はハンドルを
   ' 特定のウィンドウに提供します。
   ' IParam 引数には、関数に渡すすべてのデータを使用できます。
   ' この場合はオブジェクト型として定義されるので、EnumWindows 関数は
   ' ParentWindows コレクションへの参照を渡すことができます。
   '
   ' この関数を使用して IsWindowVisible 関数を呼び出すコードを削除すると、
   ' 表示および非表示ウィンドウの両方を返すことができます。
   
   Dim strCaption As String
   Dim pwnNew As ParentWindow
   
   ' このウィンドウが表示されるかどうかを確認します。
   If IsWindowVisible(hWnd) Then
      Set pwnNew = lParam.Add(hWnd)
      ' 関数を呼び出して子ウィンドウを列挙します。
      EnumChildWindows hWnd, AddressOf EnumChildWindowsProc, _
         pwnNew.ChildWindows
   End If

   ' True を返してウィンドウの列挙を継続します。
   ' すべてのウィンドウの列挙が完了すると
   ' 関数の実行が停止します。
   EnumWindowsProc = True
End Function

EnumWindowsProc コールバック関数は、Office 2000 Developer CD-ROM の ODETools\V9\Samples\OPG\Samples\CH10 に含まれる EnumWindows.xls の modEnumWindows モジュールにあります。このプロシージャは、サイズの小さいカスタム オブジェクト モデルにおけるオブジェクトの作成に使用されます。ParentWindows コレクションには、各表示ウィンドウを参照する ParentWindow オブジェクトが含まれます。EnumWindowsProc 関数のアドレスは、ParentWindows コレクションの Class_Initialize イベント プロシージャから呼び出される EnumWindows 関数に渡されるため、既存のウィンドウは速やかにコレクションに追加されます。

ParentWindows コレクションが初期化されたら、インデックス、またはウィンドウのハンドルであるキーを使用してコレクション内の ParentWindow オブジェクトを参照できます。コレクションのメンバを参照するには、ParentWindows コレクションの Item プロパティを使用してください。たとえば、次のコードは、ParentWindows コレクションにある 3 番目の ParentWindow オブジェクトのキャプションを表示します。

  Debug.Print ParentWindows.Item(3).Caption