【VBA×WindowsAPI】UserFormのタイトルバーにアイコンを設定する

VBAでマクロを作成しているとき、他のアプリケーションと同じようにUserFormウィンドウのタイトルバーにアイコンを付けたいと感じるときが稀にあります。しかしUserFormはタイトルバーの文字列(Caption)を変えることはできても、アイコンを設定するような機能は備わっていません。

このようなVBAの機能だけでは実現できないこともWindows APIを利用することで実現することができます。マクロの機能的には存在しなくても全く問題のないアイコンですが、設定する方法が存在するということを知っておけばデザインをこだわりたいときに非常に役に立つノウハウとなります。

UserFormのタイトルバーにアイコンを設定する

Windows APIの関数を使うことで上画像のようにUserFormのタイトルバーにアイコンを設定することができます。アイコンを設定する方法として、既に画面上に存在するウィンドウに設定されているアイコン情報を流用する方法任意のアイコンファイル(.ico)をアイコンとして設定する方法があります。

VBAでUserFormのタイトルバーにアイコンを設定するには下記のWindows APIを利用します。
それぞれ関数のより詳細な使い方の解説は各関数のリンクページを参照下さい。

icon-check-square FindWindow関数:     ウィンドウハンドルを取得する
icon-check-square GetClassLongPtr関数:  指定ウィンドウのアイコン情報を取得する
icon-check-square SetClassLongPtr関数:  指定ウィンドウにアイコン情報を設定する
icon-check-square LoadImage関数:    指定画像ファイルをメモリ上に読み込む
icon-check-square DestroyIcon関数:     アイコン情報を保持したメモリを解放する

「そもそもWindows APIって何?」という方はコチラ(メインページ)も併せて参照下さい。

 

サンプルコード

下記は現在開かれているアプリケーションのウィンドウを取得して、そのウィンドウに設定されているアイコン情報をそのままUserFormのタイトルバーに設定するためのサンプルコードです。hWndAppにアイコン付きウィンドウのハンドルを渡すことで、UserFormのタイトルバーにそのウィンドウと同じアイコンを設定することができます。サンプルコードではExcelとメモ帳のコードを記載しています。(※メモ帳の場合はコード実行時にメモ帳ウィンドウを起動しておく必要あり)

 
下記はアイコンファイルを読み込んでUserFormのタイトルバーにアイコン設定するためのサンプルコードです。sPathIconに表示させたいアイコンファイルのフルパスを入力することで、その画像をアイコンとして設定することができます。アイコンサイズに決まりはないですサンプルコードでは32×32を想定しています。hIconの取得方法が違うだけで基本的にはもう一方の手法と同じ考えです。

 

コード解説

icon-edit UserFormのウィンドウハンドルを取得

ウィンドウにはそれぞれウィンドウハンドルと呼ばれる、ウィンドウを識別するためのID情報のようなものが付与されています。このウィンドウハンドルを取得することで、”どの”ウィンドウに対して処理を行うのかを簡単に指示することができます。(Windows APIでは頻出ワードです)

UserFormもウィンドウの1つであるため一意のウィンドウハンドルを持ちます。ウィンドウハンドルを取得するための関数はいくつも存在しますがここでは常套手段のFindWindow関数を使ってウィンドウハンドルを取得しています。FindWindow関数は下記のように記載することで指定のクラス名もしくはウィンドウ名から該当のウィンドウへのハンドルを取得することができます。

icon-code FindWindow関数 

hWnd = FindWindow(クラス名”, “ウィンドウ名”)

UserFormはクラス名が”ThunderDFrame”で、ウィンドウ名はMe.Captionとなります。いずれか片方を入力してもう一方の引数をvbNullStringとしても取得可能ですが、サンプルコードではどちらの引数も入力して確実にUserFormが取得できるようにしています。
 

icon-edit アイコンへのハンドルを取得 (既存ウィンドウから情報取得)

指定のウィンドウのアイコン情報(アイコンへのハンドル)を取得するにはUserFormと同じように対象のウィンドウのハンドルを取得する必要があります。Excel VBAの場合、ApplicationオブジェクトのhWndプロパティでExcelアプリケーションウィンドウのハンドルを取得することができます。

