APIの基本的なこと
VBAでWinAPIを扱う際の基本的なことをまとめておきます。
※書籍『大村あつしのExcelVBA Win74/32APIプログラミング』(秀和システム、2016/8/26)を大変参考にさせていただきました。絶版なのが非常に惜しいです…。
中々まとまった情報がないので、載せておきます。
【APIとは】
1951年頃、プログラマーの間で頻出度の高いサブルーチンや関数を、目的別にまとめて格納するアイデアが生み出される。のちにライブラリと呼ばれる。ライブラリを参照することで開発効率の向上、コード量の圧縮、タイプミス防止等のメリットに繋がる。
ライブラリは一般的にLIB(Static Link Library)とDLL(Dynamic Link Library)の2種類に大別され、とくに後者DLLでは、プログラムの一部(頻出度の高いサブルーチンや関数)を切り離して予めコンパイルし独立したファイルとしておくことで、アプリケーション実行時に必要なファイルを参照するだけで処理が完結するようになった。(ハードディスク・メモリの使用効率が向上)
Windowsでは、C言語で書かれた膨大な関数群を、コンパイルした上でDLLとして外部公開している。
→つまり、VBA等の言語を使ってDLLへアクセスすることで目的のサブルーチンをWindows(OS)に処理させることが可能!
APIとは、ざっくりいうと、外部公開された関数群のこと、
API:Application Programming Interfaceの略語。
Windows(OS)に限らず、TwitterやOneDrive等の色々なアプリケーションにもAPIが用意されており、プログラムの開発用に外部公開された関数は全てAPIと位置付けられる。
オープンアーキテクチャ志向がIT業界の標準志向になったことも相まって、この外部公開されたAPIを使うことでハードウェアやソフトウェアメーカーが自由に互換製品を開発できるようになり、拡張性が高まっている。
通常はAPIと言ったら「WindowsのAPI」を指す。略してWin API。
ただし、例えば「OneDriveがAPIを外部公開しているのでその関数を取り込んで自動的にファイルをダウンロードするマクロを開発した」という場合のAPIは、WindowsのAPIではない。
【Win API】
Windowsを構成する関数群(DLL)にアクセスすることでWin APIが使える。
そしてDLLはC言語で書かれている。
そのため、VBAからWin APIを使う場合、言語間(VBAとC言語)の相違点に注意しなければならない。
データ型、文字コード、ポインタの有無、長整数など…
構造体
VBAでは馴染みの薄いユーザー定義型(構造体)は、C言語では積極的に利用されている。Win API関数の中にはこの構造体を引数に要求するものが少なくない。
Type~End Typeステートメントで予め定義してやることで、Win API関数の呼び出しが可能。
ポインタ
変数のメモリアドレスを指し示す数値をポインタと呼ぶ。
VBAにはポインタの概念がないが、C言語にはこのポインタを使ってメモリ上の変数を直接操作する。Win API関数が受け取った文字列を処理するには、メモリアドレスにある●●(例えば「1000」)というポインタをC言語に渡す必要がある。
ByValキーワードで処理してやることで、C言語はその変数のポインタを受け取れる仕組みになっている。
→Win API関数に文字列引数を渡すときは値渡し(ByVal)を使うこと。
Nullポインタ
Win API関数では、文字列を要求する引数にNullポインタを指定できる。
「Nullポインタを指定する」とは、特定のデータを渡さないということ。
※Win APIが要求するNullポインタと、VBAのNullキーワードは別物。
Nullポインタは、あくまでも「0」で表現される値のこと。
String型の引数で0をWin API関数へ渡したいときは、0&でなく「vbNullString」を使う。
TrueとFalse
C言語のTrueは1、VBAのTrueは-1。
C言語のFalseは0、VBAのFalseも0。
Trueの値が異なるため、Win API関数の戻り値をVBAで扱うときは、Falseの方を使うこと。
「If (戻り値) = True」ではなく「If (戻り値) <> False」とすること。
【VBAからWin APIの呼び出し方法】
モジュールの冒頭部分でDeclareステートメントを使って(モジュールレベルで宣言して)、呼び出すWin API関数の名前と引数の型、戻り値、その関数を含むDLLの名前と場所を明記することで呼び出す。
たとえば
Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal ms As LongPtr)
Sub Sample()
'何らかの処理
Call Sleep (100)
'何らかの処理
End Sub
ならば、
Windows¥¥System32のディレクトリに保存されている「Kernel32.dll」のDLLにこれからアクセスして、DLLの中にあるSleep関数を使わせてもらいますよ。引数としてLongptr型の変数msを渡しますよ。
という具合にモジュールレベルでVBAからWindowsへ宣言してやるイメージ。
VBAから、Win APIのSleep関数に引数「100」を渡して呼び出すと、Windows(OS)側で「100ミリ秒待機する」という処理結果が行われた後に、VBAへ制御が返ってくる。
因みにPtrSafeステートメントは、64Bit環境で必要になるもの。32ビットベースのWin APIライブラリを64Bitマシンで使うときはPtrSafeステートメントが必要になるんだなー位に認識しておけばOK。
【Win APIを使うメリット】
そもそもVBAは、Excel、Word、PowerPoint、AccessなどのOfficeアプリケーション上で動作する言語である以上、Officeアプリケーションの領域を超えた操作には限界がある。
DLLへアクセスしてWinAPIを呼び出すことで、Windowsで出来る様々な操作(PC再起動やディレクトリ編集などのOfficeアプリケーションの領域外の操作)が可能になる。
以上、VBAからWin APIを呼び出す際の基礎知識でした。
正直言って、わざわざVBAからWin APIを呼び出すのは非効率です。直接C言語で呼び出しても良いし、もっと高級な言語を使っても良いです。
しかし問題なのは、我々サラリーマンの職務環境では使える言語がVBA位しかないということ…。
勝手にソフトをインストールできないけど、ExcelやWordなら入っているという人は多いと思います。
そんな人のために、VBAからWin APIを呼び出す際の情報を載せておきます。