Visual Basic 6.0 テクニック
VB6対応

 

Visual Basic 中学校 > VB6 テクニック >

3.メッセージボックスを使い倒す

 

 

メッセージボックスは単にメッセージを表示するだけではなく、ユーザーに「はい」「いいえ」等を選択させることもできる大変便利な機能です。

今回はこのメッセージボックスについて、「ユーザーの選択を取得する方法」と「メッセージボックスでヘルプを使う方法」「メッセージボックスの表示位置を指定する方法」を説明します。前半は初級者レベルといえますが後半は高度なテクニックを扱うことになります。まさにタイトル通りメッセージボックスを使い倒すことになるでしょう。一部のテクニックはインプットボックスにも応用できます。

 

1.基本

 

メッセージボックスの機能は MsgBox関数を呼び出すことにより使用できます。ただ単にメッセージを表示すればよいだけの場合は単純に次のようします。


MsgBox "こんにちは!世界"
 

メッセージボックスのタイトルを設定する場合はこれに続けて第3引数にタイトルを指定します。


MsgBox "こんにちは!世界" , ,"あいさつ"
 

この例では 「あいさつ」というタイトルのメッセージボックスに 「こんにちは!世界」と表示されます。

 

2.ユーザーに選択させる

 

メッセージボックスを使ってユーザーに選択させることもできます。選択させるには第2引数にどのような選択をさせるのかを定数で指定します。

次の例では「性別」というタイトルのメッセージボックスに「あなたは男ですか?」と表示させ、「はい」か「いいえ」をユーザーに選ばせます。


MsgBox "あなたは男ですか?", vbYesNo, "性別"
 

この例ではユーザーが「はい」を押しても「いいえ」を押しても何も起こりません。ユーザーが何を選択したか知るにはMsgBox関数の戻り値を調べればよいのですがその説明をする前に「はい」「いいえ」以外にどんな選択肢の種類があるかを定数とともに表にまとめておきます。

定数 選択肢
vbOKOnly 0 [OK] 
vbOKCancel 1 [OK]  [キャンセル] 
vbAbortRetryIgnore 2 [中止] [再試行] [無視] 
vbYesNoCancel 3 [はい] [いいえ] [キャンセル] 
vbYesNo 4 [はい]  [いいえ] 
vbRetryCancel 5 [再試行]  [キャンセル] 
vbCritical 16 警告メッセージ アイコン
vbQuestion 32 問い合わせメッセージ アイコン
vbExclamation 48 注意メッセージ アイコン
vbInformation 64 情報メッセージ アイコン
vbDefaultButton1 0 第 1 ボタンを標準ボタンにします。
vbDefaultButton2 256 第 2 ボタンを標準ボタンにします。
vbDefaultButton3 512 第 3 ボタンを標準ボタンにします。
vbDefaultButton4 768 第 4 ボタンを標準ボタンにします。
vbApplicationModal 0 アプリケーション モーダルに設定します。メッセージ ボックスに応答するまで、現在選択中のアプリケーションの実行を継続できません。
vbSystemModal 4096 システム モーダルに設定します。メッセージ ボックスに応答するまで、すべてのアプリケーションが中断されます。
vbMsgBoxHelpButton 16384 ヘルプ ボタンを追加します。
VbMsgBoxSetForeground 65536 最前面のウィンドウとして表示します。
vbMsgBoxRight 524288 テキストを右寄せで表示します。
vbMsgBoxRtlReading 1048576 テキストを、右から左の方向で表示します。

この表はMSDNに掲載されている物とほぼ同じです。表の初めの方の項目は選択肢に関する物ですが後の方には機能的な定数もあります。表を参考に使用してください。値が0の項目は規定値で設定されています。

また、複数の項目を組み合わせるには演算子 Or を使います。たとえば、警告アイコンとともに「再試行」と「キャンセル」を選択させるには次のようにします。


MsgBox  "これは警告のテストです" , vbCritical Or vbRetryCancel, "テスト"
 

「標準ボタン」とはユーザーが Enterキーを押したときに押下されるボタンのことです。また、vbMsgBoxRtlReadingなどは日本版(?)では使用できないようです。

 

3.ユーザーの選択を取得する

 

ユーザーの選択したボタンは MsgBox関数の戻り値となります。そこで、戻り値を調べればユーザーが何を選択したかを判断し適切な対応をすることができます。

戻り値も定数で判断するのが一般的です。たとえば、「はい」が選択されたときには vbYes が戻り値となります。

ユーザーの選択を判断する簡単なサンプルを次に示します。

Dim Answer As Long