その他のアプリケーションのウィンドウハンドルを取得するには前項と同じくFindWindow関数GetActiveWindow関数等を使います。指定のウィンドウのクラス名やウィンドウ名などのウィンドウ情報は専用ツール(Microsoft Spy++等)で調べることができます。

取得したウィンドウハンドルが持つアイコン情報を取得するには、指定のウィンドウの情報を取得するためのGetClassLongPtr関数を使い下記のように記載します。

icon-code アイコン情報の取得 

hIcon = GetClassLongPtr(hWnd, GCL_HICON)

第1引数の「hWnd」にはアイコン情報を取得する対象のウィンドウハンドル、第2引数には取得する情報がアイコンであることを表す定数値「GCL_HICON」をそれぞれ入力することで、戻り値として入力したウィンドウが持つアイコン情報を取得することができます。
   

icon-edit アイコンへのハンドルを取得 (アイコンファイル読み込み)

ローカルにあるアイコンファイルからアイコン情報(アイコンへのハンドル)を取得するには、LoadImage関数を使って指定のアイコンデータをメモリ上に読み込ませる必要があります。

icon-code アイコン情報の取得 

hIcon = LoadImage(0, sPath, IMAGE_ICON, 32, 32, LR_LOADFROMFILE)

第1引数は今回の場合は使わないので「0」、第2引数の「sPath」には読み込ませるアイコンファイルのフルパス、第3引数には読み込ませる画像がアイコンであることを表す定数値「IMAGE_ICON」、第4と第5引数にはアイコンファイルの幅と高さ(ここでは32×32を想定)、第6引数にはファイルからデータを読み込ませることを表す定数値「LR_LOADFROMFILE」をそれぞれ入力します。

これにより指定のアイコンがメモリ上に読み込まれ、そのアイコンへのハンドルを戻り値として取得することができます。
  

icon-edit UserFormに取得したアイコンを設定

アイコンへのハンドルが取得できたら、UserFormにそのアイコンが示すハンドルを設定します。指定のウィンドウの情報を設定するためのSetClassLongPtr関数を使い下記のように記載します。

icon-code アイコン情報の設定 

hCls = SetClassLongPtr(hWnd, GCL_HICON, hIcon)

第1引数の「hWnd」にはアイコンを設定するUserFormのウィンドウハンドル、第2引数には設定する情報がアイコンであることを表す定数値「GCL_HICON」、第3引数の「hIcon」には設定するアイコンへのハンドルをそれぞれ入力します。戻り値としてアイコン設定前のウィンドウ情報が返ってきますが、サンプルコードのケースでは特に使用しないのでCallで呼び出すだけでも問題はありません。

これによりUserFormに入力したハンドルが示すアイコンが設定されます。
 

icon-edit 終了処理

前項の方法でアイコンを設定したままUserFormを閉じると内部のUserFormすべてにアイコンが付与された状態のままになってしまうので、コードで明示的にアイコンを解除させる必要があります。
(※アプリケーションを開き直せばアイコンは自動的に解除されます)

アイコンの解除は設定時と同じくSetClassLongPtr関数を使い下記のように記載します。

icon-code アイコンの解除 

Call SetClassLongPtr(hWnd, GCL_HICON, 0)

第3引数を「0」にすれば設定したアイコンを解除することができます。

また、LoadImage関数を使ってアイコンをメモリ上に読み込んだ場合はメモリの解放もあわせて行う必要があります。アイコンのメモリ解放はDestroyIcon関数を使い下記のように記載します。

icon-code アイコン解放 

Call DestroyIcon(hIcon)

 

関連情報

icon-share-square VBA×WindowsAPIまとめページ

その他のWindowsAPI関数は下記ページにまとまっているので合わせて参照下さい。

icon-share-square 参考

Microsoft公式:SetClassLongPtrW 関数 (winuser.h) – Win32
        GetClassLongPtrW 関数 (winuser.h) – Win32

Excel, VBA, Windows API

Posted by Lic