Dotfuscator で System.Xml 名前空間にあるクラスを使用しているアセンブリを難読化するとエラーになる現象を回避する

ページ更新日 :
ページ作成日 :

現象の確認

プロジェクトを新規に作成します。Windows Form, WPF どちらでも構いませんが、ここでは WPF アプリケーションを作成しています。

System.Xml 名前空間に属しているクラスを使用するようにコードを書きます。ここでは以下のように「XmlDocument」「XmlNode」のクラスを使用しています。

using System.Windows;
using System.Xml;

namespace DotfuscatorTest
{
  /// <summary>MainWindow.xaml の相互作用ロジック</;summary>
  public partial class MainWindow : Window
  {
    public MainWindow()
    {
      InitializeComponent();

      XmlDocument doc = new XmlDocument();
      doc.LoadXml("<a></a>");
      XmlNode node = doc.FirstChild;
    }
  }
}

System.Xml 名前空間のクラスを使用したコード

ビルド後、メニューのツールから「PreEmptive Dotfuscator and Analytics」を選択し起動します。

PreEmptive Dotfuscator and Analytics を起動

作成した .exe ファイルを追加し、ビルドします。

.exe ファイルを追加

すると以下のようなエラーメッセージがでてビルドに失敗します。

これはマネージ モジュール (C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\Silverlight\v4.0\Profile\WindowsPhone71\ja\System.Xml.dll) ではありません。ビルド エラーです。

ビルドエラー

このエラーの原因について調べてみたのですが明確な答えを見つけることができませんでした。英語サイトのほうにも情報がないのと、System.Xml.dll のパスに「ja」がついているのを考慮すると、英語環境以外の特有のエラーではないかと推測できます。

回避策

プロジェクトでは Windows クライアントの System.Xml.dll を参照しているにも関わらず、Dotfuscator でビルドしたときに Windows Phone の System.Xml.dll をアセンブリを参照してしまうので、ここでは強制的にローカルにコピーした System.Xml.dll を参照するという方法でビルドエラーを回避したいと思います。

プロジェクトの参照設定を開き「System.Xml」を右クリック、「プロパティ」を選択します。

プロパティを選択

ローカル コピーの項目を True に変更します。

ローカル コピーの項目を True に変更

この状態でビルドすると「System.Xml.dll」が .exe ファイルと一緒に出力されます。

System.Xml.dll が出力される

Dotfuscator を開き、難読化するアセンブリと一緒に「System.Xml.dll」も追加します。これで難読化するアセンブリはインストールされているフレームワークの DLL を参照せずローカルの DLL を見るようになります。

ここで注意していただきたいのが、System.Xml.dll のプロパティにある「ライブラリ モード」にチェックが入っていることを確認してください。このチェックがないと System.Xml.dll も難読化されてしまい、参照するクラス名が変更されてしまう場合があります。クラス名が変わるともちろんアプリケーションを正常に起動できなくなります。

System.Xml.dll を追加

この状態でビルドをすると正常に完了します。

ビルド成功

難読化したアプリケーションを単独で問題なく起動することを確認できます。

アプリケーションを起動

ここで紹介した内容は少し裏技的な方法での回避策であるため、それなりに構築したアセンブリに対しても有効かどうかは保障できません。ビルドが成功して起動できたとしても特定の処理を実行したときに落ちてしまうという可能性も否めませんので、リリースする前にきちんと動作確認を行ってください。

今回の System.Xml 名前空間に限らずとも難読化は整合性を確実に保つようにしなければならない繊細な機能です。特にリフレクションを使う場合や、ファイル入出力・外部 API とのやりとりなどの I/O 関連には影響が出やすいので注意してください。