Answer = MsgBox ( "あなたは英語ができますか?" , vbYesNoCancel , "言語選択" )

Select Case Answer

Case vbYes

MsgBox "HELLO!"

Case vbNo

MsgBox "こんにちは!"

Case vbCancel

MsgBox "キャンセルされました。"

End Select

選択したボタンと戻り値の関係は次の表の通りです。

定数 選択されたボタン
vbOK 1 [OK]
vbCancel 2 [キャンセル]
vbAbort 3 [中止]
vbRetry 4 [再試行]
vbIgnore 5 [無視]
vbYes 6 [はい]
vbNo 7 [いいえ]

 

4.ヘルプファイルを使う

 

注意:ここに書かれている説明を理解するにはヘルプファイルについての基本的な知識が必要です。

プログラムに印刷機能をつける場合にはプリンターの状態などが適切に設定されていなければなりません。もし、適切でないならば 「プリンターの設定がされていません。」 とメッセージを表示するのが普通です。さらに、プリンターの設定を正しくするにはどうしたらよいのかを説明してくれれば親切なプログラムといえるでしょう。

このような場合のためにメッセージボックスに「ヘルプ」ボタンを追加してヘルプを表示させることもできます。ヘルプボタンを表示するには第2引数に vbMsgBoxHelpButton を設定するだけです。

さらにヘルプボタンが押されたときに表示されるヘルプを指定するには 第4引数に ヘルプファイル名、第5引数に 表示するページのコンテクストを指定します。

残念ながらヘルプファイルを作成する機能はVBにはありませんので、この機能を使う場合はすでに存在するヘルプファイルを指定することになります。

ただ、Visual Studio付属のツールやフリーウェアにはヘルプファイルを作成できる物もありますのでヘルプファイルが必要な人は試してみてください。

 

5.メッセージボックスの表示位置を設定する

 

警告________________________________________

ここでの説明は高度であるとともに初心者には危険です。APIやフックについての基本的な知識がない方は十分に注意してください。ここに書かれていることを元にとった行動で何らかの損害を受けたとしても私には一切責任がないことを再確認しておきます。たとえ、ここに書かれている内容が間違っていた場合でもそうです。

__________________________________________

 

MsgBox関数は以上に見てきたようになかなか便利な関数なのですが 表示位置を指定する ことはできません。通常はこのことで困ったりしませんが、表示位置を指定したいときには歯がゆい物です。

しかし、API を使えばメッセージボックスの表示位置を設定することもできます。

これには CBTProc というプロシージャを使います。このプロシージャは特殊なプロシージャで、Windowsから直接呼び出されます。このプロシージャが呼び出されるのは次の場合です。

・ウィンドウをアクティブ化する前
・ウィンドウを作成する前
・ウィンドウを破棄する前
・ウィンドウを最小化する前
・ウィンドウを最大化する前
・ウィンドウを移動する前
・ウィンドウのサイズを変更する前
・システムコマンドを完了する前
・システムメッセージキューからマウスイベントやキーボードイベントを削除する前
・キーボードフォーカスを設定する前
・システムメッセージキューを同期させる前

メッセージボックスもウィンドウですから、アクティブ化される直前をねらってこのプロシージャから位置を指定します。

これでプログラムの設計図ができましたから実現方法を考えます。

まず、CBTProcプロシージャをセットするために SetWindowsHookEx関数を使います。この関数で指定したプロシージャがCBTProcプロシージャとなります。この技術をフックを言います。

フックしたプロシージャは必ずフックを解かなければなりません。そうしないと、Windowsはそれ以降も上記の表に該当する場合にこのプロシージャを呼び出してしまい正常に作動しなくなります。フックを行う場合には用事が済んだら速やかにフックを解きます。

フックを解くにはUnhookWindowsHookEx関数を使います。

この他にウィンドウの情報を設定するためのSetWindowPos関数も使います。

プログラムの核となる部分は以下の通りです。この部分は標準モジュールに記述する必要があります。

Public Sub SetMsgBox(Left As Long, Top As Long)

    m_Left = Left

    m_Top = Top

    HookHandle = SetWindowsHookEx(WH_CBT, AddressOf CBTProc, App.hInstance, App.ThreadID)

End Sub

Private Function CBTProc(ByVal nCode As Long, ByVal wParam As Long, ByVal lParam As Long) As Long

    Dim Ret As Long

    If nCode = HCBT_ACTIVATE Then

        Ret = SetWindowPos(wParam, 0, m_Left, m_Top, 0, 0, SWP_NOSIZE Or SWP_NOZORDER Or SWP_NOACTIVATE)

        Ret = UnhookWindowsHookEx(HookHandle)

    End If

    CBTProc = Ret

