XmlSerializerを使うと全く関係のない箇所でDllImport属性が失敗する
※注意 完全に原因が分かったわけではないが、なぜかこうするとうまくいく系の備忘録です。
アプリの構成
a.exe ← C#
b.dll ← C#
c.dll ← C++
a,b,c全部自作のものであるとする。
実装
- aの中に
XmlSerializer
を使った処理を書く - bの中でcのメソッドを
DllImport
を使って書く - c内にはstdcallの
_declspec(dllexport)
で適当な処理を書いておく
デバッグした時の流れ
- b.dll、c.dllがロードされる
- アプリケーションの設定としてxmlに保存していたのをアプリケーションの最初の方で読みだす
- ここで
XmlSerializer
のコンストラクタ内でFileNotFoundException
が発生する(シリアライズのためのDLLを作成するオプションがオフのため作ってない) - 内部的にはそのまま例外処理が行われるのでアプリケーション側ではそのまま処理が続行する
- ここでなぜかc.dllがアンロードされる
- その後aからbのメソッドを呼ぶ
- bはcのラッパーライブラリなので内部的には
DllImport
属性のついたメソッドをそのまま呼ぶ -
DllNotFoundException無効なアドレスにアクセスしようとしています。
という例外が発生して落ちる
対処法
その1
XmlSerializer
を使う処理の前にDllImport
属性のついたメソッドを読んでおく。
一回呼んでおくとアンロードされないっぽい。
その2
XmlSerializer
のコンストラクタ内でFileNotFoundException
を発生させないためにシリアライズ用のDLLを作成しておく。
以下Copilotに質問した時の返答
-
DLL の生成オプションを有効にする:
プロジェクトのプロパティからビルド設定に移動します。
「シリアル化アセンブリの生成」オプションをオンにします。
これにより、必要な DLL が生成されます。 -
csproj ファイルを直接編集する:
csproj ファイル内に false を追加します。
このオプションは UI で設定できないため、直接ファイルを編集する必要があります。 -
ビルド後イベントで sgen.exe を呼び出す:
sgen.exe を呼び出して DLL を生成する方法もあります。
Visual Studio のインストール環境によっては、ビルド後イベントのパスを調整する必要があるかもしれません。
私は1だけだと作成されなかったので2も行う必要がありました。特殊事例のためおま環の可能性が高いです。
dllがアンロードされる原因まではわからなかったのでもしかすると他の要因でダメになってるのかも・・・。
以上