【VBA×WindowsAPI】SetWindowLongPtr関数の使い方
SetWindowLongPtr関数
SetWindowLongPtr関数は指定したウィンドウに関する情報をセットするための関数です。
WinAPIにはSetWindowLong関数という同じ機能を持つ関数が存在しますが、SetWindowLongPtr関数はこのSetWindowLong関数を64bit/32bitの両環境で使えるようにしたものです。
ウィンドウに関する情報として、指定のウィンドウのウィンドウスタイルや拡張ウィンドウスタイル、関連付いたウィンドウのハンドルなどをセットすることができます。
ウィンドウスタイルとはウィンドウの見た目や動作の基本的なスタイルのことで、例えばウィンドウの枠線やタイトルバー、最大化/最小化ボタンの有無などがこれにあたります。拡張ウィンドウスタイルとはさらに応用的なウィンドウスタイルのことで、ドラッグ&ドロップ操作の機能やウィンドウの右側スクロールバー(ブラウザのような)の有無などがこれにあたります。
ウィンドウは起動時に各アプリケーションで指定されたウィンドウスタイルを持って起動されます。VBAのUserFormのデフォルト時のウィンドウスタイルと拡張ウィンドウスタイルは下画像の通りです。たとえば「WS_CAPTION」はタイトルバーが有ることを表し、「WS_EX_LEFT」は左揃えのプロパティを持っていることを表します。(詳しくは上記ウィンドウスタイルのリンクを参照)
SetWindowLongPtr関数は指定したウィンドウスタイルを設定することができますが、スタイルを”追加”する場合には予め現在のウィンドウスタイルを取得しておき、そのウィンドウスタイル+追加のスタイルという形式でSetWindowLongPtr関数に入力する必要があります。このとき現状のウィンドウスタイルを取得するにはGetWindowLongPtr関数を使います。
ウィンドウスタイル以外にもいくつか取得できる情報がありますが、VBAで利用する際はUserFormのウィンドウスタイル/拡張ウィンドウスタイルを操作して本来のUserFormではできないことを可能にすることに利用したりします。(UserFormの透明化、ウィンドウ最大化/最小化ボタンの追加など)
使用方法
SetWindowLongPtr関数を使用するにはあらかじめ関数の宣言しておく必要があります。
※宣言をしないと関数は使えずにエラーとなるので書き忘れに注意しましょう。
使用しているWindowsが32bitか64bitかによって宣言時に書く文言が違います。
環境に合わせて以下のいずれかをコードの一番初め(Option Explicitの次の行あたり)に書いておくことで、そのモジュール内で各関数を使うことができるようになります。
Declare PtrSafe Function SetWindowLongPtr Lib “user32” Alias “SetWindowLongPtrA” _
(ByVal hWnd As LongPtr, ByVal nIndex As Long, ByVal dwNewLong As LongPtr) As LongPtr
Declare Function SetWindowLongptr Lib “user32” Alias “SetWindowLongA” _
(ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
上記のどちらを書けばいいかわからない場合は以下のコードをコピペして、モジュールの最上部に書いておきましょう。この構文を書いておくことで自動的に使うことのできる方の構文が使用されます。
VBE上では使えない方の構文が赤色で表示される場合がありますが、実行に影響はありません。
1 2 3 4 5 |
#If VBA7 Then Declare PtrSafe Function SetWindowLongPtr Lib "user32" Alias "SetWindowLongPtrA" (ByVal hWnd As LongPtr, ByVal nIndex As Long, ByVal dwNewLong As LongPtr) As LongPtr #Else Declare Function SetWindowLongPtr Lib "user32" Alias "SetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long #End If |
各関数の宣言文は「Private/Public」を付けて各関数の有効範囲を指定することもできます。
・Public Declare PtrSafe Function~ :モジュール外で呼び出し有効
構文
SetWindowLongPtr関数の構文は下記のように書きます。
lRet = SetWindowLongPtr(hWnd, nIndex, dwNewLong)
引数
hWnd (64bit:LongPtr型 / 32bit:Long型)
ウィンドウの情報をセットする対象のウィンドウへのハンドルを入力します。
ウィンドウハンドルを取得するための関数としてFindWindow関数やFindWindowEx関数、GetActiveWindow関数など様々なものがあります。環境によって引数の型が変わるので注意が必要です。
nIndex (Long型)
セットしたい情報のインデックスの定数値を入力します。
定数値はいくつか存在しますが、代表的なものを抜粋すると下表のような値があります。
値 | 意味 |
GWL_STYLE = -16 | ウィンドウスタイルを取得する |
GWL_EXSTYLE = -20 | 拡張ウィンドウスタイルを取得する |
GWLP_HWNDPARENT = -8 | 親ウィンドウのハンドルがある場合はそのハンドルを取得する |
上記以外の定数値はSetWindowLongPtr関数(パラメータ)ページを参照下さい
dwNewLong (64bit:LongPtr型 / 32bit:Long型)
セットする情報を入力します。これは現在の値に上書きされます。
ウィンドウスタイルを設定する場合「WS_CAPTION」等の定数値を入力することでウィンドウスタイルを変更することができます。基本的にはすべてのウィンドウスタイルを1から定義していくのではなくGetWindowLongPtr関数を使って現在のウィンドウスタイルを取得して、それに対して追加もしくは除去したものを再入力するのが一般的な使われ方です。
ウィンドウスタイルの追加および除去の方法は論理演算を使って下記のように定義します。
追加する場合は論理和のOr、除去する場合は論理積のAndと論理否定のNotを使うことで任意のウィンドウスタイルを設定することが可能です。(※WS_xxxxxは追加/除去するウィンドウスタイル定数値)
1 2 3 4 5 6 7 8 9 10 11 |
'現状のウィンドウスタイル取得 hStyle = GetWindowLongPtr(hWnd, GWL_STYLE) 'ウィンドウスタイルに新たなスタイルを追加 (論理和[Or]) hStyle = hStyle Or WS_xxxxx Or WS_xxxxx 'ウィンドウスタイルから既存のスタイルを除去 (論理積[And]/論理否定[Not]) hStyle = hStyle And Not (WS_xxxxx Or WS_xxxxx) '設定したウィンドウスタイルに置き換え lRet = SetWindowLongPtr(hWnd, GWL_STYLE, hStyle) |
上記ではウィンドウスタイルを例としていますが、GWL_STYLEをGWL_EXSTYLE に書き換えれば、同じ考え方で拡張ウィンドウスタイルの追加/除去を行うこと可能です。
戻り値
lRet (64bit:LongPtr型 / 32bit:Long型)
戻り値は本関数で変更される前のウィンドウの情報です。
関数が失敗した場合は「0」が返されます。
ウィンドウハンドルと同様に環境によって戻り値の型が変わるので注意が必要です。
サンプルコード
以下はSetWindowLongPtr関数とFindWindow関数、GetWindowLongPtr関数を使って、UserFormに最大化ボタンと最小化ボタンを付与するサンプルコードです。UserFormを1つ作成し下記コードをコピーペーストしてUserFormを表示させることで、フォームのInitializeイベントが走り表示されるUserFormに最大化ボタンと最小化ボタンを付与することができます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
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 Const GWL_STYLE As Long = -16 'ウィンドウスタイル Const WS_MAXIMIZEBOX As Long = &H10000 '最大化ボタン Const WS_MINIMIZEBOX As Long = &H20000 '最小化ボタン Private Sub UserForm_Initialize() Dim hWnd As LongPtr Dim hStyle As LongPtr '自身(userForm)のウィンドウハンドルを取得 hWnd = FindWindow(vbNullString, Me.Caption) '現状のウィンドウスタイルを取得 hStyle = GetWindowLongPtr(hWnd, GWL_STYLE) '現状のウィンドウスタイルに最大化/最小化ボタンを追加 Call SetWindowLongPtr(hWnd, GWL_STYLE, hStyle Or WS_MAXIMIZEBOX Or WS_MINIMIZEBOX) End Sub |
VBA×WindowsAPIまとめページ
その他のWindowsAPI関数は下記ページにまとまっているので合わせて参照下さい。
参考
Microsoft公式:SetWindowLongPtrA 関数 (winuser.h) – Win32 apps