【MFC】ODBC 接続の IM002 エラー:32bit / 64bit ドライバ不一致の確認と対処

【MFC】ODBC 接続の IM002 エラー:32bit / 64bit ドライバ不一致の確認と対処

ビルド構成をx64に変えた、あるいは32bitのまま運用しているアプリで、ODBC接続だけが失敗することがあります。この記事では、アプリとODBCドライバの32bit / 64bitが食い違ったときに出るIM002エラーを、確認する場所と対処の順に扱います。DSNの設計やドライバ個別の設定値までは踏み込みません。


目次

まず確認するもの

症状最初に見る場所
IM002でドライバが見つからないアプリのビルド構成(Win32 / x64)と、同じビット数のドライバ一覧
x64に変えた途端に接続できない64bit側のドライバ一覧に、同名のドライバがあるか
ODBCアドミニストレーターにDSNが見えているのに失敗するそのDSNがUser DSNかどうか。User DSNは両方の一覧に出るため、見えていても接続できないことがある
接続文字列をコピーしたら失敗したDRIVER={…} の名前が、そのビット数で登録されている綴りと一致するか

アプリのビット数とODBCドライバのビット数は、必ず一致している必要があります。32bitアプリは32bitドライバだけ、64bitアプリは64bitドライバだけを読み込みます。これは実行ファイルとDLLのビット数が一致しないと起動しない仕組みと同じ理由で、0xc000007bエラーと根が同じ問題です。


IM002は何を言っているのか

ビット数が食い違うと、CDatabase::OpenExはCDBExceptionを投げます。32bitビルドで64bitにしか無いドライバを指定したときの出力です。

[接続失敗] CDBException
  m_strError    : データ ソース名および指定された既定のドライバーが見つかりません。

  m_strStateNativeOrigin : State:IM002,Native:0,Origin:[Microsoft][ODBC Driver Manager]

報告元がODBC Driver Managerである点が手がかりになります。データベースに届く前の段階、つまりドライバを探す段階で止まっています。DBサーバーやファイルの問題ではありません。

ドライバが見つからない理由は、登録先がビット数ごとに分かれているからです。片方に入れても、もう片方からは見えません。

対象レジストリキー
64bitドライバHKLM\SOFTWARE\ODBC\ODBCINST.INI\ODBC Drivers
32bitドライバHKLM\SOFTWARE\WOW6432Node\ODBC\ODBCINST.INI\ODBC Drivers

コマンドプロンプトで、それぞれの一覧を確認できます。

:: 64bit ドライバ一覧
reg query "HKLM\SOFTWARE\ODBC\ODBCINST.INI\ODBC Drivers"

:: 32bit ドライバ一覧
reg query "HKLM\SOFTWARE\WOW6432Node\ODBC\ODBCINST.INI\ODBC Drivers"

見落としやすいのは、ドライバ名そのものが違うこと

「Accessのドライバは入っている」と思っていても、32bit側と64bit側で登録されている名前が違うことがあります。検証機で両方の一覧を取得した結果が次です。

64bit側に登録されていた名前32bit側に登録されていた名前
Microsoft Access Driver (*.mdb, *.accdb)Microsoft Access Driver (*.mdb)
Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)Microsoft Excel Driver (*.xls)
Microsoft Access Text Driver (*.txt, *.csv)Microsoft Text Driver (*.txt; *.csv)

64bit側はAccess Database Engine(ACE)が入れたドライバ、32bit側はWindowsに元から入っている古いドライバです。名前が別物なので、64bitアプリで動いていた接続文字列を32bitビルドへ持っていくと、綴りが一致せずIM002になります。エラーは「ドライバが無い」と読めますが、実際は「その名前のドライバが、このビット数には登録されていない」という意味です。


同じコードをx64とWin32でビルドして確かめる

同一のソースを両方の構成でビルドし、同じ接続文字列で試すと違いがはっきりします。ドライバ名には64bit側にしか無いMicrosoft Access Text Driver (*.txt, *.csv) を指定し、実行ファイルと同じフォルダのCSVを読みます。

この検証機には64bit版のACEだけが入っています。32bit版のACEも入っている環境では、Win32ビルドでも接続に成功してIM002は出ません。手元で試す前に、先ほどのreg queryで32bit側の一覧を確認してください。

CString strConn;
strConn.Format(_T("DRIVER={%s};DBQ=%s;"),
               _T("Microsoft Access Text Driver (*.txt, *.csv)"),
               (LPCTSTR)GetExeDir());

