VBAに限らず、WindowsAPIでいろいろ(主に他のアプリを操作)しようと思ったら、対象をGet〜で取得したり、対象にSet〜を行うだろう。
アクティブなウインドウを切り替えるためにSetForegroundWindowしたり、アクティブなウインドウを取得するのにGetForegroundWindowしたり。
といった具合に、何かとSetとGetでついになる関数がいくつもある。
これ、そのまんまVBAのプロパティにしてしまったら楽なのでは?
というわけで、例に挙げたForegroundWindowならこんな感じになる。
※以降に載せるコードについては全てWindowsAPIの宣言は省略している
Property Get Foreground() As LongPtr Foreground = GetForegroundWindow End Property Property Let Foreground(ByVal hWnd As LongPtr) SetForegroundWindow hWnd End Property
これを使えば、「Foreground = hWnd」で対象のウインドウをフォアグラウンドにしたり、逆に「hWnd = Foreground」でhWndにアクティブなウインドウのハンドルを代入することができる。
いちいちGetForegroundWindowとSetForegroundWindowを使い分けるよりずっと手軽である。
まあ、ForegroundWindowについてはウインドウハンドルを取得するか指定するかくらいなので、わざわざプロパティにするほどのものでもないように思うだろう。
「WM_SETTEXT」と「WM_GETTEXT」なんかだと楽になる。
Property Get WindowText(hWnd As LongPtr) As String Dim sText As String: sText = String(255, Chr(0)) Call SendMessageStr(hWnd, WM_GETTEXT, Len(sText), sText) Do While Right(sText, 1) = Chr(0) sText = Left(sText, Len(sText) - 1) Loop WindowText = sText End Property Property Let WindowText(hWnd As LongPtr, sText As String) Call SendMessageStr(hWnd, WM_SETTEXT, 0, sText) End Property
いちいちSendMessageを呼び出して、ウインドウメッセージとパラメータを指定した関数を呼び出すより楽だ。
Set〜とGet〜でついになる関数があるようなAPIはプロパティに落とし込めば、それ以降のコーディングが楽になるし、何か間違った時はそのプロパティを直せば済む。
少し凝ったところでは、キーの押下状態なんていかがだろうか。
Property Get KeyPress(VK_ As Long) As Boolean If GetAsyncKeyState(VK_) = 0 Then KeyPress = False Else KeyPress = True End If End Property Property Let KeyPress(VK_ As Long, IsPress As Boolean) If IsPress Then Call keybd_event(VK_, 0, 0, 0) Else Call keybd_event(VK_, 0, KEYEVENTF_KEYUP, 0) End If Func.DoesEvents End Property
普通に仮装キーコードを引数として、Trueにすれば押下状態に、Falseで解除できる。
さらにGetで状態も取得できるから、VK_CONTROLを引数にして、Ctrlキーが押されているかどうかの判定もできるから、APIに関係なく、いろいろなところで装飾キーの押下状態によって処理を分岐させるのにも使える。
他にも、ユーザーフォームに擬似的なTopMostプロパティを作るような使い方も考えられるだろうか。
Property Get TopMost(hWnd As LongPtr) As Boolean Dim style As LongPtr style = GetWindowLong(hWnd, GWL_EXSTYLE) If style = (style Or WS_EX_TOPMOST) Then TopMost = True Else TopMost = False End If End Property Property Let TopMost(hWnd As LongPtr, bIsTopMost As Boolean) If bIsTopMost Then SetWindowPos hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE Or SWP_NOSIZE Else SetWindowPos hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE Or SWP_NOSIZE End If End Property
ユーザーフォームのウインドウハンドルは別で関数を作っておけば楽だ。
Function hwndForm(fm As Object) As LongPtr hwndForm = FindWindow("ThunderDFrame", fm.Caption) End Function
別に一体化させてプロパティの引数をObjectにして中でハンドルを取得してもいいけれど、ユーザーフォーム以外のTopMostも操作できるように、ハンドルの取得と状態の設定を分けている。
書こうと思えばまだまだあるけれど、大体のイメージを掴めればいくらでも応用できるだろう。
別にAPIに限らず、プロパティは作ってしまえばいろいろと使い回せて便利である。
しかし、VBAを触り始めた頃はなかなかプロパティというものを理解できず、そもそも知る機会もなかったりして、ある程度成熟してから知ったりする。
その時に、今まで作った関数なんかを「プロパティにしておけばよかったー」と後悔したのが私だ。
早い段階でPropertyを使えるようになっておいて損はないだろう。