ビルド構成を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.exe | 64bitドライバ / 64bit System DSN |
| 32bit版 | C:\Windows\SysWOW64\odbcad32.exe | 32bitドライバ / 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を同じビット数で用意し直します
