条件付きコンパイルについて

馴染みがないとか、不要だと思っているかも知れませんが....
VBA基本」の方で扱うことかも知れません。   「条件付きコンパイル」のことを知っていても使う必要性を感じないとか、使ったことがないと言う方も多いと思います。
私も VisualBasic(.NET) の方では接続先データベースをテスト/本番で切り替えるなどの必要があって使いますが、 ExcelVBAでは事前にビルドして実行モジュールが生成されるわけではないのでほとんど利用していませんでした。
ですが、利用される Office のバージョンが混在していく中で「テスト/本番の切替え」などとは異なる要件で 「条件付きコンパイル」の必要性が改めて確認できました。



「条件付きコンパイル」とは何でしょう?
コラムに説明している「条件付きコンパイルの別の必要性」の話は後半で説明しています。
最初は「条件付きコンパイル」を知らない方向けの説明から始めることにします。まずはサンプルコードを見て下さい。

'***************************************************************************************************
'   条件付きコンパイルのテスト①                                    Module1(Module)
'
'   作成者:井上治  URL:https://www.ne.jp/asahi/excel/inoue/ [Excelでお仕事!]
'***************************************************************************************************
'変更日付 Rev  変更履歴内容------------------------------------------------------------------------>
'19/10/22(1.00)新規作成
'20/03/03(1.10)記述標準化準拠、他
'***************************************************************************************************
Option Explicit
'===================================================================================================
' 下記の2行の内のどちらかをコメントにして下さい!
'#Const cnsTest = 0      ' ←本番
#Const cnsTest = 1      ' ←テスト

'***************************************************************************************************
'   ■■■ ワークシート側からの呼び出し処理 ■■■
'***************************************************************************************************
'* 処理名 :TEST1
'* 機能  :条件付きコンパイルのテスト①
'---------------------------------------------------------------------------------------------------
'* 返り値 :(なし)
'* 引数  :(なし)
'---------------------------------------------------------------------------------------------------
'* 作成日 :2019年10月22日
'* 作成者 :井上 治
'* 更新日 :2020年03月03日
'* 更新者 :井上 治
'* 機能説明:
'* 注意事項:
'***************************************************************************************************
Sub TEST1()
    '-----------------------------------------------------------------------------------------------
    Dim strMSG As String                                            ' メッセージWORK
#If cnsTest = 1 Then
    strMSG = "これは「テスト」です!"
#Else
    strMSG = "これは「本番」です!"
#End If
    MsgBox strMSG
End Sub

'----------------------------------------<< End of Source >>----------------------------------------
これは、「テスト/本番の切替え」を行なう例です。

これだけ見ると、必要性が判りません。例えば、

'***************************************************************************************************
'   条件付きコンパイルを使用しない場合                              Module0(Module)
'
'   作成者:井上治  URL:https://www.ne.jp/asahi/excel/inoue/ [Excelでお仕事!]
'***************************************************************************************************
'変更日付 Rev  変更履歴内容------------------------------------------------------------------------>
'19/10/22(1.00)新規作成
'20/03/03(1.10)記述標準化準拠、他
'***************************************************************************************************
Option Explicit
'===================================================================================================
' 下記の2行の内のどちらかをコメントにして下さい!
'Const cnsTest = 0       ' ←本番
Const cnsTest = 1       ' ←テスト

'***************************************************************************************************
'   ■■■ ワークシート側からの呼び出し処理 ■■■
'***************************************************************************************************
'* 処理名 :TEST0
'* 機能  :条件付きコンパイルを使用しない場合
'---------------------------------------------------------------------------------------------------
'* 返り値 :(なし)
'* 引数  :(なし)
'---------------------------------------------------------------------------------------------------
'* 作成日 :2019年10月22日
'* 作成者 :井上 治
'* 更新日 :2020年03月03日
'* 更新者 :井上 治
'* 機能説明:
'* 注意事項:
'***************************************************************************************************
Sub TEST0()
    '-----------------------------------------------------------------------------------------------
    Dim strMSG As String                                            ' メッセージWORK
    ' テスト判定
    If cnsTest = 1 Then
        strMSG = "これは「テスト」です!"
    Else
        strMSG = "これは「本番」です!"
    End If
    MsgBox strMSG
End Sub

'----------------------------------------<< End of Source >>----------------------------------------
このように記述すれば済むことですから。

しかし、それは違います。
ひとつのスイッチで済むなら必要ないかも知れませんが、「テスト/本番の切替え」を考えただけでも「画面のタイトル」「接続先データベース」「デバッグデータの出力有無と出力先」「不正実行のログ出力有無」など、 切り分けなければならない項目は多岐にわたるはずです。

「条件付きコンパイル」は記述にモジュールを越えられないデメリットはありますが、プロシージャの概念がないので、

