C#でWindowsフォームアプリのexeにdllを組み込む

# はじめに
Windowsアプリケーションを作成していると、いつの間にかdllファイルだけで2～3スクロールするようになってしまった。

なんとなく１つにまとめたい。

### 参考にしたサイト

その昔（遥か昔）できなかった事ができるようになっていた。

https://learn.microsoft.com/ja-jp/dotnet/core/deploying/single-file/overview?tabs=cli

# 環境

* .NET 8
* Visual Studio 2022
* C#

# プロジェクトの作成

Visual Studioで**Windows フォーム アプリ**を選択し.NET8を選択する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/119455/75a11d78-5b16-42ce-2d4f-f83d4ea75f5f.png)

dllがまとまるのを見たかったのでNuGetよりNLogをインストール。
デバッグでビルドすると以下の出力内容となる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/119455/f9d3f0eb-fdb9-4c16-bf12-fa6aa5b8af8b.png)

# 単一アプリにする方法

ソリューションを右クリックし**発行**を選択し、実行プロファイルを作成。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/119455/5643dbe8-76fb-2330-492a-c4d7112d9163.png)

## 実行プロファイルを作成する

手順は以下の通り

1. **ターゲット**でフォルダーを選択
2. **特定のターゲット**でフォルダーを選択
3. **場所は**デフォルト

実行プロファイルの作成が完了すると**公開準備が完了しました**となり発行可能となります。

ここで**すべての設定を表示**を選択しプロファイル設定を変更します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/119455/9f493faf-ac3c-2578-4549-5ab0e769ec24.png)

### 変更箇所

1. 配置モードを自己完結
1. ファイルの公開オプションで単一ファイルの作成にチェック


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/119455/6c1fcc64-6869-6882-aeaf-4904ddccfbc9.png)

設定完了後、発行ボタンを実行すると指定フォルダの中にexeが作成されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/119455/dd4e1207-984f-b7a4-391d-86c74f043497.png)

実際に出力された中身。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/119455/f3242d6c-d972-db9c-0134-87b4640ae5be.png)

単一ファイルの作成とありましたが、この設定だけでは完全にまとめきれないようなのでIncludeNativeLibrariesForSelfExtractプロパティを指定します。

# 設定方法

ソリューションのWinformsApp1をダブルクリックし、WinFormsApp1.csprojを開きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/119455/d52cf6b4-39d7-f0c9-559a-5408ee48616a.png)

PropertyGroupにIncludeNativeLibrariesForSelfExtractプロパティを追加しTrueを指定します。

``` WinFormsApp1.csproj

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net8.0-windows</TargetFramework>
    <Nullable>enable</Nullable>
    <UseWindowsForms>true</UseWindowsForms>
    <ImplicitUsings>enable</ImplicitUsings>
	<IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="NLog" Version="5.3.2" />
  </ItemGroup>

</Project>

```

これで組み込むことができましたが、発行されたexeは**初期状態で140MB**近くあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/119455/fd456813-def4-93dd-3ea6-8dea077d7164.png)

# 圧縮してみる

単一ファイルアプリケーションを圧縮する方法はEnableCompressionInSingleFileプロパティをtrueに設定することで圧縮する事が可能です。

``` WinFormsApp1.csproj

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net8.0-windows</TargetFramework>
    <Nullable>enable</Nullable>
    <UseWindowsForms>true</UseWindowsForms>
    <ImplicitUsings>enable</ImplicitUsings>
	<IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
    <EnableCompressionInSingleFile>true</EnableCompressionInSingleFile>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="NLog" Version="5.3.2" />
  </ItemGroup>

</Project>

```

公式ドキュメントに**圧縮にはパフォーマンス コストが伴います。 アプリケーションの起動時に、アセンブリをメモリに展開する必要があり、この処理に時間がかかります。** とありますが、ハローワールドレベルのプログラムだと体感では分かりにくいレベルでした。

また、圧縮に関しては140MBだったものが64MBにまで圧縮されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/119455/cc415fa9-83c5-ae37-204d-ad768ba1b895.png)

# メモリ消費について
起動時、無圧縮（141MBの方）はメモリを20MB程度利用するのに対し、圧縮版（64MB）では70MB消費していました。
圧縮しているので展開にメモリを要するのかと思いますが、メモリを消費するアプリケーションを作成する場合は圧縮しない方が良いかもしれません。