「序数 X がダイナミックライブラリから見つかりませんでした」というエラーの原因


前提環境

Aというライブラリがある

A.h:A1という関数を宣言
A.cpp:A1という関数を定義
A.def:A1という関数を「@1」として指定して公開:ここは「序数」の番号
A.lib:コンパイル後作成
A.dll:コンパイル後作成

BというアプリケーションがライブラリAを使っている

BがA.hを見ている
BがA1という関数を使っている
BがA.libを使用している(関数A1を使用するためにコンパイルする時に使用)
BがA.dllを使用している(関数A1を使用するために実行する時に使用):※ここは重要

開発の流れ

①Aを製造・修正
②Aをコンパイル
③Bを製造・修正
④Bをコンパイル
⑤A.dllをBの実行フォルダにコピー:※ここは重要
⑥Bを実行して確認

エラーが発生する経緯

AのA.defで関数A1を「@1」として指定しているため、関数A1と「@1」の対応関係がA.libに反映されている。
BでA1関数を使う時に、A.libを参照しA.libに定義されている対応関係によって、A.dllから「@1」を探す。
すべてのソース・ライブラリ・モジュールは同じバージョンであれば「@1」は確認できるので問題ない。

しかし、上記流れの⑤は漏れたら、この記事のエラーが発生する。

例えば、ライブラリAにA2という関数を追加し、BでA2も使用される。
A.h:A2という関数の宣言を追加
A.cpp:A2という関数の定義を追加
A.def:A2という関数を「@2」として指定:最後にエラーになる番号
A.lib:コンパイル後「@1」と「@2」の2個の対応関係がある
A.dll:コンパイル後A1とA2両方の関数が使える

Bをコンパイルする際、A.hとA.libが参照され、A2という関数が存在することを確認でき、Bをコンパイルしてもエラーにならない。
(コンパイル時、A.hとA.libしか使用しないため、A.hとA.libが正しく参照できる限りBのコンパイルエラーが発生しない)

この後、Aの新しいdllをBの実行フォルダにコピーせずにBを実行すると、Bの実行時エラーが発生する。

原因としては、
①BがライブラリAのA.libからA2という関数が存在することを知っている。
②このため、BがA2を使おうとしている際、A.libの対応関係によってA.dllから「@2」を探す。
③しかし、Bが見えるA.dllは、「@2」がまだ実装されていない古いA.dllであるため、「序数2が見つかりませんでした」というエラーが発生する。

即ち、Bが使用しているA.libのバージョンは、Bが見えるA.dllのバージョンと違う。

解決方法も簡単で、上記開発の流れ⑤を漏れなく再実行すること。
※Aを更新するたびにBの実行フォルダにコピーする必要がある。
 Aのプロジェクトにコピー用のコマンドを指定してもよいし、AとBのモジュールを同じフォルダに作成してもよい。