'***************************************************************************************************
'   条件付きコンパイルのテスト②                                    Module2(Module)
'
'   作成者:井上治  URL:https://www.ne.jp/asahi/excel/inoue/ [Excelでお仕事!]
'***************************************************************************************************
'変更日付 Rev  変更履歴内容------------------------------------------------------------------------>
'19/10/22(1.00)新規作成
'20/03/03(1.10)記述標準化準拠、他
'***************************************************************************************************
Option Explicit
'===================================================================================================
' 下記の2行の内のどちらかをコメントにして下さい!
'#Const cnsTest = 0      ' ←本番
#Const cnsTest = 1      ' ←テスト
' システム定数
#If cnsTest = 1 Then
Public Const g_cnsSystemTitle As String = "テストシステム"
Public Const g_cnsSystemDatabase As String = "C:\DB\TEST_DB.mdb"
Public Const g_cnsSystemUrl As String = "http://localhost/TEST/"
#Else
Public Const g_cnsSystemTitle As String = "本番システム"
Public Const g_cnsSystemDatabase As String = "\\HONBAN_SV\DB\HONBAN_DB.mdb"
Public Const g_cnsSystemUrl As String = "http://HONBAN_SV/"
#End If
このように1つのスイッチだけでシステムで使用する定数をまとめて入れ替えるようなこともできるのです。
「条件付きコンパイル」で使用しているスイッチ「cnsTest」はモジュールを越えられませんが、 このサンプルの各定数は Publicスコープなので他モジュールから参照される分も含めて入れ替わります。
全体の初期処理で入れ替えれば良いという考えからもあるでしょうが、実質的にそれは「定数」ではなくなるわけですし、 場合によってはこの入れ替えに関する動作検証を要求されてしまいます。

実行環境による動作の切り分けへの利用
「条件付きコンパイル」というのはビルドする段階での動作を切り分けるためのもので、VisualBasic(.NET)であれば配布する実行モジュールはこれらの「条件」はすでに決定した状態で配布されるものです。
ですが、VBAは逐次コンパイルであるがために、実行時環境(例えばWindows環境の違いやOfficeのバージョン)による動作の切り分けに「条件付きコンパイル」が利用できるという利点があります。

'***************************************************************************************************
'   条件付きコンパイルのテスト③                                    Module3(Module)
'
'   作成者:井上治  URL:https://www.ne.jp/asahi/excel/inoue/ [Excelでお仕事!]
'***************************************************************************************************
'変更日付 Rev  変更履歴内容------------------------------------------------------------------------>
'19/10/22(1.00)新規作成
'20/03/03(1.10)記述標準化準拠、他
'***************************************************************************************************
'*****************************************************************************************
'   条件付きコンパイルのテスト③ システムが持つ条件付きコンパイル定数の利用
'
'   作成者:井上治  URL:https://www.ne.jp/asahi/excel/inoue/ [Excelでお仕事!]
'*****************************************************************************************
Option Explicit
'===================================================================================================
Private Const g_cnsTitle As String = "システムが持つ条件付きコンパイル定数"

'***************************************************************************************************
'   ■■■ ワークシート側からの呼び出し処理 ■■■
'***************************************************************************************************
'* 処理名 :TEST3
'* 機能  :条件付きコンパイルのテスト③  本ワークブックを別名で保存します
'---------------------------------------------------------------------------------------------------
'* 返り値 :(なし)
'* 引数  :(なし)
'---------------------------------------------------------------------------------------------------
'* 作成日 :2019年10月22日
'* 作成者 :井上 治
'* 更新日 :2020年03月03日
'* 更新者 :井上 治
'* 機能説明:システムが持つ条件付きコンパイル定数の利用
'* 注意事項:
'***************************************************************************************************
Sub TEST3()
    '-----------------------------------------------------------------------------------------------
#If VBA7 And Win64 Then
    ' 64ビット版Excelのご利用はお断わりしています(例ですが....)
    MsgBox "本システムは64ビット版Excelではご利用いただけません。", , g_cnsTitle
    Exit Sub
