読者です 読者をやめる 読者になる 読者になる

STDIO

システム開発やフクロウ、節約などの情報をI/Oするためのブログ

「Excel VBA」異なるバージョンの利用者に配布するときの注意点

先日、CSVファイルを読み込んで帳票を印刷するツールを、Excel 2010(64bit版)で作成しました。

ツールの作成は無事に終わりましたが、運用テストで問題が起きました。 ユーザーのExcelが「2007(32bit版)」のため思うように動かず、迷惑をかけてしまいました。

作成したツールは「リボンUI」や「テーブル機能」を使用していましたが、これらの機能はExcel 2007から搭載されています。見た目も2010と似ており、おそらく動くだろうと甘く考えていました。

今回はExcel VBAで作成したツールを、別のバージョンのExcelで動かすためのポイントをまとめました。

事前にユーザーの環境を確認する

Excelの搭載機能はバージョンよって異なります。特に「リボンUI」や「テーブル機能」が搭載された2007以降は、2003以前とは大きな差があります。

開発前にユーザーが使用しているExcelのバージョンを確認し、可能であれば同じ環境で開発することが一番確実な方法です。

ライブラリの参照設定は必要最小限に

Excelファイルの配布前に、未使用の参照設定は外しておきます。

FileSystemObject(ファイル・フォルダ操作)やADO(DB接続)などのライブラリを使用する際に「参照設定」しておくと、入力候補の表示や実行前のエラーチェックが可能なため、効率良く開発できます。

しかし、参照設定を含むファイルを他のPCで開くと、コンパイルエラーになる場合があります。 通常は実行環境に合わせてライブラリのバージョンも置換されますが、上手くいかないこともあるようです。

今回は「Mid」関数のところでコンパイルエラーとなりました。 配布用ファイルでは不要となっていた参照設定をすべて外したところ、この問題は解消しました。

必要なライブラリの参照設定が原因でエラーとなる場合には、参照設定をせずに「CreateObject」関数で実行時にオブジェクトを作成する方法もあります。

Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")

この場合、上で挙げた参照設定によるメリットはなくなり、開発効率は悪くなります。

互換性重視であれば、参照設定をした状態で開発を進め、完成直前に参照設定を解除して「CreateObject」に変更する方法もおすすめです。

Windows API関数は極力使用しない・使う場合はExcelの32bit/64bitを意識する

VBAに存在しない高度な機能を実現する場合に、Windows API関数を使用することがあります。 使用前には「Declare」ステートメントによる宣言が必要ですが、この宣言が厄介で「Excel」が64bit版の場合は記述が異なります。

私は条件付きコンパイルで「Excel」の32bit/64bitを判断し、有効なコードを環境ごとに切り替えるようにしています。

' Excel 64bit用
#If Win64 Then

Public Declare PtrSafe Function SetForegroundWindow Lib "user32" Alias "SetForegroundWindow" ( _
    ByVal Hwnd As LongPtr) As Long

' Excel 32bit用
#Else

Public Declare Function SetForegroundWindow Lib "user32" Alias "SetForegroundWindow" ( _
    ByVal Hwnd As Long) As Long

#End If

「#If Win64 Then」という条件は、Excelが64bit版の場合に成立します。 紛らわしいですが、Windowsが64bit版でも、Excelが32bit版であればこの条件は成立しないため、「#Else」以下のコードが有効になります。

64bit用のAPI宣言では、「PtrSafe」というキーワードが必要です。 また、メモリアドレス範囲の拡張により、ポインタやハンドルを渡す引数・戻り値は「LongPtr」という64bitの型で定義する必要があります。 (通常のLongは32bit、Integerは16bit)

この「ポインタ」や「ハンドル」という基準も厄介で、単純に「Long」をすべて「LongPtr」に変更すれば良いわけではありません。 引数名でもおおよそ判断できますが、Microsoftのドキュメントで確認しておくと確実です。("MSDN " + API関数名 で検索)

現時点では、上記のAPI宣言を行えば32bit/64bit版の両方に対応可能です。 ただし、このコードにも欠点があり、将来的にExcelが128bit版になった際に、おそらく32bit用コードが適用されてしまいます。

Excelの32bit/64bit両環境を対象とするAPI宣言は煩雑であり、将来的に修正が必要な可能性もあるため、API関数の使用は必要最小限に留めることをおすすめします。

特定のバージョン間で発生する問題

Excel 2010で作成、2007で実行する場合

リボンUIの「ActivateTab」は2007では使用できない

リボンUIのタブを切り替える「ActivateTab」は2010で追加された機能のため、2007では実行時エラーが発生します。

オブジェクトは、このプロパティまたはメソッドをサポートしていません。(エラー番号438)

テーブル内の数式に項目名を使用する場合の記述が異なる

テーブル機能(シート内の対象セル範囲を選択して[Ctrl]+[T]で作成)を使用すると、テーブル内の数式に「項目名」を指定できます。

Excel 2010でテーブル内に数式を入力すると次のようになります。 (セル選択時にアドレスではなく項目名が表示される)

=[@数量]*[@単価]

Excel 2007では次のように指定します。(@が使えない)

=[数量]*[単価]

入力済みの数式については、ファイルを開いた際に対応する形式に変換されます。 しかし、VBAでセルの「FormulaLocal」プロパティにExcel 2010の数式(@付き)をセットしてしまうと、2007ではエラーとなります。(「Formula」プロパティでも同様)

@無しの記述は2010でも使えたので、今回はこの方法に変更しました。

まとめ

Excel(特に2007以降)の機能を活用すると、本格的な業務アプリも開発できます。

ですが、機能の活用は上手に行わないと、別のバージョンとの互換性ダウンにつながります。

今回は主にExcel 2010と2007の間で起きた問題を取り上げましたが、今後また新たな問題が見つかった際には、随時追加していければと思います。