End Function

SetMsgBoxにメッセージボックスのX座標と、Y座標を渡すと、呼び出されたメッセージボックスの位置に反映される仕組みになっています。SetMsgBoxは同時にフックを行っています。従ってこのプロシージャを呼び出した後にMsgBoxを表示しようとするとその直前に CBTProc が呼び出されるわけです。

このタイミングをねらってCBTProc関数の中でメッセージボックスの位置を設定します。CBTProc関数の引数はWindowsかた直接送られてくるので自分では設定できません。この例のようにしてください。

第1引数 nCode を調べるとこの関数が呼び出された理由が分かります。今回はメッセージボックスがアクティブになるときに処理をしたいので nCode が HCBT_ACTIVATE であるかを調べればよいわけです。

この場合、メッセージボックスのウィンドウのハンドルは wParamに格納されているのでこれを利用してSetWindowPos関数を呼び出します。この例では 横幅 と 縦幅 は 0 になっていますがフラグにSWP_NOSIZEを指定しているのでこの設定は無視されて規定値が採用されます。もしこの値も自分で設定したいときはこのフラグをはずして、第5、第6引数に数値を入れてください。 

それでは、標準モジュールの全コードを示します。

Option Explicit

Private Declare Function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA" _
        (ByVal idHook As Long, _
        ByVal lpfn As Long, _
        ByVal hmod As Long, _
        ByVal dwThreadId As Long) As Long

Private Declare Function UnhookWindowsHookEx Lib "user32" _
        (ByVal hHook As Long) As Long

Private Declare Function SetWindowPos Lib "user32" _
        (ByVal hwnd As Long, _
        ByVal hWndInsertAfter As Long, _
        ByVal x As Long, _
        ByVal y As Long, _
        ByVal cx As Long, _
        ByVal cy As Long, _
        ByVal wFlags As Long) As Long

Const WH_CBT = 5
Const HCBT_ACTIVATE = 5
Public Const SWP_NOSIZE = &H1          '「サイズを指定しない」オプション
Public Const SWP_NOZORDER = &H4     '「Zオーダーを指定しない」オプション
Public Const SWP_NOACTIVATE = &H10

Dim HookHandle As Long             '元のCBTProcプロシージャへのハンドル

Dim m_Left As Long 'メッセージボックスのX座標
Dim m_Top As Long 'メッセージボックスのY座標
Public Sub SetMsgBox(Left As Long, Top As Long)

    m_Left = Left
    m_Top = Top
    HookHandle = SetWindowsHookEx(WH_CBT, AddressOf CBTProc, App.hInstance, App.ThreadID)

End Sub
Private Function CBTProc(ByVal nCode As Long, ByVal wParam As Long, ByVal lParam As Long) As Long

    Dim Ret As Long

    If nCode = HCBT_ACTIVATE Then
        Ret = SetWindowPos(wParam, 0, m_Left, m_Top, 0, 0, SWP_NOSIZE Or SWP_NOZORDER Or SWP_NOACTIVATE)
        Ret = UnhookWindowsHookEx(HookHandle)

    End If

    CBTProc = Ret

End Function


このモジュールを使ってメッセージボックスの位置を指定するにはメッセージボックスを表示したい位置に次のように記述します。

SetMsgBox 0 , 0

MsgBox "この例では左上に表示されます。"

SetMsgBoxに続く2つの数字がX座標とY座標を表しています。なお、この例のように SetMsgBoxはメッセージボックスを呼び出す直前に使ってください。インプットボックスにも使えます。

本当は1回で位置の指定からメッセージボックスの表示までやってくれる関数を作ろうと思ったのですがMsgBox関数の引数が多くて見にくいコードになるのでやめました。このプログラムの作成中に何回か強制終了させられてしまいました。フックするときは気をつけなければ行けませんね。

この標準モジュールを使った簡単なプログラムはここからダウンロードできます。

MsgBoxEx.lzh

 

6.最後に

 

後半はちょっと内容があったと思っています。CBTフックにはいろいろな可能性があるようなので時間があったら試してみたいです。たとえば、メッセージボックスの背景に画像を表示するとか・・・。

あと、自分でメッセージボックス風のフォームを作ればこんな面倒くさいことしなくても位置を指定できますね。しかし、メッセージボックスは手軽さがメリット。私が作ったモジュールを利用すればプログラムサイズもほとんど大きくしないで手軽にメッセージボックスやインプットボックスの位置を指定できます。まぁどっちでもいいか。

私はこれからちょっと台湾に行って来ます。台湾からこのページを更新しようかな・・・。それでは。