#End If
    '-----------------------------------------------------------------------------------------------
    Const cnsRootPath = "C:\"      ' ルートフォルダ
    Const cnsFixRootPath = 1       ' ルートフォルダ以外を選択不可にする時は1に
                                   ' キャンセル時に初期化する時は3に
    Dim strFileName As String
    ' 「名前を付けて保存」ダイアログよりファイル名の取得(引数は呼び先記述を参照)
    ' ※2つ目以降の引数は省略が可能です。
    strFileName = modFolderPicker2.SaveDialog(g_cnsTitle, _
                                              True, _
                                              cnsRootPath, _
                                              cnsFixRootPath, _
                                              CurDir, _
                                              "保存")
    ' キャンセルは終了
    If Len(strFileName) = 0 Then Exit Sub
    '-----------------------------------------------------------------------------------------------
    ' 拡張子による保存先のファイル名妥当性チェック
    Const cnsXLS As String = ".XLS"
    Const cnsXLSX As String = ".XLSX"
    Const cnsXLSM As String = ".XLSM"
    Dim lngPos As Long                                              ' 拡張子境界文字位置
    Dim strExtU As String                                           ' 拡張子(大文字)
    lngPos = InStrRev(strFileName, ".")
    strExtU = UCase(Mid(strFileName, lngPos))
    If ((strExtU <> cnsXLS) And (strExtU <> cnsXLSX) And (strExtU <> cnsXLSM)) Then
        MsgBox "このファイル名はExcelワークブック形式ではありません。", , g_cnsTitle
        Exit Sub
    End If
    '-----------------------------------------------------------------------------------------------
    ' 利用Excel(Office)のバージョンによるファイル名妥当性チェック
#If VBA7 Then
    ' Office2010以降
    If strExtU = cnsXLSX Then
        MsgBox "本ワークブックは「マクロ有効ブック」で保存して下さい。", , g_cnsTitle
        Exit Sub
    End If
#Else
    ' Office2007以前(Office2007は2003と同じ扱いになってしまう)
    If strExtU <> cnsXLS Then
        MsgBox "Excel2003以前のバージョンでは指定の形式では保存できません。", , g_cnsTitle
        Exit Sub
    End If
#End If
    '-----------------------------------------------------------------------------------------------
    ' 指定ファイル名で保存する
    ' ※VBA7判定により旧Verで新Verの定数がコンパイルエラーになるのを防ぐ
#If VBA7 Then
    ' 拡張子からの指定形式で保存
    If strExtU = cnsXLS Then
        ThisWorkbook.SaveAs strFileName, xlExcel8
    Else
        ThisWorkbook.SaveAs strFileName, xlOpenXMLWorkbookMacroEnabled
    End If
#Else
    ' XLS形式(固定)で保存
    ThisWorkbook.SaveAs strFileName, xlWorkbookNormal
#End If
End Sub

'----------------------------------------<< End of Source >>----------------------------------------
このサンプルは自身のワークブックを「名前を付けて保存」のダイアログの指定によるものですが、 システムから提供されている条件付きコンパイル定数を利用してバージョンの違いを利用しようとしているサンプルです。
まず、「#If VBA7 And Win64 Then」はそもそも64ビット版Office以外での動作を回避するための記述であり、 以降の「#If VBA7 Then」はVBAのバージョンを制限するための記述です。
例えば「xlOpenXMLWorkbookMacroEnabled」などはOffice2003以前のバージョンでは記述自体がコンパイルエラーになる対象でしたが、 「#If VBA7 Then」の記述によりOffice2010以降のバージョンだけが対象となるためコンパイルエラーにはならずに動作します。

これらは昔話になりますが、Office2000が登場した時にOffice97以前での動作との切り分けを行なうために「VBA6」という条件付きコンパイル定数があったものの正常進化なので 古くからVBAを使っている方には馴染みの深いことだと思います。

ここまで説明すればお解りだと思いますが「条件付きコンパイル」というのは「Option Explicit」の記述に関係なく、宣言有無にとらわれずに動作してしまうという問題は持っています。 未宣言の変数を参照した場合は「False(Else)」として正常処理されてしまいます。 このことは理解の上で利用するしかありません。

もう一点、「VBA7」という条件付きコンパイル定数はOffice2010以降かどうかを切り分けるためのものですが、 このサンプルの用途からするとOffice2007も含まれていなければならないところが含まれません。
これはOffice2007VBAがバージョン「6.5」であるために起きることですが、 本来の用途とマイクロソフトの対応を考えるとOffice2007は中途半端な扱いになってしまっています。

64ビット版Excelの対応について
Excel環境の64ビット版Excelについて」で概要は説明しています。
いよいよMicrosoft64ビット版Officeをメインに舵を切るようで、 少なくとも従来マクロのAPI記述は変更が必要になります。
「舵を切る」と言ってもデフォルトが64ビット版になるだけで、32ビット版がなくなるのではありませんが、今後は32ビット版に「戻す」のが別の作業になるのかも知れません。


このページは「条件付きコンパイル」の話なのですが、64ビット版Officeを検索すると 必ず「条件付きコンパイル」が出てきます。
これはAPIの記述で見分ける必要があるためですが、ほとんどの場合実際の作業は「Office2010」以上かどうかなので、現段階ではそれより前のバージョンはほぼ使われておらず、実際のところ「条件付きコンパイル」の判断は不要なのかも知れません。
「条件付きコンパイル」が不要だとしてもマクロ記述の変更は発生するので、 この変更については「API関連」の32ビット版、64ビット版での共用利用」をご覧下さい。