Visual Studio 2010 で 32bit としてビルドした C++ の GUI アプリが、Windows 7(64bit)で “The application was unable to start correctly (0xC000007B)” を出して起動しない――この症状の9割は「ビット数の取り違え」と「DLL の置き場所の誤り」です。本稿は現場での切り分け手順と再発防止までを、コピペで実行できる具体策に落とし込んで解説します。
0xC000007B の正体と発生メカニズム
0xC000007B = STATUS_INVALID_IMAGE_FORMAT は、プロセスが読み込もうとした PE 画像(EXE/DLL)の形式が自分と適合しないときに返される代表的な例外コードです。現場で最も多いのは、32bit 実行ファイルが 64bit DLL をロードした(またはその逆)というケースです。
Windows x64 では 32bit プロセスは WOW64 上で動作し、ロードできるのは PE32(x86) の DLL に限られます。アプリ側が PE32+(x64)の DLL を捕まえてしまうと、初期ロード段階(Load Image)で失敗し、起動前に 0xC000007B を返します。
他に、破損した DLL、ランタイムの欠如、デバッグ版ランタイムへの依存などでも同エラーに見えることはありますが、まずはビット数の不一致から疑うのが最も効率的です。
最初に理解しておくべき「System32 と SysWOW64」
64bit Windows では名称と実体が直感に反します。以下の表を頭に入れておくと、DLL の置き場所を誤りません。
| フォルダ | 実体(x64 OS) | 主な用途 |
|---|---|---|
| C:\Windows\System32 | 64bit のシステム DLL | 64bit プロセス用。x64 ネイティブの OS コンポーネントがここを見る。 |
| C:\Windows\SysWOW64 | 32bit のシステム DLL | 32bit プロセス用。WOW64 リダイレクトにより 32bit アプリはここに誘導される。 |
| C:\Windows\Sysnative | 32bit プロセスから見た System32 への実体参照 | スクリプト等で 32bit プロセスが 64bit 側の System32 にアクセスしたいときだけ使用。 |
結論:サードパーティ DLL を System32 / SysWOW64 に手動コピーしない。この誤った運用が 0xC000007B の主犯です。
状況整理:今回の「質問概要」への当てはめ
- VS2010 で Win32 としてビルドした GUI アプリ。
- Windows 7 x64 で 0xC000007B により起動不可。
- 過去に
WDAPI.dllが見つからない警告 → System32 / SysWOW64 に 32bit/64bit DLL を手動コピー した経緯あり。
この履歴から、アプリが x64 版の WDAPI.dll(または別の依存 DLL)を捕まえている可能性が非常に高いです。
原因の本質:ビット数の不一致を断定する
PE のビット数はツールで即断できます。Windows SDK(VS 付属)の dumpbin を使います。
dumpbin /headers <ファイル名> | findstr /C:"machine" /C:"PE32"
典型的な結果:
FILE HEADER VALUES
14C machine (x86)
8664 machine (x64)
OPTIONAL HEADER VALUES
10B magic # (PE32) ← 32bit
20B magic # (PE32+) ← 64bit
判定ポイントは machine と PE32 / PE32+ の組み合わせです。アプリ EXE が x86 / PE32 であるのに、どこかの DLL が x64 / PE32+ ならそれが犯人です。
依存 DLL の全体像を出す(起動時ロードを観測)
依存が多い場合は、手作業で一つずつ確認するより、ツールで一網打尽に洗い出します。
- Dependency Walker(depends.exe):静的解析で Import/Delay-Load を可視化。赤い「×」や「wrong machine type」で即判明。
- Process Explorer:実行後に該当プロセスを選択し、下部ペインを「DLLs」に切替えると実ロード DLL とパスが一覧化。
- Process Monitor:フィルタ「Process Name is <exe名>」「Operation is Load Image」で、どの検索順でどこを見に行ったかまで追跡可能。
なお、コマンドだけで絞る場合は次の組み合わせも有効です。
where /r C:\ WDAPI.dll
sigcheck -q -nobanner -a WDAPI.dll <!-- Sysinternals があればビット数を一発表示 -->
やってはいけないこと:システムフォルダへの手動コピー
以下は 0xC000007B を引き起こしやすいアンチパターンです。
- DLL を System32 と SysWOW64 に両方コピーして「どちらか当たるだろう」と期待する。
- PATH に x64 版 DLL を含むフォルダを先頭に入れ、32bit アプリからも共有する。
- ベンダが提供する x86 版と x64 版の同名 DLL を同一フォルダに混在させる。
すべて Loader の検索順(Application Directory > System32 > … > PATH)と WOW64 リダイレクトにより、意図せず 異なるビット数を拾う温床になります。
正しい DLL 配置:アプリローカル配置が鉄則
第三者提供の DLL は、アプリの実行ファイルと同じフォルダに置くのがトラブル最小です。推奨レイアウトの例を示します。
| フォルダ構成 | 中身 | 備考 |
|---|---|---|
| \MyApp\bin\MyApp.exe | 32bit 実行ファイル | VS2010 の Win32 構成で生成された EXE |
| \MyApp\bin\WDAPI.dll | WDAPI の x86 版 | 必ず x86 版。dumpbin で確認。 |
| \MyApp\bin\<その他の非システム DLL> | x86 版のみ | ベンダ SDK の Win32 配下から取得する。 |
| \MyApp\bin\x64\(必要なら別パッケージ) | x64 版一式 | 32bit 用とは混在させない。配布も別にする。 |
既に System32 / SysWOW64 にコピーしてしまった DLL は、アプリが意図せず掴まないように削除してください。管理外のシステム領域に残すのは将来の事故要因になります。
Visual Studio 2010 側のチェックポイント
- 構成とプラットフォーム:メニュー「ビルド」→「構成マネージャ」で アクティブ ソリューション プラットフォーム = Win32 を確認。誤って x64 にしていないか。
- リンカの入力:プロジェクトのプロパティ → リンカ → 入力 の「追加の依存ファイル」で、x64 用 .lib を混ぜていないか。ライブラリ ディレクトリも Win32 用パスのみを指すよう整理。
- ランタイム:C/C++ → コード生成 → ランタイム ライブラリ は
/MD(リリース)または/MDd(デバッグ)。配布は/MDを推奨。 - マニフェスト:リンカ → マニフェスト ファイル は「はい」。Side-by-Side エラーの予防になる。
- 再ビルド:「クリーン → リビルド」で古い成果物を完全に除去。
生成直後の EXE / DLL は、忘れず dumpbin /headers でビット数を目視確認しましょう。
WDAPI.dll ケースの実践手順(サンプル)
WDAPI のようなデバイス SDK 由来 DLL では、ベンダ配布物に x86 と x64 が同梱されていることが多く、混在しがちです。次の手順で修正します。
- System32 / SysWOW64 に
WDAPI.dllをコピーした履歴があれば、まずすべて削除。 - ベンダ SDK の Win32(x86) フォルダから
WDAPI.dllを取り出し、アプリ EXE と同じフォルダに配置。 - 同じフォルダ内にある WDAPI 系 DLL(例:
WDAPI32.dll、wdapi_core.dllなど)もすべて x86 版で統一。名前が同じでも中身が x64 の場合があるため dumpbin で逐一確認。 - PATH にベンダの x64 フォルダが先行していないか確認。必要なら配布パッケージ内で PATH を変更しない、またはアプリが DLL を 相対パス(アプリローカル)だけで解決できる構成にする。
- 起動してもダメなら Process Monitor で Load Image のログを確認。意図しないフォルダから WDAPI を拾っていないかを特定。
コマンドで一括検査:配布前の「ビット数チェック」
配布物に紛れ込んだ x64 DLL を見落とさないための簡易スクリプト例(PowerShell)。
# MyApp\bin 配下の EXE/DLL の machine を一覧表示
Get-ChildItem -Path . -Include *.exe,*.dll -Recurse |
ForEach-Object {
$out = & "dumpbin.exe" /headers $_.FullName 2>&1 | Select-String -Pattern "machine|PE32"
"{0}`t{1}" -f $_.Name, ($out -join " | ")
}
出力に machine (x64) や PE32+ が混じっていないかを確認します。混在があれば、そのファイルは配布対象から除外します。
トラブル切り分け用の最小検証プログラム
ライブラリ提供元の動作に疑義があるときは、最小の Win32 アプリを作って LoadLibrary の成否とエラーコードを確認します。VS2010 の「空の Win32 プロジェクト」で以下を貼り付けます。
#include <windows.h>
#include <stdio.h>
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
HMODULE h = LoadLibraryW(L"WDAPI.dll");
if (!h) {
DWORD e = GetLastError();
wchar_t msg[1024];
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, e, 0, msg, 1024, NULL);
MessageBoxW(NULL, msg, L"LoadLibrary 失敗", MB_ICONERROR);
return (int)e;
}
FreeLibrary(h);
MessageBoxW(NULL, L"Load 成功 (x86).", L"OK", MB_OK);
return 0;
}
GetLastError() が 193 (ERROR_BAD_EXE_FORMAT) の場合、DLL のビット数不一致が確定です。
ランタイム欠如による類似症状の備え
頻度は低いものの、MSVC ランタイム(msvcr100.dll など)がない環境では、起動直後に失敗して 0xC000007B と見分けづらいことがあります。配布先がクリーンな Windows 7/10/11 の場合は、念のため Visual C++ 2010 再頒布可能パッケージ(x86) をインストール手順に含めておくと安全です。
- デバッグ版(
/MDd)は msvcr100d.dll を要求します。配布不可かつ OS には存在しないため、配布は Release(/MD) に限定すること。 - Side-by-Side で別エラー(例:
0xC0150002)が出る場合は、マニフェストの欠如や VC ランタイムとの不整合を疑う。
Windows の DLL 検索順と実運用のコツ
Windows 7 既定の検索順は概ね次のとおりです(SafeDllSearchMode 有効時)。
- アプリケーション ディレクトリ
- System ディレクトリ(32bit プロセスからは SysWOW64)
- Windows ディレクトリ
- カレント ディレクトリ
- PATH の各ディレクトリ
運用コツはシンプルです。
- アプリローカルで完結させる(最優先)。
- どうしても PATH を使う場合は、x86 版 DLL のみを含むフォルダを PATH の先頭にし、x64 版パスは同居させない。
- 自作 DLL は名前にアーキテクチャを含める(例:
mylib32.dll/mylib64.dll)と混入事故を減らせる。
よくある症状と原因・対処の対比表
| 画面/ログの症状 | 主な原因 | 対処 |
|---|---|---|
| The application was unable to start correctly (0xC000007B) | x86 EXE が x64 DLL をロード(または逆) | dumpbin で全 DLL を確認。x86 版で統一し、アプリローカル配置に修正。 |
| DLL が見つからない(not found) | 検索パスに対象 DLL がない/PATH 順序の問題 | アプリフォルダに配置。PATH 依存をやめる。Process Monitor で検索順を確認。 |
| 起動はするが途中で落ちる | Delay-Load 先の DLL が不一致/関数エクスポートの不整合 | Dependency Walker で Delay-Load を確認。バージョンとビット数を合わせる。 |
| 「Side-by-Side 構成が正しくない」 | VC ランタイムやマニフェストの不整合 | 再頒布パッケージ(x86)導入、/MD で再ビルド、マニフェスト有効。 |
| デバッグ環境では動くが配布先では動かない | デバッグ ランタイム(msvcr100d.dll)への依存 | Release ビルドで配布。必要なら x86 再頒布を同梱。 |
実施手順まとめ:これだけやれば直るチェックリスト
- System32 / SysWOW64 に置いた サードパーティ DLL を全削除。
- VS2010 の構成を Win32(x86) に固定し、クリーン → リビルド。
- EXE とすべての非システム DLL に対し
dumpbin /headersで machine (x86) / PE32 を確認。 - 依存 DLL は アプリ EXE と同じフォルダに集約。
- 起動しない場合は Process Monitor の Load Image で、誤フォルダから拾っていないかを確認。
- それでも不可なら、最小検証アプリで
LoadLibraryのエラーコードを取得し、193 かを確認。
配布・運用の再発防止プラクティス
- アーキテクチャ別パッケージ:x86 と x64 のインストーラを分ける。フォルダやファイル名にも
_x86/_x64を明記。 - ビルド後検証を自動化:CI の後工程に dumpbin 走査スクリプトを入れ、x86 パッケージに x64 DLL が混じったらビルド失敗にする。
- ベンダ SDK の取り込み規約:プロジェクト内に
external\vendor\wdapi\x86のように明示的に分け、Additional Library Directories はその x86 パスのみを参照。 - デバッグ配布禁止:/MDd ビルドを配布パイプラインから排除し、Release のみ成果物にする。
- ドキュメント化:README に「System32 / SysWOW64 へコピーしない」旨を太字で明記。
補足:Windows 10/11 でも基本は同じ
本稿は Windows 7 を前提に説明しましたが、「ビット数を揃える」「DLL はアプリローカル」という原則と手順は Windows 10/11 でも変わりません。VS2010 時代の資産でも、ルールを守れば最新 OS 上で問題なく動作します。
ケーススタディ:修復の実際(要点だけ)
- エラー:起動直後に 0xC000007B。ログに
WDAPI.dllの警告履歴あり。 - 調査:
where WDAPI.dllで System32 と SysWOW64 の両方に存在。dumpbinで System32 のものが x64 と判明。 - 対処:両方から削除 → ベンダ SDK の Win32 から x86 版をアプリフォルダへ配置。
- 確認:Process Monitor の Load Image が
\MyApp\bin\WDAPI.dllを指し、dumpbin でも machine (x86) / PE32 を確認。 - 結果:起動成功。依存 DLL も同様に x86 で統一し、ビルド・実行とも正常になった。
FAQ(現場でよく出る質問)
Q. 32bit アプリから 64bit のドライバ API(DLL)を直接呼べますか?
A. できません。32bit プロセスは 32bit DLL しかロードできません。必要ならば、x64 のブリッジプロセスを用意し、IPC(Named Pipe 等)で連携します。
Q. 64bit OS なら System32 に 32bit DLL を置けば両対応できませんか?
A. できません。System32 は 64bit の居場所です。32bit は SysWOW64 側ですが、そもそもシステムフォルダに手動コピーしないのが正解です。
Q. VS2010 しか使えません。対処は変わりますか?
A. いいえ。ビット数一致と配置場所の原則は同じです。VS2010 のツール(dumpbin, depends.exe)だけで解決可能です。
Q. ランタイムの不足とビット不一致をどう見分けますか?
A. LoadLibrary のエラーが 193 なら不一致、126/127 なら見つからない、14001 などなら Side-by-Side(ランタイム)を疑います。Process Monitor とイベントログも併用すると早いです。
まとめ
0xC000007B は難解に見えて、実は原因が絞りやすいエラーです。行うべきことは次の二点に尽きます。
- EXE・DLL のビット数を徹底的に 32bit で統一する。
- サードパーティ DLL はアプリと同じフォルダに置き、System32 / SysWOW64 にコピーしない。
この原則に沿って、dumpbin で確認しながら配置を正せば、Windows 7 x64 でも VS2010 製 Win32 アプリは確実に起動します。もし迷ったら、本稿のチェックリストに沿って一つずつ潰していきましょう。
実行手順(コピペ用ショートガイド)
- (管理者権限のコマンドプロンプトで)System32 / SysWOW64 の該当 DLL を削除。
del /f /q C:\Windows\System32\WDAPI.dll
del /f /q C:\Windows\SysWOW64\WDAPI.dll
- ベンダ SDK の Win32 から x86 版 DLL をアプリフォルダへ。
dumpbinで EXE / DLL のビット数を確認。
dumpbin /headers MyApp.exe | findstr /C:"machine" /C:"PE32"
dumpbin /headers WDAPI.dll | findstr /C:"machine" /C:"PE32"
- VS2010 を Win32 構成にして Clean → Rebuild。
- 必要に応じて x86 の VC 再頒布を導入(配布先)。
- 起動。ダメなら Process Monitor の Load Image で検索順を追跡。
チェック項目のテンプレート(プロジェクトに貼って使う)
| 項目 | 期待値 | 確認方法 |
|---|---|---|
| ソリューション プラットフォーム | Win32(x86) | 構成マネージャで Win32 を選択 |
| 出力 EXE のビット数 | PE32 / machine (x86) | dumpbin /headers |
| 配布 DLL のビット数 | 全て PE32 / machine (x86) | スクリプトまたは個別に dumpbin |
| DLL の配置 | アプリフォルダのみ | System32 / SysWOW64 に存在しないことを確認 |
| ランタイム依存 | /MD(Release)のみ | プロパティ「ランタイム ライブラリ」 |
| PATH の影響 | 不要(アプリローカルで完結) | PATH からベンダ DLL パスを排除 |
最後に:現場の落とし穴を避ける合言葉
「x86 で揃える。System32 には置かない。アプリと同じ場所。」
この三点を守るだけで、0xC000007B で悩む時間はゼロにできます。今日直して、明日以降も再発させない仕組みづくりへ進みましょう。

コメント