えくせるちゅんちゅん

ことりがエクセルをちゅんちゅんするブログ

VBAでWin32APIの64bit対応自動変換プログラムを作ってみた

愛用マクロを64bit版Excelに早急に対応させる必要が出てきたので、ソースコード上のWin32APIのDeclare文を64bit対応に自動変換プログラムを作ってみたので紹介する。

なお、Declare文だけの変更では完全に64bit対応とはならないので、実際に使う人はちゃんと勉強してから使うようにしましょう。


はじめに

つい先日(2017-2018年頃)まで、Microsoftは「32bit版 Excelを推奨」としていた。

実際に推奨設定でインストールした場合、32bit版が入ったと認識している。

ところがココ最近は推奨設定でインストールすると「64bit版 Excel」がインストールされるようになってしまった。


64bit版Excelになると何が困るかというと、VBAでWin32APIを使用している場合にDeclare文コンパイルエラーが起こるのである。

f:id:Kotori-ChunChun:20191021001651p:plain

---------------------------
Microsoft Visual Basic for Applications
---------------------------
コンパイル エラー:

このプロジェクトのコードは、64 ビット システムで使用するために更新する必要があります。Declare ステートメントの確認および更新を行い、次に Declare ステートメントに PtrSafe 属性を設定してください。
---------------------------
OK   ヘルプ   
---------------------------

解消方法については既にたくさんの情報が公開されているため割愛するが、既存の方法では一つ一つ書き換えていくのがとにかく「めんどくさい」のである。

特に「Office2007対応」が求められている場合は、宣言文が入れ子になりさらにめんどくさい。


というわけで、ソースコードを自動的に変換するプログラムを思いついたので即興で書いてみた。(開発時間4時間くらいか?=バグ多し?)


サンプル

早速だが、今回用意した関数を使うと、ソースコード(文字列)は以下のように変換される。


変換前1

Private Declare Function SetCursorPos Lib "user32" (ByVal x As Long, ByVal y As Long) As Long

変換後1

#If VBA7 Then
    Private Declare PtrSafe Function SetCursorPos Lib "user32" Alias "SetCursorPos" ( _
                                            ByVal x As Long, _
                                            ByVal y As Long _
                                            ) As Long
#Else
    Private Declare Function SetCursorPos Lib "user32" ( _
                                            ByVal x As Long, _
                                            ByVal y As Long _
                                            ) As Long
#End If


変換前2

Declare Function WindowFromPoint Lib "user32" Alias "WindowFromPoint" (ByVal xPoint As Long, ByVal yPoint As Long) As LongPtr

変換後2

#If VBA7 Then
    #If Win64 Then
        Declare PtrSafe Function WindowFromPoint Lib "user32" Alias "WindowFromPoint" ( _
                                            ByVal Point As LongLong _
                                            ) As LongPtr
    #Else
        Declare PtrSafe Function WindowFromPoint Lib "user32" Alias "WindowFromPoint" ( _
                                            ByVal xPoint As Long, _
                                            ByVal yPoint As Long _
                                            ) As LongPtr
    #End If
#Else
    Declare Function WindowFromPoint Lib "user32" Alias "WindowFromPoint" ( _
                                            ByVal xPoint As Long, _
                                            ByVal yPoint As Long _
                                            ) As Long
#End If

※Declareと関数名を元にtxtを探索しているので、どのような宣言方法になっていても変換できる。

VBA7Win64スイッチを判定しているので、変換後のソースに変換を掛けても大丈夫。


自動変換関数

まずはソースコード(テキストファイルデータ)を自動的に変換するための関数を作ってみた。


事前準備と使い方

  • 64bit対応に際してはMicrosoftのサイトを良く読むこと

  • Win32API_PtrSafe.txt を入手して、マクロを記述したブックと同じ場所に保存すること

  • ソースコードConst TESTFILE = "Win32API変換テスト.bas"のように用意しておくこと
  • テスト実行はTESTFILEのファイルを用意してSampleを実行
  • 基本的にはソースコードの文字列をConvertVBAcode関数で変換するだけでOK
  • パラメータのインデント幅は定数P_INDENT_LEVELで変えられる。
  • パラメータの自動改行は関数InsertDeclareIndentで行っているので、これを消せばOK
  • ちなみに、コメントアウトされていても変換する。
  • ついでに、無意味な改行の繰り返しは自動的に除去する。
  • Private / Public / 未指定は保持される。


ソースコード

標準モジュールを作成してそこにコピペすればOK


使用例

関数だけでは面白みがないので、実際に活用するフォームを二種類作ってみた。

左側のテキストボックスにDeclare文をコピペすれば、瞬時に右側に変換プログラムが表示される。

f:id:Kotori-ChunChun:20191021015516g:plain


左側のテキストボックスに関数名を入れただけで、瞬時に右側にプログラムが生成される。

f:id:Kotori-ChunChun:20191021203335g:plain

ソースコード

UserForm1を作成して貼り付けるだけでOK。

コントロール等の設置は不要。


参考

ツール

ちなみに、Declareの宣言文の作成であれば、こんなツールもある。

https://www.rondebruin.nl/win/dennis/windowsapiviewer.htm

f:id:Kotori-ChunChun:20191021021628g:plain

  • ディレクティブで分岐できない(?)

  • 1件づつ関数をポチポチしないといけない

  • Win32API_PtrSafe.txtよりは網羅されている印象

という感じです。


関連ツイート


まとめ

とりあえず大量のAPIの置き換えはこれで楽に対処できそうだ。

しかし動かない部分が沢山あるはずなので、動作テストには時間がかかりそうである。

よほど巨大なデータを扱わない限り64bit版Excelを使うメリットはないので、社内のPCは32bit版をインストールするようにしたほうが幸せになれると思う。

またExcel2007は流石に古すぎるので完全に破棄しましょう。Office365 / Excel 2019最高やで!

以上


何か御座いましたらコメント欄、またはTwitterからどうぞ♪

それではまた来週♪ ちゅんちゅん(・8・)

プライバシーポリシー