iMacでプログラミング

Microsoft Officeの旧バージョンで作成されたVBAマクロ(Excel、Access)を最新バージョンのOfficeや最新OSで動かそうと思っても、そのままでは動かないというケースはとても多いです。

VBAマクロが動かなくなる理由は様々なのですが、その中でも

VBAマクロ内で使用されているDLL(Win32API)が新PCで動かずにエラーが発生する

というのは、よくあるパターンの1つです。

DLLが原因でVBAマクロが動かないというのは、主に次のケースで発生します。

今まで動いていたマクロが動かなくなるケース

  • PCの入れ替えに伴いWindowsのバージョンを変えた(Windows7→Windows10)ら、今まで使えていたマクロが動かなくなった
  • Accessをバージョンアップしたら動かなくなった
  • 32bit版のAccess/Excelから64bit版のAccess/Excelに変えたら動かなくなった
  • AccessからAccess Runtimeに変えたら動かなくなった

例として4つほど上げましたが、今まで動いていたVBAマクロが動かなく場合、大抵はこれらのどれかに当てはまることが多いです。また、場合によっては複数に当てはまっているケースもあり得ます。

いっそのこと過去に作られたVBAマクロは使わないようにしたいところですが、中々そういうわけにもいかないことも多いです。VBAマクロが使えないことで場合によっては業務が止まってしまう可能性もあり、どうにか継続利用できるようにしたいというのは出てきて当然の声だと思います。

動かなくなったVBAマクロを動かせるようにするには、次の状況がそろっている必要があります。

VBAマクロを修正するには
  1. VBAマクロを作った人に修正をお願いする

または

  1. PCにMicrosoft Officeがインストールされている(Runtimeではなく)
  2. VBAの知識がある(デバッグできる)

VBAマクロを作った人がいるならばその人にお願いすれば修正してくれると思いますが、いない場合は自力で解決するか誰かにお願いするかが必要です。自力で解決する場合はVBAの知識が無いとまず修正することはできません。

今回の記事ではVBAの知識がある方に向けて、VBA内で使用しているDLL(Win32API)を64ビット環境で動くように修正対応する方法をご紹介します。

色々なサイトで対応方法は載っていますが、個人的にわかりづらい部分が多かったので、わかりやすいように流れを整理してみました。

VBAを使っているような場合で特にWin7からWin10へのPCの入れ替えを行ったら動かなくなったという方は参考になるかと思います。

DLLが原因でVBAマクロが動かない理由

DLLが原因でVBAマクロが動かなくなる最大の理由は、PCにインストールされているOfficeのバージョンです。ここで指しているバージョンというのは、Access 2010/2013/2016/2019のようなバージョンではなく、32bit版なのか64bit版なのか、ということです。

この理由により、VBAマクロが動かないというのはほぼ間違いなく、次のような環境になっていると想定されます。

想定される環境
  1. VBAマクロは32bit版で作られているファイルである
  2. 64bit版のOfficeがインストールされているPCで動かそうと思ったら、エラーが出て動かない!

元々Windowsは32bit版のみで、それに伴いOfficeも32bit版しかありませんでした。

それが、PCに搭載されるメモリが2GBを超え始めたころから性能を最大限利用するために64bit版が出始めて、Officeも32bit版と64bit版の2種類存在するようになりました。(たぶん・・)

Officeの64bit版が出始めたころは、32bit版から64bit版に変えたら色々と問題が出たようで、Microsoftとしても32bit版が推奨していました(確か・・)

で、なんやかんやあって、記事投稿時点(2020年6月時点)ではOfficeのバージョンは特に気にされなくなって、64bit版が多く使われるようになっていると思います(たぶん・・・)。

参考:64 ビット版または 32 ビット版の Office を選択する

ということで、

  1. 32bit版で作成したマクロを32bit環境で利用していた(例えばWindows7 & Office2010 32ビット版)
  2. パソコンが古くなったのでWindows10への買い替えついでにOfficeも最新バージョンにした(この時に特に気にせず64ビット版のオフィスを購入)
  3. Windows10 & Office 64bit環境でVBAマクロを動かしたところ、動かなくなった

