none
64ビット環境でExcel VBAからDLLを呼び出す方法 RRS feed

  • 質問

  • お世話になっております。

    Visual Studio Premium 2012を使用しています。

    Visual C++で作成したDLLファイルをsystem32フォルダーに置き、Excel VBAから呼び出すプログラムを作成しました。

    これまで32ビット版Excelでは問題なく動作していましたが、この度、64ビット版Excelに対応するべく試行錯誤していますが、うまくいきません。

    構成マネージャーでプラットフォームをx64に変更しましたが解決しませんでした。

    ターゲットをAnyCPUにすれば良いと思ったのですが、ターゲットを変更する箇所が見当たりません。

    解決につながりそうな情報をお持ちの方がいらっしゃいましたら、回答お願いします。


    ●動作する環境

    Win 7 x86 / Excel 2010 x86
    Win 7 x64 / Excel 2010 x86
    Win 7 x86 / Excel 2013 x86


    ●動作しない環境

    Win 7 x64 / Excel 2010 x64
    Win 8 x64 / Excel 2013 x64


    ●dllmain.cpp

    // dllmain.cpp : DLL アプリケーションのエントリ ポイントを定義します。
    #include "stdafx.h"

    BOOL APIENTRY DllMain( HMODULE hModule,
                           DWORD  ul_reason_for_call,
                           LPVOID lpReserved
          )
    {
     switch (ul_reason_for_call)
     {
     case DLL_PROCESS_ATTACH:
     case DLL_THREAD_ATTACH:
     case DLL_THREAD_DETACH:
     case DLL_PROCESS_DETACH:
      break;
     }
     return TRUE;
    }


    ●matrix.cpp

    #include "stdafx.h"

    // 掃き出し
    void WINAPI SweepC(long n,long intCs,long intCe,SAFEARRAY **saDat,SAFEARRAY **saRes)
    {
       long i, j, k, idx[2];
     double **dat, **res;

     // ロック
     SafeArrayLock(*saDat);
     SafeArrayLock(*saRes);

     // 配列確保
     dat = new double*[n+1];
     res = new double*[n+1];
     for (i=0;i<=n;i++) dat[i] = new double[n+1];
     for (i=0;i<=n;i++) res[i] = new double[n+1];

     // SAFEARRAY → 2次元データ
     for (idx[0] = 1 ; idx[0] <= n ; idx[0]++) {
      for (idx[1] = 1 ; idx[1] <= n ; idx[1]++) {
       SafeArrayGetElement(*saDat, idx, &dat[idx[0]][idx[1]]);
       SafeArrayGetElement(*saRes, idx, &res[idx[0]][idx[1]]);
      }
     }

     // 掃き出し
     for (i = intCs; i <= intCe; i++) {
      if (fabs(dat[i][i]) > 0.0000000001) {
       for (j = 1 ; j <= n ; j++) {
        for (k = 1 ; k <= n ; k++) {
         if (j == i && k == i) {
                      res[j][k] = 1 / dat[i][i];
         } else if (j == i) {
                      res[j][k] = dat[j][k] / dat[i][i];
         } else if (k == i) {
                      res[j][k] = -dat[j][k] / dat[i][i];
                   } else {
                      res[j][k] = dat[j][k] - dat[j][i] * dat[i][k] / dat[i][i];
         }
        }
       }
       for (j = 1 ; j <= n ; j++)
        for (k = 1 ; k <= n ; k++)
                   dat[j][k] = res[j][k];
      } else {
       for (j = 1 ; j <= n ; j++)
        for (k = 1 ; k <= n ; k++)
                   res[j][k] = dat[j][k];
      }
     }

     // 2次元データ → SAFEARRAY
     for (idx[0] = 1 ; idx[0] <= n ; idx[0]++) {
      for (idx[1] = 1 ; idx[1] <= n ; idx[1]++) {
       SafeArrayPutElement(*saDat, idx, &dat[idx[0]][idx[1]]);
       SafeArrayPutElement(*saRes, idx, &res[idx[0]][idx[1]]);
      }
     }

     // ロック解除
     SafeArrayUnlock(*saDat);
     SafeArrayUnlock(*saRes);

     // 配列解放
     for (i=0;i<=n;i++) delete dat[i];
       for (i=0;i<=n;i++) delete res[i];
     delete dat;
     delete res;

     return;
    }


    ●define,def

    LIBRARY "mydll"

    EXPORTS
     SweepC


    ●stdafx.h

    // stdafx.h : 標準のシステム インクルード ファイルのインクルード ファイル、または
    // 参照回数が多く、かつあまり変更されない、プロジェクト専用のインクルード ファイル
    // を記述します。
    //

    #pragma once

    #include "targetver.h"

    #define WIN32_LEAN_AND_MEAN             // Windows ヘッダーから使用されていない部分を除外します。
    // Windows ヘッダー ファイル:
    #include <windows.h>

     

    // TODO: プログラムに必要な追加ヘッダーをここで参照してください。
    #define _USE_MATH_DEFINES
    #include "math.h"     //数学関数
    #include "oleauto.h"  //SAFEARRAY


    ●targetver.h

    #pragma once

    // 以下のマクロは、最低限必要なプラットフォームを定義します。最低限必要なプラットフォームとは、
    // アプリケーションを実行するために必要な機能を備えた最も古いバージョンの Windows や Internet Explorer など
    // をいいます。これらのマクロは、指定したバージョンと、それ以前のバージョンのプラットフォーム上で利用できるすべての機能を有効にすることによって
    // 動作します。

    // 下で指定された定義の前に対象プラットフォームを指定しなければならない場合、以下の定義を変更してください。
    // 異なるプラットフォームに対応する値に関する最新情報については、MSDN を参照してください。
    #ifndef WINVER                          // 最低限必要なプラットフォームが Windows Vista であることを指定します。
    #define WINVER 0x0600           // これを Windows の他のバージョン向けに適切な値に変更してください。
    #endif

    #ifndef _WIN32_WINNT            // 最低限必要なプラットフォームが Windows Vista であることを指定します。
    #define _WIN32_WINNT 0x0600     // これを Windows の他のバージョン向けに適切な値に変更してください。
    #endif

    #ifndef _WIN32_WINDOWS          // 最低限必要なプラットフォームが Windows 98 であることを指定します。
    #define _WIN32_WINDOWS 0x0410 // これを Windows Me またはそれ以降のバージョン向けに適切な値に変更してください。
    #endif

    #ifndef _WIN32_IE                       // 最低限必要なプラットフォームが Internet Explorer 7.0 であることを指定します。
    #define _WIN32_IE 0x0700        // これを IE の他のバージョン向けに適切な値に変更してください。
    #endif

     

    ●64ビット用VBAのコード

    Private Declare PtrSafe Sub SweepC Lib "mydll.dll" (ByVal n As Long, ByVal s As Long, ByVal e As Long, ByRef dat() As Double, ByRef res() As Double)

    Private Sub MatSweep(n As Integer, s As Integer, e As Integer, adbDat() As Double, adbRes() As Double)
      
       SweepC n, s, e, adbDat(), adbRes()  'この行でエラーが表示される
      
    End Sub


    ●VBAで表示されるエラーの内容

    実行時エラー '53':ファイルが見つかりません mydll.dll

     

    2012年12月5日 4:05

