WindowsAPIのMessageBoxがVBAのMsgBoxと大きく違うのは、ウインドウハンドルを指定できることである。
VBAのMsgBoxだとメッセージボックスは必ずエクセル側で表示されてしまう。
例えば、WindowsAPIで他のアプリを操作していてエクセル以外のウインドウがアクティブになっていたら、そのメッセージは表示されない。
タスクバーのエクセルアイコンが点滅して、自分でエクセルをアクティブにして初めて、メッセージボックスが表示されるのだ。
その辺りはMsgBoxの実行前に「SetForegroundWindow Application.Hwnd」を挟んでおけばとりあえず対応はできる。
けれど、結局はVBAによるエクセルからのメッセージボックスなので、表示位置はエクセルのウインドウ中央となる。
一方のWindowsAPIによるMessageBoxなら、引数でウインドウハンドルを指定できる。
もしも他のウインドウを操作している最中に表示させたいメッセージであれば、そのウインドウハンドルを指定してやれば、よりユーザビリティの高いプログラムになるとは思わないだろうか?
しかし、動作によってWindowsAPIの「MessageBox」とVBAの「MsgBox」を使い分けるのは面倒である。
なにしろ定数が異なる。
その定数に関する部分をできるだけVBAに寄せようというのが今回の試みだ。
というわけで早速コードを提示する。
なお、各種APIと定数の宣言は省略している。
Function ShowMessageBox(btn As Long, ico As Long, sText As String, sCap As String, Optional hWnd As LongPtr = 0, Optional isSysModal As Boolean = True) As Long SetForegroundWindow hWnd Dim uType As Long Select Case btn Case vbOKOnly uType = MB_OK Case vbOKCancel uType = MB_OKCANCEL Case vbYesNo uType = MB_YESNO Case vbYesNoCancel uType = MB_YESNOCANCEL End Select Select Case ico Case vbInformation uType = uType Or MB_ICONINFORMATION Case vbExclamation uType = uType Or MB_ICONEXCLAMATION Case vbQuestion uType = uType Or MB_ICONQUESTION Case vbCritical uType = uType Or MB_ICONSTOP End Select If isSysModal Then uType = uType Or MB_SYSTEMMODAL Dim ret As Long ret = MessageBox(hWnd, sText, sCap, uType) Select Case ret Case IDOK ShowMessageBox = vbOK Case IDCANCEL ShowMessageBox = vbCancel Case IDYES ShowMessageBox = vbYes Case IDNO ShowMessageBox = vbNo End Select End Function
要するにAPIの定数とVBAの定数を相互変換して、引数と戻り値をともにVBAのMsgBoxと同じにしているだけである。
機能としては最低限だろうか。
上記のサイトを参考に引数を増やすなどしてより柔軟に対応できるメッセージボックス関数を作るのも楽しいかもしれない。