というのが、今まで動いていたマクロが動かなくなった状況として多いのではないかと思います。

動かなくなったという方は、まず動かないPCにインストールされているOfficeが32ビットなのか64ビットなのかを確認してみましょう。

DLLを64bit環境でも動くようにするための手順

VBA内で使用されているDLLはWin32APIなので、32ビット用のAPIです。

そのため、これを64ビット環境でも動くように修正をする必要がありますので、次の手順で該当箇所を修正してみましょう。

VBAソース内を「.dll」で検索して修正箇所をブックマーク

まず、ファイルを開きます。

Accessファイル起動時の補足

Accessファイルの場合、起動時にマクロが動いてしまってエラーメッセージが表示され強制終了してしまうようなケースがあります。このような時は、Shiftキーを押しながらAccessファイルを開くとマクロが実行されずにAccessファイルを開くことができます。

次に、Visual Basic Editorを開き、VBAのソースをどれでもいいので表示します。

Visual Basic Editor

この状態でctrl+fをクリックして検索ボックスを表示し、dllと入力、対象を「カレント プロジェクト(C)」にチェックして、次を検索ボタンをクリックします。

VBAソースの検索ボックス

該当する部分が表示されますので、この状態でツールバーの青い旗をクリックしてブックマークします。

DLLの検索&ブックマーク前

カーソルがある行にブックマークが設定されます。ブックマーク後はこのように目印が表示されるようになります。

VBAのDLL部分のブックマーク後

これをVBAソース内のすべての該当箇所に対して行います。

  1. dllで検索する
  2. ヒットした行をブックマークする
  3. 次を検索する
  4. ヒットした行をブックマークする・・・

これで、修正すべき箇所に対して全てブックマークすることができました。

ブックマークの補足1

Visual Basic Editorにブックマーク用のツールバーが表示されていない場合、

メニューの「表示」→「ツールバー」→「編集」

にチェックを入れることで表示されるようになります。

合わせて「標準」にもチェックを入れておくとよいでしょう。

VBA編集バーの表示方法

ブックマークの補足2

ブックマークをすることで、ブックマーク移動ボタンから次のブックマークに遷移することができるようになります。

ブックマークの移動ボタン

ブックマークをすることで都度検索の手間が省けますので、使ってみましょう。

DLLの定義部分のソースを修正

次に、DLLの定義部分のソースを修正します。

修正時のポイントは次の3つです。

DLL修正時のポイント

  1. 関数の宣言に「PtrSafe」を付ける
  2. 64bit版での動作用に条件分岐して定義する(必要な場合)
  3. Long型で参照型パラメータとなっている部分をLongstrに変更する

関数の宣言に「PtrSafe」を付ける

64bit版で動作させるようにする場合、DLL呼び出し用の関数にPtrSafeを付ける必要があります。64bit版で動作させるためにこれは必須の設定となるため、必ず設定します。

Private Declare Function SHGetPathFromIDList Lib "shell32.dll" Alias "SHGetPathFromIDListA" _
(ByVal lxDigital As Long, _
ByVal lxFolderPath As String) As LongPtr

Private Declare PtrSafe Function SHGetPathFromIDList Lib "shell32.dll" Alias "SHGetPathFromIDListA" _
    (ByVal lxDigital As LongPtr, _
     ByVal lxFolderPath As String) As LongPtr

64bit版での動作用に条件分岐して定義する(必要な場合)

マクロを利用するPC環境として32bit版と64bit版が混在するような場合、関数の定義をそれぞれで動かすために条件分岐を行います。

条件分岐は次のように、IFの前に#を追加したコードを書きます。

'API:フォルダのパスを取得する
Private Declare Function SHGetPathFromIDList Lib "shell32.dll" Alias "SHGetPathFromIDListA" _
    (ByVal lxDigital As Long, _
     ByVal lxFolderPath As String) As LongPtr

#If VBA7 Then    
    'API:フォルダのパスを取得する
    Private Declare PtrSafe Function SHGetPathFromIDList Lib "shell32.dll" Alias "SHGetPathFromIDListA" _
        (ByVal lxDigital As LongPtr, _
         ByVal lxFolderPath As String) As LongPtr
         
