C# - Windows常駐アプリ(タスクトレイ) - Form表示なし

# 1. タスクトレイ（タスクバー）にアイコンを置く

## 1-1. サンプルコード

このままのプログラムだと何も役には立たない。
使い道としては、外部exeを実行したりするとか。

```cs

using System;
using System.ComponentModel; // CancelEventArgsを使用するため
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;


static class MyIconUtil
{
    static class NativeMethods
    {
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public extern static bool DestroyIcon(IntPtr handle);
    }

    public static Icon Create16x16Icon(string[] iconDot)
    {
        Bitmap bmp = new Bitmap(16,16);
        using ( Graphics g = Graphics.FromImage(bmp) ) {
            g.Clear(Color.White);
        }
        for(int y=0;y<16;y++){
            for(int x=0;x<16;x++){
                if (iconDot[y][x]=='#') {
                    bmp.SetPixel(x,y,Color.Black);
                }
            }
        }

        IntPtr Hicon = bmp.GetHicon();
        return Icon.FromHandle(Hicon);
    }

    public static void DestroyIcon(Icon icon)
    {
        NativeMethods.DestroyIcon(icon.Handle);
    }
}


class TaskTrayTest
{
    static string[] iconDot = new string[]{
        "................",
        ".###...##...##..",
        "..#...#..#.#..#.",
        "..#...#....#..#.",
        "..#...#....#..#.",
        "..#...#....#..#.",
        "..#...#....#..#.",
        "..#...#....#..#.",
        "..#...#....#..#.",
        "..#...#....#..#.",
        "..#...#....#..#.",
        "..#...#....#..#.",
        "..#...#....#..#.",
        "..#...#..#.#..#.",
        ".###...##...##..",
        "................",
    };


    TaskTrayTest()
    {
        //this.ShowInTaskbar = false; // TaskTrayTestがFormを継承する場合はコメントアウトを外す

        NotifyIcon trayIcon = new NotifyIcon();

        //trayIcon.Icon = new Icon("hogehoge.ico"); // 何かしらのアイコンを設定しないとタスクトレイに表示されない
        Icon tmpIcon = MyIconUtil.Create16x16Icon(iconDot);
        trayIcon.Icon = tmpIcon;
        trayIcon.Visible = true;
        // MyIconUtil.DestroyIcon(tmpIcon);

        trayIcon.Text = "常駐テスト";
        var menu = new ContextMenuStrip();

        menu.Items.AddRange(new ToolStripMenuItem[]{
            new ToolStripMenuItem("&Open", null, (s,e)=>{MyDoSomething();}, "Open"),
            new ToolStripMenuItem("E&xit", null, (s,e)=>{MyExit();}, "Exit")
        });

        trayIcon.DoubleClick += (s,e)=>{MyDoSomething();};
        trayIcon.ContextMenuStrip = menu;
    }

    void MyDoSomething()
    {
        Console.WriteLine("MyDoSomething is called.");
    }

    void MyExit()
    {
        var e = new CancelEventArgs();
        Application.Exit(e);
        if (e.Cancel) {
            Console.WriteLine("Application.Exit is canceled.");
        }
    }
  
    [STAThread]
    static void Main(string[] args)
    {
        Console.WriteLine("Main() Start.");
        new TaskTrayTest();
        Console.WriteLine("Instance is created.");
        Application.Run();
        Console.WriteLine("Main() End.");
    }
}
```

## 1-2. 説明

- `NotifyIcon`が、タスクトレイにアイコンを表示させるためのクラス([Microsoft Docs参照](https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.notifyicon?view=netframework-4.8)[^1])。
このクラスのメンバが`WndProc`を持っていて、メッセージループを処理してイベントを処理しているようである。(ILSpyで見た感じでは。)
- `Application.Run()`が、プログラムが終了しないようにしている。NotifyIconとApplication.Runのループがやりとりしているのかはよくわからない。。
([Application.Run() - Microsoft Docs](https://docs.microsoft.com/ja-jp/dotnet/api/system.windows.forms.application.run?view=netframework-4.8#System_Windows_Forms_Application_Run))

■気を付けるべきこと
- タスクトレイからFormを表示させたりする場合は、アプリの終了のさせ方に気を付ける必要がありそう。参考サイト3参照。


## 1-3. 参考サイト

1. [C#: タスクトレイに常駐するアプリの作り方 ](http://pineplanter.moo.jp/non-it-salaryman/2017/06/01/c-sharp-tasktray/)
2. [フォームを表示させずにトレイアイコンを表示する - dobon.net](https://dobon.net/vb/dotnet/form/hideformwithtrayicon.html#section3)
3. [アプリケーション（自分自身）を終了させる - dobon.net](https://dobon.net/vb/dotnet/programing/applicationexit.html)
4. [通知領域のアイコン情報のレジストリについて](https://answers.microsoft.com/ja-jp/windows/forum/all/通知領域の/e0ad4223-e9a7-496a-ba12-db3aa7f47e90)

## 1-4. アイコン

アイコンを準備する必要があるので、それ用のソフトを持っていない・フリーソフトを入れたくない場合は、手前味噌ですが下記あたりで適当に対応ください。
- [C# - ちょー雑な方法でFormのアイコンを生成する (Windows)](https://qiita.com/kob58im/items/850da88ebed27c05022a)
- [C#で、文字と図形からなるWindowsアイコン(.Ico)【透過】を作成するプログラムを作ってみた](https://qiita.com/kob58im/items/6f319988e3cdb745cf88)
- [C#で画像からWindowsアイコン(.ico)に変換するソフトつくった - 透過対応](https://qiita.com/kob58im/items/1d3420b51ff6cb5c3871)


# 2. スタートアップへの登録

## 2-1. 参考サイト

まだ試せていない
[[C#] スタートアップメニューにショートカットを登録する方法](https://www.osadasoft.com/c-スタートアップメニューにショートカットを登/)

# 3. 多重起動の防止

まだ試せていない。Mutexを使うらしい。

https://dobon.net/vb/dotnet/process/checkprevinstance.html

# 4. タスクバーの常時表示領域に置く設定方法（※手作業）

2020.10.31追記しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/438183/434ea1de-837d-218f-832c-a5887d89d42c.png)




[^1]: 日本語版は機械翻訳が酷かったので英語のほうにしてます。