画像を含むWPFアプリを単一のファイルとして出力する（滅茶苦茶時間掛かった件）


Visual Studio 2022 .net7 C#(Csharp)で動作確認。

デメリットとして、内部でデータ解凍を行うために**初回起動がかなり遅くなる**。

自作のアプリ開発をしていてどーも「単一のexeファイル出力(make single exe file)」が上手くいかず、半年以上詰んでました。ひつじです。
作ったはいいものの、ファイルサイズは肥大化（設定次第で74MB~240MBにまで変化）、そもそも **ダブルクリックしても起動しない** という、途方に暮れてました。

質問してみてもやり方知ってる人も居ないんですよねぇ。。。（遠い目）


そこで、テストプロジェクトを作成し、実験してみました。

ソリューションエクスプローラーの右クリックメニューから「発行」です
![hakkkou.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145714/a37280c0-674a-b686-324f-19c27b1fb44e.png)


実際、単純なテストプロジェクトであれば難なくこれは行えることが分かりました。
出力場所を変えようと、TargetRuntimeや構成のCPUを変えるようと問題なく単一のexeとして出力出来ます。


 # 参考になったLink

https://scribble-note.com/2022/02/15/howtoloadfileresourcesofinproject/

https://web.archive.org/web/20230304031342/https://scribble-note.com/2022/02/15/howtoloadfileresourcesofinproject/

link先が消えたのでArcaiveを。

# 何が問題だったのか？
 ここで、テストプロジェクトに背景画像を設定してみました。
画像のビルドアクションを「コンテンツ」にしてビルドすると、 **単一のexeを作成しても動作しない事**が分かりました。

![bandicam 2023-11-23 16-07-02-230_Harua.mp4.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145714/4a68d035-1740-ad94-0a14-fc304924ec73.gif)


正解は <font color="red">　対象の画像の**ビルドアクションを「リソース」に替える**</font>ことです。ビルドに成功したら発行すれば良いという非常に単純な事でした。

![スクリーンショット 2023-11-23 194844.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145714/c635d1fc-0c10-3d4e-8a15-0feb745c15ec.png)


切り替え後に「ソリューションのクリーン」を行う必要があったことを付け加えておきます。


再度発行した結果。
![bandicam 2023-11-23 16-20-21-206_Harua.mp4.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145714/effab8c0-a380-7098-f4a2-b92e34f3d24b.gif)

※画像は頂きもので、このキャラクターを使用したアプリ開発を行っています。

出力されるファイルサイズが大幅に削減され、フォイル数も7個程度まで減らす事が出来ました。
自作のアプリではバイナリのサイズは24.2MBでした。元のサイズは251kbですが、十分許容範囲だと思われます。

![hikaku.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145714/04225892-006b-d254-3f3e-3677cf016eb4.png)


この件の教訓。　~~他人はあまり役に立たない~~
いいたか無いですがこの件のために半端じゃないぐらい色々試しています....



# dllファイルも内部に取り込める
これを実現するために数多くの記事を参照しましたが、**全てが無駄でした** そのような事をせずともdllは単一のexeとして格納されるようです。**上手く行きさえすれば。**



参考までに設定内容も付記しておきます。

デバッグシンボル　: PDBファイル、現在のプラットフォーム

※変更して発行しなおしても問題なかったので多分関係ない

アセンブリに署名する：チェック


サポートするOS　；　Windows7
![スクリーンショット 2023-11-23 165740.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/145714/568f8543-f7a0-71ac-83a3-79808a6838b9.png)

    

# 試してみて全くの無駄だったもの
ChatGPTの回答。
 <loadFromRemoteSources enabled="true"/> 

以下はプローブを使用するという方法です

https://qiita.com/float-on-mk-9/items/166ccb7a1fed53783a0e

 App.Config　作成　→
 ```Cs
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <probing privatePath="dll" />
    </assemblyBinding>
  </runtime>
```


改めて検証しましたが、
1.Visual Studio 2022では”アプリ名”+exe.Configが作成されない
→無効になっている？
2.”アプリ名”+dll.Config　なら作成される
3.App.Configを作成して追加したり、ドラッグ&ドロップで当該のファイルを導入したりしてみた
結局、<probing privatePath="dll" />は動作していないようにしか見えず、defaultのprobe検索アルゴリズムが動作している模様。
→あるいは記述が間違っている？
→CodeBase要素を先に検索するとのこと

4.プロジェクト内にあるApp.Configや”アプリ名”+dll.Configを　”アプリ名”+exe.Configにリネームしてみた
→意味がないと判断せざる負えなかった


いずれにせよ、Visual Studio 2022では通用しない方法だと判断せざる負えず断念中。当該ファイル群ののビルドアクションも弄ってみましたが、意味は無かったです。

App.Xanl.csへの

 ```Cs:App.Xaml.cs
namespace HaruaConvert
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : Application
    {

        protected override void OnStartup(StartupEventArgs e)
        {

            //    string exeDir = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
            //    string dllDir = Path.Combine(exeDir, "dll");


            //    try
            //    {
            //        string[] fileList = Directory.GetFiles(dllDir);

            //        foreach (string file in fileList)
            //        {
            //            if (Path.GetExtension(file).Equals(".dll", StringComparison.OrdinalIgnoreCase))
            //            {
            //                Assembly.LoadFrom(file);

            //            }
            //        }
            //    }
            //    catch (Exception ex)
            //    {
            //        // 例外処理: ファイルの読み込みやアセンブリのロードに関するエラーが発生した場合の処理
            //        Console.WriteLine($"Error loading assemblies: {ex.Message}");
            //    }
            //}

        }

    }
}

 
 ```

一部をChatGPTに手直ししてもらったもの。
なんていうかいかにも意味ありげに見えるのが曲者なんですよねぇ



# この件に関しての追加調査
.Net5から<probing privatePath="..." /> doesn't work in .Net 5.0 と報告されている。

https://github.com/dotnet/runtime/issues/45342

必要ならCromeでも使って翻訳して読んでみて欲しい。
一応Web魚拓を取得しておいた。
要するに.Net 5.0以降、<probing privatePathは使えない。らしい。

この事から、2020/11/11(.net5.0 のリリース日)以前の単一ファイルを出力するTips系の記事は**Visual Studio2022において全く使用できない**と結論付ける事が出来ます。了

# 初回起動がかなり遅くなる

単一のEXEとして出力するとファイルサイズが肥大化するだけでなく、**初回起動がかなり遅くなる**ということが判明してます（私のはるあこんばーた https://sheephuman.hatenablog.com/entry/HaruaConvert ）で30秒ぐらいかかる。内部で解凍処理をするためらしいですね。
それ以降の起動に時間はかからないようですので、まあそこまでデメリットではないかなとは感じました。たぶん。