教えて!ExcelVBA!

ExcelVBAの基礎知識・書き方について紹介します。

【ExcelVBA API操作】ウィンドウに直接メッセージを送信しアプリケーションを終了(SendMessage)する方法を教えて!

SendMessage関数は、WindowsAPIの1つで、ウィンドウに対してメッセージを送信するために使用され、ウィンドウの制御や情報の取得などに利用されます。

API宣言

ExcelVBAでは、SendMessage関数を使用する前にAPI宣言を行う必要があります。API宣言を行うことで、ExcelVBAがWindowsAPI関数を認識することができるようになります。API宣言は次のように行います。

Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" (ByVal hWnd As Long, ByVal MSG As Long, ByVal wParam As Long, ByVal lParam As Long) As Long

解説

パラメータ 内容
Lib 使用する動的リンクライブラリ(DLL)の名前を指定します。ここでは "user32.dll"となります。
Alias API関数名を指定します。ここでは"SendMessageA"という関数名が指定されています。

引数については以下の通りです。

引数 内容
hWnd 送信先のウィンドウを識別するためのウィンドウハンドル(HWND)を指定します。ウィンドウハンドルは、ウィンドウを一意に識別するための値であり、FindWindowなどの関数を使って取得することが一般的です。
MSG 送信するメッセージを示す定数を指定します。SendMessage関数は様々なメッセージを送信できますが、どのメッセージを使用するかは操作内容によります。以下にメッセージコードを幾つか紹介します。
wParam メッセージに関連する情報を伝達するための整数型のパラメータです。具体的な役割はメッセージコードによって異なります。
lParam メッセージに関連する情報を伝達するためのもう一つの整数型のパラメータです。具体的な役割はメッセージコードによって異なります。

メッセージコードは以下の通りです。

コード 内容
&H10 ウィンドウに閉じる要求が送られます。通常はウィンドウを閉じるために使用されます。
&HC ウィンドウのテキストを設定できます。引数のlParamには、設定したいテキストを指定します。
&HD ウィンドウのテキストを取得できます。引数のlParamには、取得したテキストを受け取るためのバッファを指定します。
&H111 メニュー、ボタンなどのコントロールがクリックされたときに送信されるメッセージです。ボタンのクリックやメニューの選択などの操作をエミュレートする際に使用されます。
&H100 キーボードのキーが押されたときに送信されるメッセージです。特定のキーの操作をシミュレートする際に使用されます。
&H200 マウスがウィンドウ内で移動したときに送信されるメッセージです。マウス操作をエミュレートする際に使用されます。
&HFFFF 特定のメッセージを示す定数を使用しない場合に利用される空のメッセージコードとして使われることがあります。

※上記は一部のメッセージコードの例であり、他にもさまざまなメッセージコードがあります。各メッセージコードには、それぞれ独自の目的と動作がありますので、WindowsAPIの公式ドキュメントや参考文献を参照することをおすすめします。

使い方

SendMessage関数を呼び出し、メモ帳(Notepad)のウィンドウに対してメッセージを送信します。

Dim result As Long
result = SendMessage(notepadHwnd, &HFFFF, 0, ByVal textToWrite)

戻り値として、ウィンドウがメッセージを処理した結果を示す数値が返されます。ウィンドウがメッセージを正常に処理した場合、0以外の値が返ります。エラーで終了した場合、戻り値は0になります。

プログラミング例

以下に、プログラミング例を幾つか紹介します。

例1:メモ帳を起動してテキストを入力する

Declare PtrSafe Function FindWindow Lib "user32.dll" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long

Declare PtrSafe Function SendMessage Lib "user32.dll" Alias "SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As String) As Long

Sub StartNotepadAndWriteText()
    Dim notepadHwnd As Long
    Dim textToWrite As String
    Dim result As Long
    ' メモ帳のウィンドウクラス名とタイトルを指定してウィンドウハンドルを取得
    notepadHwnd = FindWindow("Notepad", vbNullString)
    If notepadHwnd <> 0 Then
        ' メモ帳のウィンドウにメッセージを送信してテキストを入力する
        textToWrite = "Hello, ExcelVBA!"
        result = SendMessage(notepadHwnd, &HFFFF, 0, ByVal textToWrite)
    Else
        MsgBox "メモ帳が見つかりませんでした。", vbExclamation
    End If
End Sub

例2:外部アプリケーションを終了する

Declare PtrSafe Function FindWindow Lib "user32.dll" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long

Declare PtrSafe Function SendMessage Lib "user32.dll" Alias "SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long

Sub CloseExternalApplication()
    Dim appName As String
    Dim appHwnd As Long
    Dim result As Long
    ' 終了させるアプリケーションのタイトルを指定
    appName = "Untitled - Notepad"
    ' アプリケーションのウィンドウハンドルを取得
    appHwnd = FindWindow(vbNullString, appName)
    If appHwnd <> 0 Then
        ' アプリケーションのウィンドウにWM_CLOSEメッセージを送信して終了させる
        result = SendMessage(appHwnd, &H10, 0, 0)
    Else
        MsgBox "指定したアプリケーションが見つかりませんでした。", vbExclamation
    End If
End Sub

これらの例では、SendMessage関数を使用して別のアプリケーション(メモ帳など)を制御しています。第1例ではメモ帳を起動してテキストを入力し、第2例では指定したアプリケーションを終了させています。ただし、外部アプリケーションを操作する場合は慎重に行う必要があります。

まとめ

SendMessage関数を利用することで、外部のアプリケーションを制御したり、アプリケーションを終了させたりすることが可能です。ただし、他のアプリケーションを終了させる操作は慎重に行う必要があります。不要なプロセスを終了させると、他のアプリケーションやシステムに影響を及ぼす場合がありますので、注意してください。