回答

  • はい。32bit版DLLを動作させるにはvcredist_x86.exeが、64bit版DLLを動作させるにはvcredist_x64.exeが、それぞれインストールされている必要があります。
    • 回答としてマーク ライト 2012年12月13日 6:37
    2012年12月12日 13:28

すべての返信

  • 構成マネージャーでプラットフォームをx64に変更しました

    この記述では不明確なので確認です。

    プロジェクトのプロパティでダイアログ上部のプラットフォームが「x64」になっていますでしょうか?
    # 構成マネージャーはソリューション全体の制御をしているだけであり、個々のプロジェクトがx64になっていることを表すわけではありません。

    またファイルについても、x86の出力先はDebug / Releaseですが、x64の出力先は x64\Debug / x64\Release です。ファイルを間違えていたりはしませんか?

    2012年12月5日 4:40
  • 回答ありがとうございます。

    プロジェクトのプオrパティーのダイアログ上部のプラットフォームが「x64」となっていることを確認しました。

    また、x64\Releaseフォルダー内のDLLを用いました。

    今のところ、状況に変化ありません。

    引き続きご連絡いただけますと幸いです。

    2012年12月5日 8:19
  • では逆の可能性として、64bit環境であってもインストールしたExcelが実は32bit版ということはありますでしょうか? Excelを起動してタスクマネージャで確認した際に (32ビット) 等の表示が出ていないか確認してください。

    ちなみに64 ビット版の Office 2010 をインストールする方法には

    64 ビット OS に Office 2010 のインストール DVD-ROM をセットした場合、既定では 32 ビット版 Office 2010 のインストーラーが起動します。これは、64 ビット OS 環境に対しても 32 ビット版 Office 2010 をインストールすることが推奨されているためです。

    と書かれています。

    2012年12月5日 12:37
  • Excel が 32bit で WOW64 として実行されているのなら、System32 ではなく、SysWoW64 側が PATH に入るので、System32 にコピーすることは意味ないと思います。

    64bit Windows で System32 フォルダーは 64bit DLL、SysWOW64 フォルダーは 32bit DLL と考えてください。
    (System32 に今回の自作の DLL を入れるのが妥当かは何とも言いかねますが)

    2012年12月5日 13:46
    モデレータ
  • 回答ありがとうございます。

    Excel が64ビット版であることを確認しました。

    DLLの配置については、System32に保存したり、SysWOW64に保存したりと、両方の可能性を考えて試してみましたが、状況は変わりませんでした。

    VBAにて、LongLong型やLongPtr型を使用することを試していますが、今のところ状況は変わりません。

    他に何か対処法がありますでしょうか。よろしくお願い致します。

    2012年12月7日 2:24
  • x64向けのVC++ランタイムライブラリはインストール済みでしょうか?
    • 回答の候補に設定 佐伯玲 2012年12月10日 4:45
    2012年12月7日 4:01
  • ご連絡ありがとうございます。

    こちらのダウンロードとインストールのことでしょうか?

    http://www.microsoft.com/ja-jp/download/details.aspx?id=30679

    2012年12月12日 7:53
  • はい。32bit版DLLを動作させるにはvcredist_x86.exeが、64bit版DLLを動作させるにはvcredist_x64.exeが、それぞれインストールされている必要があります。
    • 回答としてマーク ライト 2012年12月13日 6:37
    2012年12月12日 13:28
  • vcredist_x64.exe をインストールしてから動作を確認したところ、無事正常に動作しました。

    ありがとうございました。大変助かりました。

    2012年12月13日 6:40