WindowsAPI関数をクラスモジュールに封印するとメッチャ便利

WindowsAPIの関数をラップするクラスを作ったらメッチャ便利だった

タイトル通り。

そもそもは、

f:id:akashi_keirin:20181228210702j:plain

コチラの『VBA Developer's Handbook』で紹介されていたテクニックで、ちょっとやってみたら便利だったというだけの話。

ちなみに、コチラの書籍は、VBA四天王の一人、id:t-hom さんも

thom.hateblo.jp

紹介しておられる。

WindowsAPIの関数をクラスに封印する

クラスモジュールを挿入して、テキトーな名前をつける。

私は「WindowsAPI」という何のひねりもないそのままやんけなネーミングにしている。

WindowsAPIの関数をラップしたいだけ、すなわちプロパティやフィールドを持つ必要がないので、Attribute VB_PredeclaredIdの値をTrueにしておく。

Attribute VB_PredeclaredId」については、

akashi-keirin.hatenablog.com

コチラをどうぞ。

たとえば

最近、IE操作関係でWindowsAPI関数を使うことが多いので、手始めにGetTickCountSleepをクラスモジュールに封印してみる。

リスト1 クラスモジュール

オブジェクト名は「WindowsAPI」、「Attribute VB_PredeclaredId」の値はTrue

Option Explicit

'(1)WindowsAPI関数の宣言'
Private Declare Function GetTickCount Lib "kernel32" () As Long
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)

'(2)GetTickCount関数呼び出しメソッド'
Public Function callGetTickCount() As Long
  callGetTickCount = GetTickCount
End Function

'(3)Sleep関数呼び出しメソッド'
Public Sub callSleep(ByVal milliSeconds As Long)
  Call Sleep(milliSeconds)
End Sub

'(4)GetTickCountとSleepを組み合わせた待機用メソッド'
Public Sub waitFor(ByVal milliSeconds As Long)
  Dim startTime As Long
  startTime = GetTickCount
  Dim endTime As Long
  Do
    Sleep (1)
    DoEvents
    endTime = GetTickCount
  Loop Until endTime - startTime > milliSeconds
End Sub

それぞれコード中の(1)~(4)に記した通り。

(1)の

Private Declare Function GetTickCount Lib "kernel32" () As Long
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)

はおなじみのアレ。

ただし、いづれPrivate指定にして、直接外から呼び出すことができないようにクラス内に封印している。

そして、(2)、(3)は、GetTickCountSleepを呼び出すためのメソッド。

あと、(4)は、コメント通りGetTickCountSleepを組み合わせて、引数で渡した時間だけ待機するメソッド。

単純にDo~Whileでループさせるだけでなく、ループ中にSleepかましているところがミソ。

こんなふうに複数のWindowsAPIを組み合わせた処理を簡単に利用できるようにすることができる。

使ってみる

次のコードで実行してみる。

スト2 標準モジュール
Public Sub disposableMacro01()
  Dim n As Long
  n = 1
  Do
    Call WindowsAPI.waitFor(1000)    '……(1)'
    Debug.Print "待機 " & n & " 回目"
    Debug.Print "ち~んw"
    n = n + 1
  Loop Until n > 10
  Call WindowsAPI.waitFor(2000)
  Debug.Print "おしまい"
End Sub

上にも書いたように、WindowsAPIクラスは、「Attribute VB_PredeclaredId」の値をTrueにしているので、インスタンス化せずに、(1)のように

Call WindowsAPI.waitFor(1000)

と書けばメソッドの利用ができる。

ここでは、GetTickCountSleepを組み合わせた自作のwaitForメソッドを使っている。

Doループの中でこのメソッドを呼び出すことにより、1000ミリ秒(メソッド内でSleepを引数1で実行しているので、正確には1001ミリ秒+α)ごとにイミディエイト・ウインドウに、文字列を出力し、ループを抜けたところで再度しばらく時間をおいて文字列を出力することになる。

f:id:akashi_keirin:20181228210718g:plain

こんな感じ。

おわりに

めんどくさいWindowsAPI関数の利用が、非常に簡単になると思った。

ちょこっと修正しました

akashi-keirin.hatenablog.com