ビルド構成を 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 を同じビット数で用意し直します
