何が悪いのかを見つけるのに丸一日かかりました。
ここで、私が何をしているのかをもう少し詳しく説明する必要があります。LIB ファイルにコンパイルする C++ コードがあります。上記のコード (Tester と Thrower) は、このプレーンな C++ LIB ファイルにあります。
そして、この LIB ファイルにリンクするマネージド C++ DLL にコンパイルされる別の C++ コードがあります。したがって、最後に両方のコードが同じ DLL 内にあります。次のように、LIB ファイル内のコードを呼び出すラッパー関数を管理しました。
ManagedWrapper()
{
try
{
Thrower();
}
catch (std::exception& e)
{
throw new System::Exception(e.what());
}
}
これは機能しません。このコードでは、メモリ リークとネットワーク ソケットが閉じられていません。Thrower のスタックは巻き戻されません。
これは、catch に到達する前にスタックの巻き戻しが行われないためです。ただし、catch が throw 以外の別のライブラリにある場合、スタックは巻き戻されません。DLL は LIB ファイルのスタックをアンワインドする方法を知りません (両方とも最終的に同じ DLL にコンパイルされますが!!)
しかし、私は非常に簡単な解決策を見つけました。
LIB ファイルでは、次のように ManagedWrapper() と Thrower() の間に中間関数を追加する必要がありました。コードはばかげているように見えますが、問題は解決します。
Catcher()
{
try
{
Thrower();
}
catch(...) // unwind HERE
{
throw;
}
}
重要なことは、このキャッチャーは、例外がスローされる LIB ファイルに存在する必要があるということです。例外がキャッチされると、スタックがアンワインドされ、マネージド ラッパーに例外が再スローされます。
ばかげているように見えるコードが非常に賢い場合もあります。
概要: 例外は常に、例外がスローされたのと同じライブラリでキャッチする必要があることを忘れないでください。それらがライブラリの境界を越えてキャッチされると、重大な問題が発生します。