CDatabase db;
try
{
    db.OpenEx(strConn, CDatabase::noOdbcDialog);
    CRecordset rs(&db);
    rs.Open(CRecordset::forwardOnly, _T("SELECT id, name FROM sample.csv"),
            CRecordset::readOnly);
    // 取得処理
}
catch (CDBException* e)
{
    // ビット数が一致しないと、ここで IM002 が報告される
    _tprintf(_T("%s\n"), (LPCTSTR)e->m_strStateNativeOrigin);
    e->Delete();
}

x64ビルドは接続でき、CSVの中身まで読み取れました。

--------------------------------------------------
プロセスのビット数 : 64 bit (sizeof(void*)=8)
使用する DRIVER    : Microsoft Access Text Driver (*.txt, *.csv)
--------------------------------------------------
接続文字列 : DRIVER={Microsoft Access Text Driver (*.txt, *.csv)};DBQ=C:\temp\178_OdbcBitness\x64;

[接続成功] ドライバのビット数が一致しています。
--- sample.csv の中身 ---
  id=1, name=Alice
  id=2, name=Bob
  id=3, name=Carol

同じソースのWin32ビルドは、接続の時点で失敗します。32bit側にこの名前のドライバが無いためです。

--------------------------------------------------
プロセスのビット数 : 32 bit (sizeof(void*)=4)
使用する DRIVER    : Microsoft Access Text Driver (*.txt, *.csv)
--------------------------------------------------
接続文字列 : DRIVER={Microsoft Access Text Driver (*.txt, *.csv)};DBQ=C:\temp\178_OdbcBitness\x86;

[接続失敗] CDBException
  m_strError    : データ ソース名および指定された既定のドライバーが見つかりません。

  m_strStateNativeOrigin : State:IM002,Native:0,Origin:[Microsoft][ODBC Driver Manager]

コードも接続文字列も同じで、違うのはビルド構成だけです。


odbcad32.exeとDSNの見え方

ODBCアドミニストレーターも2つあります。フォルダ名と中身が逆に見えますが、System32が64bit用、SysWOW64が32bit用で正しい対応です。

ツールパス対象
64bit版C:\Windows\System32\odbcad32.exe64bitドライバ / 64bit System DSN
32bit版C:\Windows\SysWOW64\odbcad32.exe32bitドライバ / 32bit System DSN

スタートメニューから「ODBCデータ ソース」を開くと、どちらを起動したのか分かりにくいことがあります。確実に区別するには、上記のパスを直接指定して起動します。

DSNの見え方は種類によって違うので注意が必要です。System DSNはビット数ごとに分かれていて、32bit用に作ったものは64bit版の一覧には出ません。一方User DSNは分かれておらず、両方の一覧に出ます。ただし一覧に出ることと接続できることは別です。32bitドライバを使うUser DSNは64bitアプリからも見えますが、接続するとIM002になります。「アドミニストレーターには見えているのに繋がらない」ときは、この状態を疑ってください。


症状ごとの対処

症状原因対処
64bitアプリでAccessのファイルに接続できない64bit版ACEが未インストールMicrosoft Access Database Engineの64bit版を入れる
Win32からx64に変えたら接続できなくなった64bit側に同名ドライバが無い、またはSystem DSNが32bit側にしか無い64bit側の一覧を確認し、必要なら64bit版odbcad32.exeでDSNを作る
DSNレス接続でドライバ名エラーになるドライバ名の綴りが、そのビット数の登録名と違うreg queryで登録名をそのまま写す
User DSNが見えているのにIM002になるそのDSNが、アプリと違うビット数のドライバを指しているアプリと同じビット数のドライバを入れるか、そのDSNを作り直す
64bit版ACEのインストーラが止まる32bit版Officeが入っているとブロックされることがあるOfficeのビット数を確認する。合わせられない場合はアプリをWin32ビルドのままにする

どちらのビット数に合わせるかは、入れられるドライバ側の制約で決まることが多いです。ドライバを32bitしか用意できない場合、そのプロセスから直接つなぐ限りはWin32ビルドに揃えることになります。


まとめ

  • IM002の報告元がODBC Driver Managerなら、DBではなくドライバを探す段階で止まっています
  • 32bitアプリは32bitドライバ、64bitアプリは64bitドライバだけを読み込みます
  • ドライバの登録先はODBCINST.INIとWOW6432Node\ODBC\ODBCINST.INIに分かれています
  • 同じ製品でも32bit側と64bit側で登録名が違うことがあるため、接続文字列の綴りは登録名をそのまま写します
  • odbcad32.exeはSystem32が64bit用、SysWOW64が32bit用です
  • System DSNはビット数ごとに分かれ、User DSNは両方から見えます。見えていても接続できるとは限りません
  • ビルド構成をWin32からx64に変えたら、ドライバとDSNを同じビット数で用意し直します
目次