LoginSignup
44
49

More than 5 years have passed since last update.

WPFで実行ファイルとDLLを一つにまとめる(C#編)

Last updated at Posted at 2014-10-16

その1 プロジェクトファイルにコマンドを追加

C#プロジェクトファイルの

<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets"/>

のあとに以下の文字列を挿入します

<Target Name="AfterResolveReferences">
  <ItemGroup>
    <EmbeddedResource Include="@(ReferenceCopyLocalPaths)" Condition="'%(ReferenceCopyLocalPaths.Extension)' == '.dll'">
      <LogicalName>%(ReferenceCopyLocalPaths.DestinationSubDirectory)%(ReferenceCopyLocalPaths.Filename)%(ReferenceCopyLocalPaths.Extension)</LogicalName>
    </EmbeddedResource>
  </ItemGroup>
</Target>

その2 EXEからアセンブリをロードするコードを追加

以下のコードをソースファイルにしてプロジェクトに追加してください。

startup.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.IO;

namespace StartUpCode //名前空間は使いやすいものに変えてください
{
    public class StartUp
    {
        [STAThread]
        public static void Main()
        {
            AppDomain.CurrentDomain.AssemblyResolve += OnResolveAssembly;

            App.Main(); // Run WPF startup code.
        }

        private static Assembly OnResolveAssembly(object sender, ResolveEventArgs e)
        {
            var thisAssembly = Assembly.GetExecutingAssembly();

            // Get the Name of the AssemblyFile
            var assemblyName = new AssemblyName(e.Name);
            var dllName = assemblyName.Name + ".dll";

            // Load from Embedded Resources - This function is not called if the Assembly is already
            // in the same folder as the app.
            var resources = thisAssembly.GetManifestResourceNames().Where(s => s.EndsWith(dllName));
            if (resources.Any())
            {

                // 99% of cases will only have one matching item, but if you don't,
                // you will have to change the logic to handle those cases.
                var resourceName = resources.First();
                using (var stream = thisAssembly.GetManifestResourceStream(resourceName))
                {
                    if (stream == null) return null;
                    var block = new byte[stream.Length];

                    // Safely try to load the assembly.
                    try
                    {
                        stream.Read(block, 0, block.Length);
                        return Assembly.Load(block);
                    }
                    catch (IOException)
                    {
                        return null;
                    }
                    catch (BadImageFormatException)
                    {
                        return null;
                    }
                }
            }
            // in the case the resource doesn't exist, return null.
            return null;
        }
    }
}

その3 プロジェクト設定を変更

プロジェクト設定を変更して、スタートアップオブジェクトをその2で追加したソースに変更する。
すべて終了したらビルドすればEXE単独で起動できるようになります。

ただし、WPFToolkitのグラフのようにDLLからDLLの関数を呼んでいたりすると動かない場合があるので100%とはいきませんが99%くらいはこれでいけます。

WPFプロジェクトじゃなくても使えるので意外に便利です。

今回の記事は次のサイトの日本語訳だったりする
http://blogs.interknowlogy.com/2011/07/13/merging-a-wpf-application-into-a-single-exe/

44
49
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
44
49