ここでは、「タスクバーのトレイにアイコンを表示させる」という機能(API)のクラス化から、クラスモジュールやオブジェクトの設計を考えていきたいと思います。

「タスクトレイのアイコンを操作したい」
と思っても、VB にはそのような機能が標準実装されていません。
従って、該当する API 関数を宣言して利用することになります。
その関数とは、ずばり Shell_NotifyIcon です。
まずは、この関数の使い方を簡単に説明しておきます。
Private Declare Function Shell_NotifyIcon Lib "shell32.dll" _
Alias "Shell_NotifyIconA" ( _
ByVal dwMessage As Long, lpData As NOTIFYICONDATA) As Long
Shell32.dll という DLL に入っている関数で、追加や削除などの「メッセージ」と、アイコンの状態を示す構造体を使って「通知アイコン」の制御を行います。
| 引数 | 説明 | 型 |
|---|---|---|
| dwMessage | 「何をするのか?」を示すメッセージを指定する | Long |
| lpData | アイコンの情報が詰まった構造体を指定してね | NOTIFYICONDATA |
| メッセージ | 説明 |
|---|---|
| NIM_ADD | アイコンを「追加」する |
| NIM_MODIFY | 既に追加されているアイコンの状態を変更する |
| NIM_DELETE | 追加したアイコンを「削除」する |
| メンバ | 説明 | 型 |
|---|---|---|
| cbSize | 構造体のサイズ | Long |
| hWnd | アイコンを管理するウィンドウのハンドル | Long |
| uID | 各アイコンを識別するID番号 | Long |
| uFlags | アイコンに割り当てる機能(フラグ) | Long |
| uCallbackMessage | コールバックであると認識するためのオリジナルメッセージ | Long |
| hIcon | アイコン画像のハンドル | Long |
| szTip | アイコン上にマウスポインタを乗せたときに表示されるツールチップの文字列 | String |
| フラグ | 説明 |
|---|---|
| NIF_ICON | アイコン画像を表示します |
| NIF_TIP | ツールチップ表示を有効にします |
| NIF_MESSAGE | サブクラス化とコールバックを利用してマウスイベントをトラップします |
「コールバック」、「メッセージ」など、VB ではあまり扱わない概念が出てきました。トレイに表示させたアイコンをマウスクリックに反応させるには、「サブクラス化」という特殊なウィンドウ制御処理を用います。それまでやるとややこしくなるので、ここではとりあえず「アイコンを表示させる」ことをやってみます。
フォームに以下のようなコードを記述します。
Private m_nid As NOTIFYICONDATA
Private Sub AddStatusIcon( _
ByVal hWnd As Long, ByVal IconHandle As Long, ByRef ToolTipText As String)
With m_nid
.cbSize = Len(m_nid)
.uFlags = NIF_ICON Or NIF_TIP
.hWnd = hWnd
.hIcon = IconHandle
.szTip = ToolTipText & vbNullChar
End With
Call Shell_NotifyIcon(NIM_ADD, m_nid)
End Sub
AddStatusIcon サブプロシージャを作りました。
引数にウィンドウハンドルとアイコンハンドルとツールチップの文字列を受け取り、NOTIFYICONDATA のメンバデータを埋めて追加メッセージを送り、アイコンをトレイに追加(表示)します。
Private Sub ModifyStatusIcon( _
ByVal IconHandle As Long, ByRef ToolTipText As String)
With m_nid
.hIcon = IconHandle
.szTip = ToolTipText & vbNullChar
End With
Call Shell_NotifyIcon(NIM_MODIFY, m_nid)
End Sub
同じように、ModifyStatusIcon プロシージャを作ります。
一度トレイに追加したアイコンのデータを変更するには、変更メッセージと変更内容を送ります。
Private Sub DeleteStatusIcon()
Call Shell_NotifyIcon(NIM_DELETE, m_nid)
End Sub
追加したアイコンは、アプリケーションが終了するまでに「削除」しておかなければなりません。削除メッセージを送るだけで削除されます。
Private Sub Form_Load()
Call AddStatusIcon(hWnd, Icon.Handle, "StatusIcon")
End Sub
Private Sub Form_Unload(Cancel As Integer)
Call DeleteStatusIcon
End Sub
フォームの Load イベントと Unload イベントにサブプロシージャを利用するコードを記述します。これで、フォーム起動時にアイコンがトレイに追加され、プログラムが終了する(フォームが削除される)ときに自動的に削除されます。実行して確認してみてください。
アイコンを表示させるだけなのでシンプルにまとまりました。
これをクラスモジュールにまとめてみます。
クラスモジュールをプロジェクトに追加し、モジュールレベルの全宣言と、AddStatusIcon、ModifyStatusIcon、DeleteStatusIcon をそれぞれクラスモジュールへカット&ペーストします。クラス名は、StatusIconManager としました。
クラスのインターフェイスは Public で宣言します。
そのまま貼り付けた各サブプロシージャの宣言を Private から Public に変更します。各プロシージャがオブジェクトのメソッドとなります。
Public Sub AddStatusIcon( _
ByVal hWnd As Long, ByVal IconHandle As Long, ByRef ToolTipText As String)
Public Sub ModifyStatusIcon( _
ByVal IconHandle As Long, ByRef ToolTipText As String)
Public Sub DeleteStatusIcon()
処理を別モジュールに分別したおかげで、フォームモジュールの方は、かなりすっきりとします。クラスのインスタンスを格納するオブジェクト変数をモジュールレベルで宣言し、Load イベントでインスタンス作成、Unload イベントで解放するようにします。
Private m_theSIM As StatusIconManager
Private Sub Form_Load()
Set m_theSIM = New StatusIconManager
Call m_theSIM.AddStatusIcon(hWnd, Icon.Handle, "StatusIcon")
End Sub
Private Sub Form_Unload(Cancel As Integer)
Set m_theSIM = Nothing
End Sub
解放処理を担う Unload イベントでは、少し工夫をしています。
プログラム終了時に必ず DeleteStatusIcon メソッドを呼ばなければならないのだとすれば、クラスの特性のひとつ「起動・終了処理の制御」を利用して省略することができます。
Private Sub Class_Terminate()
Call DeleteStatusIcon
End Sub
自分自身のメソッドを呼び出すことで、終了処理の自動化を行っています。これで、このクラスを利用するクライアントは、終了時のアイコン削除処理を気にする必要がなくなりました。(ただし、オブジェクトインスタンス自体の解放は忘れてはなりません!)
非常に簡単なクラスを作成しました。
これだけでもクラスの恩恵をわずかながら受けています。
しかし、このままでは終われません。このクラスは構造的に未熟で、クラスのメリットを活かせていません。まだこれではフォームや標準モジュールに記述したときとあまり変わらないのです。
この講座のタイトルは StatusIcon であり、StatusIconManager ではありません。そう、ここに考え方の違いがあります。