#Else
    'API:フォルダのパスを取得する
    Private Declare Function SHGetPathFromIDList Lib "shell32.dll" Alias "SHGetPathFromIDListA" _
        (ByVal lxDigital As Long, _
         ByVal lxFolderPath As String) As LongPtr
 
#End If

If VBA7 Then の中に64bit版用の宣言を書き、#Elseの中に32bit版用の宣言を書きます。

厳密にはVBA7での判定だけではなくWin64での条件分岐も必要なようですが、VBA7だけでも動くのでここではWin64での判定は行っていません。

Long型で参照型パラメータとなっている部分をLongstrに変更する

関数でLong型を使用している場合、Longstrに変更します。

注意点としては、参照型の部分のみLongstrに変えるということです。Long型の部分を全てLongstrに変えるということではありません

また、パラメータの他に、関数の戻り値関数のパラメータで使用している構造体もあわせて変更する必要があるので、忘れずに変換するようにしましょう。

とはいえ、使いたい関数がLong型を使っている場合に、どの部分がLongの参照型でLongstrに変える必要があるのかを見つけるのは中々めんどくさいです。

そんな方のために、以下のサイトにWin32API_PtrSafe.TXTがあるのを見つけました。

このテキスト内を関数名で検索し、その関数部分をコピペすれば基本的には64bit環境で使えるようになりますので、参考にしてみて下さい。(構造体の宣言も記載されているので、合わせてコピペしましょう)

参考ページへ

DLLの関数を使用している部分のソースを修正

基本的には関数の宣言部分のみ変更すれば64bit版環境でもVBAが動くようになりますが、中にはそれだけでは動かないケースがあります。

その最たる例がGetSaveFileNameを利用してダイアログ表示する場合です。

GetSaveFileNameの場合、この関数を利用して構造体のサイズをlStructSizeに設定しますが、64bit環境ではLenBを使用する必要があります。32bit環境ではLenで動きますが、64bit環境ではLenでは動かない(エラーが出ない代わりにダイアログも出ない)という状況になります。

   Dim OFN As OPENFILENAME                     'OPENFILENAME構造体
   Dim Ret As Long                             '戻り値

   With OFN                                 '構造体の設定
     .flags = OFN_PATHMUSTEXIST Or _
              OFN_FILEMUSTEXIST Or _
              OFN_HIDEREADONLY Or _
              OFN_OVERWRITEPROMPT
             'Or OFN_SHOWHELP
     .hInstance = 0                          'インスタンスハンドルを設定
     .hwndOwner = nHandle                    'ウインドウハンドルを設定
     .lpstrTitle = "ファイルを保存する"       'コモンダイアログのタイトルを設定
     .lpstrFilter = nFilter                  'フィルターを設定
#If VBA7 Then    'VBA7(64bit)時
     .lStructSize = LenB(OFN)                 '構造体のサイズを設定
#Else
     .lStructSize = Len(OFN)                 '構造体のサイズを設定
#End If
     .nMaxFile = 250                         'ファイル名のバッファサイズを設定
     .lpstrFileTitle = String(250, Chr(0))   'フルパス用のバッファを確保
     .nMaxFileTitle = 250                    'フルパス用のバッファサイズを設定
     .lpstrFile = String(250, Chr(0))        'ファイル名のバッファを確保
    '.lpstrInitialDir = CurDir               'デフォルトのディレクトリを設定
   End With
    
  Ret = GetSaveFileName(OFN)

    If Ret = 0 Then
         SaveDlg = vbNullString
    Else
         SaveDlg = Left$(OFN.lpstrFile, InStr(OFN.lpstrFile, Chr$(0)) - 1)       'パスを取得
    End If

まとめ

VBA DLL(Win32API)を64ビット環境で動くように修正対応する方法についてご紹介しました。

ちょっと躓くポイントを記載しましたので、参考になれば幸いです。


新型コロナ対策に

マスク

マスク用取り換えシート

手洗い用ハンドソープ

Twitterでフォローしよう

おすすめの記事