はじめに
VBAマクロから特定のファイルを開く際、通常は Shell
関数に直接ファイルパスを渡せば、Windowsが自動的に関連付けられたプログラムで開いてくれます。しかし、「.pdf
ファイルを開くプログラムが何であるか(Acrobat Readerなのか、ブラウザなのか)を事前に知りたい」という、より高度な要求に応える場面があります。
このような「拡張子とプログラムの関連付け情報」を取得するのが、Windows APIの FindExecutable
関数です。この関数を使えば、指定したファイルの拡張子を開くために設定されている、実行ファイルのフルパスを取得できます。
この記事では、FindExecutable
APIを使って、特定の拡張子に関連付けられたプログラムの情報を取得する方法を解説します。
関連付けられたプログラムを取得するVBAサンプルコード
Declare
ステートメントや Const
(定数)は、モジュールの最上部(Sub
などのプロシージャよりも前)に記述する必要があります。
このマクロは、一時的にダミーの .html
ファイルを作成し、その拡張子に関連付けられているプログラム(通常はデフォルトのウェブブラウザ)のパスを取得します。
完成コード
'--- モジュールの最上部にAPI関数と定数を宣言 ---
' 64bit/32bit両対応
#If VBA7 Then
Private Declare PtrSafe Function FindExecutable Lib "shell32.dll" Alias "FindExecutableA" ( _
ByVal lpFile As String, _
ByVal lpDirectory As String, _
ByVal lpResult As String _
) As LongPtr
#Else
Private Declare Function FindExecutable Lib "shell32.dll" Alias "FindExecutableA" ( _
ByVal lpFile As String, _
ByVal lpDirectory As String, _
ByVal lpResult As String _
) As Long
#End If
' パスを格納するためのバッファサイズ
Private Const MAX_PATH As Long = 260
' .html拡張子に関連付けられたプログラムのパスを取得する
Sub GetAssociatedExecutable()
Dim dummyFileName As String
Dim resultBuffer As String
Dim resultCode As LongPtr
Dim executablePath As String
'--- 1. 存在確認のための一時ファイルを作成 ---
dummyFileName = ThisWorkbook.Path & "\_temp.html"
Open dummyFileName For Output As #1: Close #1
'--- 2. 結果を格納するための文字列バッファを準備 ---
resultBuffer = String(MAX_PATH, vbNullChar)
'--- 3. FindExecutable API関数を実行 ---
resultCode = FindExecutable(dummyFileName, vbNullString, resultBuffer)
'--- 4. 後片付け ---
Kill dummyFileName
'--- 5. 結果を判定して表示 ---
' 戻り値が32より大きい場合、成功と見なす
If resultCode > 32 Then
' バッファから実際のパス部分だけを切り出す
executablePath = Left(resultBuffer, InStr(resultBuffer, vbNullChar) - 1)
MsgBox ".html ファイルは、以下のプログラムに関連付けられています:" & vbCrLf & _
executablePath, vbInformation, "関連付け情報"
Else
MsgBox ".html に関連付けられたプログラムが見つかりませんでした。", vbExclamation
End If
End Sub
コードの解説
FindExecutable
API関数
FindExecutable
は、指定したファイルを開くために実行されるプログラムのパスを探し出す関数です。
lpFile
: 調査したいファイルの名前(フルパスまたはファイル名)を渡します。実際にファイルが存在する必要があるため、一時的なダミーファイルを作成しています。lpDirectory
: ファイルのデフォルトディレクトリを指定しますが、lpFile
にフルパスを渡す場合はvbNullString
で問題ありません。lpResult
: 結果(見つかった実行ファイルのパス)を格納するための、あらかじめ領域を確保しておいた文字列変数(バッファ)を渡します。
resultBuffer = String(MAX_PATH, vbNullChar)
FindExecutable
は、結果を第3引数 lpResult
に書き込みます。そのため、VBA側で、結果を書き込むのに十分な長さの「空の箱」を用意しておく必要があります。
String(MAX_PATH, vbNullChar)
:MAX_PATH
(Windowsのパスの最大長である260文字)分の、vbNullChar
(ヌル文字)で満たされた文字列を作成し、バッファとして準備しています。
結果の判定と抽出
If resultCode > 32 Then
:FindExecutable
は、成功した場合に32
より大きい値を返します。これをチェックすることで、処理が成功したかどうかを判定します。Left(resultBuffer, InStr(resultBuffer, vbNullChar) - 1)
: APIから返される文字列は、実際のパスの後にヌル文字が続いています。InStr
で最初のヌル文字の位置を探し、Left
でそれより前の部分だけを切り出すことで、純粋な実行ファイルのパスを取得しています。
まとめ
今回は、Windows APIの FindExecutable
を使って、ファイルの拡張子に関連付けられたプログラムのパスを取得する方法を解説しました。
FindExecutable
APIで、ファイルを開くプログラムを特定できる。- 事前にダミーファイルと、結果を格納する文字列バッファの準備が必要。
- 戻り値が
32
より大きいかどうかで成功を判定する。
このテクニックを使えば、「ユーザーのPCでPDFが開けるか(Adobe Readerやブラウザが関連付けられているか)を確認する」といった、より環境に配慮した、堅牢なマクロを作成することが可能になります。