Visual Studio 2012以降で、.NETを使ったC++/CLIでXmlDocumentクラスを使った場合に実行時に以下のようなエラーになる事があります。
「'System.Xml.BinaryCompatibility' のタイプ初期化子が例外」
「'System.Uri' のタイプ初期化子が例外」
最初はWindows 8.1とWindows Server 2012だけの現象かと考えていましたが違いました。Visual Studio 2012以降に、C++/CLIを使った時に生じる問題でした。OSは無関係です。かなり悩んだのできっと同じ道を辿る方の為に原因と対処方法をまとめます。ちなみにこの解決方法は
「ここ」で知りました。感謝感謝です!
C++/CLIをVisual Studioでビルドするとテンポラリフォルダ(C:\Users\YOURNAME\AppData\Local\Temp\)の下に、
.NETFramework,Version=v4.0.AssemblyAttributes.cpp
と言うファイルが自動作成されます。このファイルの中の記述が問題を生じていました。Visual Studio 2010で生成される内容は以下です。
#using
[assembly: System::Runtime::Versioning::TargetFrameworkAttribute(L".NETFramework,Version=v4.0", FrameworkDisplayName=L".NET Framework 4")];
対してVisual Studio 2012以降では以下の内容が自動生成されます。
#using
[assembly: System::Runtime::Versioning::TargetFrameworkAttribute(L"", FrameworkDisplayName=L".NET Framework 4")];
問題は太字にしている文字列です。ここが L"" になったままビルドされたアプリやライブラリを利用すると最初に書いたようにXmlDocument::LoadXml()を利用するだけで例外を生じるようになってしまいます。ちなみにエラーは以下です。
ハンドルされていない例外: System.TypeInitializationException: 'System.Xml.BinaryCompatibility' のタイプ初期化子が例外をスローしました。 ---> System.Reflection.TargetInvocationException: 呼び出しのターゲットが例外をスローしました。 ---> System.TypeInitializationException: 'System.Runtime.Versioning.BinaryCompatibility'のタイプ初期化子が例外をスローしました。 ---> System.ArgumentException: 文字列の長さを 0 にすることはできません。
パラメーター名:frameworkName
つまり文字列の長さが 0 になっている為のエラーです。なので解決方法は、.NETFramework,Version=v4.0.AssemblyAttributes.cpp の中を、Visual Studio 2010と同じ内容に修正してしまう方法になります。つまり以下のように修正します。
#using
[assembly: System::Runtime::Versioning::TargetFrameworkAttribute(L".NETFramework,Version=v4.0", FrameworkDisplayName=L".NET Framework 4")];
.NETFramework,Version=v4.0.AssemblyAttributes.cpp は既に存在している場合には上書きされない仕様のようですので、通常は1回書き換えるだけで以後問題はなくなるはずです。何かの拍子に再発した場合には再度修正しましょう。なおトレースは以下と表示されていました。
場所 System.Xml.XmlReaderSettings.EnableLegacyXmlSettings()
場所 System.Xml.XmlTextReaderImpl..ctor(XmlNameTable nt)
場所 System.Xml.XmlTextReaderImpl..ctor(String url, TextReader input, XmlNameTable nt)
場所 System.Xml.XmlDocument.LoadXml(String xml)
問題を難しくしていたのは、Visual Studio 2010を先に入れて使っていた環境に、後からVisual Studio 2015なんかを入れた場合には、既に正しい .NETFramework,Version=v4.0.AssemblyAttributes.cpp が生成されているので、問題を生じることは無いと言う点です。
これってVisual Studioのバグなんじゃ無いかと愚考するのですがいかがでしょうか?とにかく最初は理由が全く分からずに苦労しました。後から来る人の参考になれば幸いです。やれやれ…(^^;;