インストールされているエクセルのビット数を取得

Excel VBA でプログラミングを行っている人であれば知っていると思いますが、32bit 版と64bit 版のエクセルではコードの記述が異なることがあります。

例えば、データ型である LongLong 型は 64bit 版のエクセルでしかコンパイルできません。こういう場合、変数が Long 型の範囲を超えることがないのであれば無理せず Long 型を使うか、あるいはシステム依存型の LongPtr 型を使うことで不具合を回避することができます。

このため一般的には大きな問題になることは少ないと思いますが、面倒なのは外部ファイル内で実装されているプロシージャへ Declare ステートメントで参照宣言する場合です。この場合、条件付きコンパイル定数 Win64 を使用して、例えば以下のように判断することにより実行できます。

32bit 版であれば問題なかったのですが、しかしながらこのコードを 64bit 版のエクセルに記述すると文法間違いを示す赤文字になり、起動時に「間違ってるよ!」というメッセージが表示されます。

不具合が起きないようなコードについてさらに調査してもいいのですが、もう面倒なので 64bit 版と 32bit 版のエクセルファイルを2つ用意し、それぞれPC環境に合わせて使用してもらうことにしました。


ただし、そうなると問題なのが外部プログラムからエクセルを起動する場合です。当社では VB.Net で作成したシステムから VBA プログラムを実行するケースも多いため、「インストールされているエクセルが 32bit か 64bit か」を判断して適切な処理を行う必要があります。

エクセルのビット数を取得するコードについては、C# や Python についてはネット上でいくつか見つけることができます。しかしながら VB.Net については情報がないようなので、以下に一例を示しておきます。

流れとしては「OS が 32bit かどうか」「OS が 64bit の場合は WOW64 が使用されているか」を元に判断しています。

Public Shared Function Get_ExcelBitNo() As Integer

    '--------------------------------------------------------------
    '   インストールされている Excel のビット数を取得する
    '
    '     Get_ExcelBitNo=2 : 64bit
    '                   =1 : 32bit
    '                   =0 : 判定不能(インストールされていない)
    '--------------------------------------------------------------

    Dim result As Integer, app = Nothing
    Dim bWow64 As Boolean

    Try
        Dim ExcelType = Type.GetTypeFromProgID("Excel.Application")

        If ExcelType Is Nothing Then
            Return 0
        End If

        app = Activator.CreateInstance(ExcelType)
        Dim procs = Process.GetProcessesByName("excel")

        If procs.Length = 0 Then
            Return 0
        End If

        '64bit OS ではない場合は無条件で 32bit
        If Not Environment.Is64BitOperatingSystem Then
            Return 1
        End If

        'プロセスの実行に WOW64 が使用されているかどうか確認する(使用されている場合は 32bit)
        If IsWow64Process(procs(0).Handle, bWow64) = 0 Then
            Return 0
        End If

        If bWow64 = True Then
            result = 1
        Else
            result = 2
        End If
    Catch
        Return 0
    Finally
        If app IsNot Nothing Then
            app.Quit()
            Marshal.ReleaseComObject(app)
            GC.Collect()
            GC.WaitForPendingFinalizers()
            GC.Collect()
        End If
    End Try

    Return result

End Function

需要があるかどうかわかりませんが、何かの参考にしてください。