StatusIcon

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

タスクトレイと通知アイコン

目次

Shell_NotifyIcon

「タスクトレイのアイコンを操作したい」
と思っても、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 に入っている関数で、追加や削除などの「メッセージ」と、アイコンの状態を示す構造体を使って「通知アイコン」の制御を行います。

Shell_NotifyIcon(関数)
引数説明
dwMessage「何をするのか?」を示すメッセージを指定するLong
lpDataアイコンの情報が詰まった構造体を指定してねNOTIFYICONDATA
dwMessage に指定するメッセージ一覧(定数)
メッセージ説明
NIM_ADDアイコンを「追加」する
NIM_MODIFY既に追加されているアイコンの状態を変更する
NIM_DELETE追加したアイコンを「削除」する
NOTIFYICONDATA(構造体)
メンバ説明
cbSize構造体のサイズLong
hWndアイコンを管理するウィンドウのハンドルLong
uID各アイコンを識別するID番号Long
uFlagsアイコンに割り当てる機能(フラグ)Long
uCallbackMessageコールバックであると認識するためのオリジナルメッセージLong
hIconアイコン画像のハンドルLong
szTipアイコン上にマウスポインタを乗せたときに表示されるツールチップの文字列String
uFlags で選択するフラグ一覧(定数)
フラグ説明
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 ではありません。そう、ここに考え方の違いがあります。