配布したマクロが「32bit版Excelでは動くけど64bit版だとエラーになる」「Windowsでは動くのにMacだと動かない」——そんなトラブルに遭遇したことはないでしょうか。VBAには、実行環境に応じてコンパイルするコード自体を切り替えられる条件付きコンパイル(#If…#End If)という仕組みが用意されています。
この記事では、条件付きコンパイルの基本構文と、よく使われる定義済み定数、32bit/64bit対応やWindows/Mac対応の具体例、独自の定数を定義する#Constの使い方まで解説します。
条件付きコンパイルとは
条件付きコンパイルは、見た目は通常のIf...End Ifによく似ていますが、動作するタイミングが全く異なります。
- 通常のIf文:マクロの実行時に条件を判定し、分岐する
- 条件付きコンパイル(#If):マクロのコンパイル時に条件を判定し、条件に合わないコードはそもそもコンパイルされない(存在しないものとして扱われる)
この違いにより、たとえば「32bit環境には存在しないデータ型」を使ったコードを#Ifで分岐させておけば、64bit環境ではそのコードがコンパイル対象にすらならないため、32bit環境でエラーになることを防げます。
基本構文
#If 条件式1 Then
' 条件式1がTrueのときだけコンパイルされる処理
#ElseIf 条件式2 Then
' 条件式2がTrueのときだけコンパイルされる処理
#Else
' どちらの条件にも当てはまらないときの処理
#End If
通常のIf文と混同しないよう、行頭に#を付ける点がポイントです。
よく使う定義済み定数
VBAにはあらかじめ以下のような定数が用意されており、#Ifの条件式として利用できます。
| 定数名 | 内容 |
|---|---|
| VBA7 | VBA 7.0以降(Excel 2010以降)で実行している場合にTrue |
| Win64 | 64bit版Office上で実行している場合にTrue |
| Win32 | 32bit版Office上で実行している場合にTrue |
| Mac | macOS上で実行している場合にTrue |
具体例1:32bit/64bit対応のAPI宣言
Windows APIを呼び出すDeclareステートメントは、32bit環境と64bit環境で書き方が異なります。条件付きコンパイルを使うと、1つのモジュールに両対応のコードをまとめて書けます。
#If VBA7 Then
' Excel 2010以降(32bit/64bit共通でPtrSafeが必要)
Private Declare PtrSafe Function GetTickCount Lib "kernel32" () As Long
#Else
' Excel 2007以前(PtrSafeキーワードが存在しない)
Private Declare Function GetTickCount Lib "kernel32" () As Long
#End If
Sub ShowUptime()
MsgBox "PC起動からの経過ミリ秒: " & GetTickCount
End Sub
Excel 2010以降のVBA7ではPtrSafeキーワードが必須になった一方、Excel 2007以前にはそのキーワード自体が存在せずコンパイルエラーになります。#If VBA7 Thenで分岐しておけば、どちらのバージョンで開いても、その環境に合ったDeclare文だけがコンパイルされるため、「ステートメントが正しくありません」といったコンパイルエラーを防げます。
具体例2:Windows/Macで処理を分岐する
Excelは Windows版・Mac版の両方が存在し、ファイルパスの区切り文字やAPI呼び出しの可否など、環境依存の違いがあります。Mac定数を使うと、OSに応じた処理の切り替えが可能です。
Sub ShowDataFolder()
Dim dataFolder As String
#If Mac Then
dataFolder = Environ("HOME") & "/Documents/"
#Else
dataFolder = Environ("USERPROFILE") & "\Documents\"
#End If
MsgBox "データフォルダ: " & dataFolder
End Sub
Windows APIを使うコード(Declare文など)は基本的にMacでは動作しないため、Mac対応も視野に入れる場合は、API依存の処理を#If Mac Thenで分岐させ、代替処理を用意しておく必要があります。
具体例3:独自の定数を定義する(#Const)
#Constを使うと、自分で条件付きコンパイル用の定数を定義できます。デバッグ用のコードを、本番配布時にはコンパイル対象から外したい場合などに便利です。
' モジュールの先頭で定義(このモジュール内のみ有効)
#Const DEBUG_MODE = True
Sub ProcessData()
#If DEBUG_MODE Then
Debug.Print "デバッグ: 処理を開始します " & Now
#End If
' ここに本来の処理を書く
MsgBox "処理が完了しました"
#If DEBUG_MODE Then
Debug.Print "デバッグ: 処理が完了しました " & Now
#End If
End Sub
DEBUG_MODE = Falseに切り替えて保存すれば、Debug.Print行はコンパイル対象から除外されます。なお、#Constは原則としてそのモジュール内でのみ有効です。複数モジュールで共通の定数を使いたい場合は、VBEのメニューから「ツール」→「(プロジェクト名)のプロパティ」→「条件付きコンパイル引数」でプロジェクト全体に適用される定数を設定できます。
通常のIf文との違い・注意点
- 実行速度に影響しない:条件付きコンパイルはコンパイル時に確定するため、通常のIf文のような実行時の条件判定コストが発生しません
- 存在しない構文・関数を分岐で回避できる:バージョンによって存在しないメソッドや、環境によって使えないDeclare文を安全に切り替えられます
- 条件式には限られた定数しか使えない:
#Ifの条件式には、VBA7・Win64・Mac等の定義済み定数や#Constで定義した定数しか使えません。セルの値やワークシート関数の結果など、実行時にしか分からない値は条件式に使えないため注意してください
まとめ
条件付きコンパイル(#If…#End If)を使うと、32bit/64bit・Windows/Mac・Excelのバージョン差異を、コンパイルの段階で吸収できます。特に社内外へマクロやアドインを配布する際は、実行環境の違いによるエラーを未然に防げる強力な仕組みなので、ぜひ活用してみてください。


コメント