【VBA×WindowsAPI】ウィンドウ(UserForm)を透明/半透明にする
VBAでUserFormをはじめとした指定のウィンドウを透明化したいと思うことはごく稀にあります。
VBAだけの機能では実現できませんが、Windows APIのいくつかの関数を呼び出すことでコードとしては簡単に設定ができます。(内容を理解するのは少し難易度が高いですが)
Windows APIを使ってウィンドウを透明にするコードは、基本的にほとんど決まりきったものです。そのためパッと使いたい程度であればサンプルコードをコピペすればそのまま利用できます。コード解説の項では詳しく内容を説明しているので興味のある方はあわせて参照下さい。
指定のウィンドウを透明/半透明にする
Windows APIの関数を使うことで上画像のように指定のウィンドウを透明化することができます。
UserFormだけではなくFindWindow関数でハンドルが取得できるようなウィンドウは基本的にすべて透明にすることができます。透明化は現在表示されているウィンドウに適用するため、一度ウィンドウを閉じて開き直すと元の表示に戻されます。(永続的なものではないということ)
透明にする方法は指定の色を透過させる方法とウィンドウ自体の透明度を変更させる方法の2通りあります。この2つを同時に適用させることもできますが指定の色だけを半透明にすることはできません。
VBAで指定のウィンドウを透明/半透明にするには下記のWindows APIを利用します。
それぞれ関数のより詳細な使い方の解説は各関数のリンクページを参照下さい。
FindWindow関数: ウィンドウハンドルを取得する
GetWindowLongPtr関数: ウィンドウスタイルを取得する
SetWindowLongPtr関数: ウィンドウスタイルを設定する
SetLayeredWindowAttributes関数: 透明度(アルファ値もしくは色キー)を設定する
「そもそもWindows APIって何?」という方はコチラ(メインページ)も併せて参照下さい。
サンプルコード
UserFormの指定の色を透明にするサンプルコードは下記の通りです。
事前の準備としてUserFormを1つ作成しその中に適当な大きさのLabelを作成して、名称を「lblAlpha」とします。背景色は画像ではクロマキーらしく緑にしていますが、実際はコード内で変更するので何色にしておいても問題ありません。WindowsAPIを使ってこのLabelのBackColorの色を透明にすることで、あたかもUserFormを”くり抜いた”かのようなウィンドウにすることができます。
UserFormの作成が完了したら下記コードをUserFormのコードに直接コピペします。これによりUserFormを表示させるとフォームのInitializeイベントが実行され、表示と同時に指定の色部分を透明にすることができます。ここではLabel部分のみが透明になりますが同色のテキストやボタン等のコントロールを配置した場合、それらもまとめて透明になってしまうので注意が必要です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
Option Explicit Private Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr Private Declare PtrSafe Function GetWindowLongPtr Lib "user32" Alias "GetWindowLongPtrA" (ByVal hWnd As LongPtr, ByVal nIndex As Long) As LongPtr Private Declare PtrSafe Function SetWindowLongPtr Lib "user32" Alias "SetWindowLongPtrA" (ByVal hWnd As LongPtr, ByVal nIndex As Long, ByVal dwNewLong As LongPtr) As LongPtr Private Declare PtrSafe Function SetLayeredWindowAttributes Lib "user32" (ByVal hWnd As LongPtr, ByVal crKey As Long, ByVal bAlpha As Byte, ByVal dwFlags As Long) As Long Const LWA_COLORKEY = &H1 '透明度の色キー Const LWA_ALPHA = &H2 '不透明度レベル Const GWL_EXSTYLE As Long = (-20) Const WS_EX_LAYERED As LongPtr = &H80000 Private Sub UserForm_Initialize() Dim hWnd As LongPtr Dim hStyle As LongPtr '透明化するウィンドウのハンドルを取得 hWnd = FindWindow(vbNullString, Me.Caption) '現状の拡張ウィンドウスタイルを取得 hStyle = GetWindowLongPtr(hWnd, GWL_EXSTYLE) '現状の拡張ウィンドウスタイルにレイヤードウィンドウを追加 Call SetWindowLongPtr(hWnd, GWL_EXSTYLE, hStyle Or WS_EX_LAYERED) '透明色設定 (※このUserForm内で使用しない色でれば何色でもOK) Me.lblAlpha.BackColor = RGB(0, 255, 0) 'ウィンドウの指定の色を透明化 Call SetLayeredWindowAttributes(hWnd, Me.lblAlpha.BackColor, 0, LWA_COLORKEY) End Sub |
指定の色ではなくウィンドウ全体を透明にするには下記のようなコードを書きます。
以下は最前面にあるメモ帳ウィンドウを半透明にするサンプルコードです。こちらは標準モジュールにコピペしてメモ帳ウィンドウを1つ以上開いた状態で実行すれば最前面のメモ帳が半透明になります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
Option Explicit Private Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr Private Declare PtrSafe Function GetWindowLongPtr Lib "user32" Alias "GetWindowLongPtrA" (ByVal hWnd As LongPtr, ByVal nIndex As Long) As LongPtr Private Declare PtrSafe Function SetWindowLongPtr Lib "user32" Alias "SetWindowLongPtrA" (ByVal hWnd As LongPtr, ByVal nIndex As Long, ByVal dwNewLong As LongPtr) As LongPtr Private Declare PtrSafe Function SetLayeredWindowAttributes Lib "user32" (ByVal hWnd As LongPtr, ByVal crKey As Long, ByVal bAlpha As Byte, ByVal dwFlags As Long) As Long Const LWA_COLORKEY = &H1 '透明度の色キー Const LWA_ALPHA = &H2 '不透明度レベル Const GWL_EXSTYLE As Long = (-20) Const WS_EX_LAYERED As LongPtr = &H80000 Sub main() Dim hWnd As LongPtr Dim hStyle As LongPtr '透明化するウィンドウのハンドルを取得 hWnd = FindWindow("Notepad", vbNullString) '現状の拡張ウィンドウスタイルを取得 hStyle = GetWindowLongPtr(hWnd, GWL_EXSTYLE) '現状の拡張ウィンドウスタイルにレイヤードウィンドウを追加 Call SetWindowLongPtr(hWnd, GWL_EXSTYLE, hStyle Or WS_EX_LAYERED) 'ウィンドウ全体を透明化 Call SetLayeredWindowAttributes(hWnd, 0, 100, LWA_ALPHA) End Sub |
コード解説
ウィンドウハンドルを取得する
ウィンドウにはそれぞれウィンドウハンドルと呼ばれる、ウィンドウを識別するためのID情報のようなものが付与されています。このウィンドウハンドルを取得することで、”どの”ウィンドウに対して処理を行うのかを簡単に指示することができます。(Windows APIでは頻出ワードです)
今回は指定のウィンドウを透明にしたいので、透明にする対象となるウィンドウのハンドルを習得します。ウィンドウハンドルを取得する方法はいくつも存在しますがここでは常套手段のFindWindow関数を使ってウィンドウハンドルを取得しています。FindWindow関数は下記のように記載することで指定のクラス名もしくはウィンドウ名から該当のウィンドウへのハンドルを取得することができます。
hWnd = FindWindow(“クラス名”, “ウィンドウ名”)
UserFormの場合はCaptionがウィンドウ名となるので引数を「(vbNullString, Me.Caption)」、メモ帳の場合はクラス名がNotepadとなるので引数を「(“Notepad”, vbNullString)」としています。
拡張ウィンドウスタイルにレイヤードウィンドウを追加
ウィンドウはハンドルのほかに「ウィンドウスタイル」という情報も持っています。
ウィンドウスタイルとはウィンドウの見た目や動作のスタイルのことで、例えばウィンドウの枠線やタイトルバー、最大化/最小化ボタンの有無などがこれにあたります。
そしてこのウィンドウスタイルには「拡張ウィンドウスタイル」というさらに応用的なウィンドウスタイルが存在します。こちらはウィンドウのドラッグ&ドロップ操作の機能やウィンドウの右側スクロールバー(ブラウザのような)の有無などがこれにあたります。
これらのスタイルはWindowsAPIの関数を使うことで取得したり設定したりが可能になります。UserForm初期状態のウィンドウスタイルと拡張ウィンドウスタイルは下画像のようになっていますが、ウィンドウを透明にするにはこの拡張ウィンドウスタイルにレイヤードウィンドウというものを追加する必要があります。(UserFormはあくまで一例でどのウィンドウでも可)
これをコードで行うには上画像のような既存で設定されている拡張ウィンドウスタイルを取得し、そのスタイルにレイヤードウィンドウを追加して、ウィンドウに再設定するという処理が必要になります。
現状の拡張ウィンドウスタイルを取得するにはGetWindowLongPtr関数、拡張ウィンドウスタイルを設定するにはSetWindowLongPtr関数を使います。サンプルコードの引数「GWL_EXSTYLE」は拡張ウィンドウスタイルのことを表しており、「hStyle Or WS_EX_LAYERED」は現状の拡張ウィンドウスタイル(hStyle)+レイヤードウィンドウ(WS_EX_LAYERED)を表しています。
透明化設定
拡張ウィンドウスタイルにレイヤードウィンドウの設定ができたらSetLayeredWindowAttributes関数を使いウィンドウの透明化(指定色のみの透過とウィンドウ全体の透過)の設定を行います。
指定の色を透明にするには下記のように記載します
Call SetLayeredWindowAttributes(hWnd, lColor, 0, LWA_COLORKEY)
色指定で透明化するには第4引数に定数値「LWA_COLORKEY」、第2引数に色コードを入力します。
色コードはVBAで扱うものと同じでRGB(255,255,255)や.BackColorなどの入力が可能です。
「LWA_COLORKEY」は該当のヘッダーファイル内に定義されていますが、VBAでは関数の呼び出しを行っているだけなのでこれら定数は定義されていません。そのため「Const LWA_COLORKEY = &H1」というかたちでコードの初めに定義しています。(引数として直接「&H1」を入力しても可)
第1引数の「hWnd」はスタイルにレイヤードウィンドウを追加したウィンドウのハンドルを入力、第3引数は色指定での透明化の際は使用しないので「0」を入力します。
これによりウィンドウ内にある「lColor」色の部分がすべて透明になります。
ウィンドウ全体を透明にするには下記のように記載します。
Call SetLayeredWindowAttributes(hWnd, 0, lAlpha, LWA_ALPHA)
ウィンドウ全体を透明化するには第4引数に定数値「LWA_ALPHA」、第3引数の「lAlpha」部分には透明度を入力します。透明度は「0(透明) ~ 255(不透明)」の256段階の整数いずれかです。(LWA_ALPHAもLWA_COLORKEYと同じく定数で値は「&H2」です)
第1引数の「hWnd」はスタイルにレイヤードウィンドウを追加したウィンドウのハンドルを入力、第2引数はウィンドウ全体の透明化の際は使用しないので「0」を入力します。
これによりウィンドウが「lAlpha」で指定した透明度を持ちます。
関連情報
VBA×WindowsAPIまとめページ
その他のWindowsAPI関数は下記ページにまとまっているので合わせて参照下さい。
参考
Microsoft公式:Windows の使用(レイヤード ウィンドウの使用)