はじめに
Visual Studio 2026を使っています。
GUIは使用しませんがフォームアプリケーションを使います。

手順
コンポーネントの追加
ツールボックスから NotifyIcon と ContextMenuStrip をフォームにドラッグ&ドロップします。
コンポーネントの設定
notifyIcon1
Icon: 好きな.icoファイルを選択。(これがないと表示されません)ContextMenuStrip:contextMenuStrip1を選択。Visible:true(おそらくdefaultでtrueになっている)Text: アプリ名(マウスホバー時に表示されます)。

contextMenuStrip1
- 項目を追加:「終了」は必須。これがないと終了できません。


- イベントハンドラの作成:「終了」をダブルクリックで作成。
private void 終了ToolStripMenuItem_Clic(object sender, EventArgs e)
{
// タスクトレイのアイコンを明示的に非表示にする(これをしないと終了後もアイコンが残ることがあります)
notifyIcon1.Visible = false;
// プロセスを完全に終了させる
Application.Exit();
}
Form1.csの書き換え
先ほどのイベントハンドラも含まれます。
namespaceは各自のプロジェクト名になります。
using System;
using System.Windows.Forms;
namespace background_app
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
// 1. プロパティでも設定可能ですが、念のためコードでも指定
this.ShowInTaskbar = false; // タスクバーに表示しない
this.WindowState = FormWindowState.Minimized; // 最小化状態で起動
}
// 起動時にフォームを一瞬も表示させないための核心部分
protected override void SetVisibleCore(bool value)
{
if (!this.IsHandleCreated)
{
value = false;
CreateHandle();
}
base.SetVisibleCore(value);
}
// コンテキストメニュー:終了(ここがご要望のポイントです)
private void 終了ToolStripMenuItem_Click(object sender, EventArgs e)
{
// タスクトレイのアイコンを明示的に非表示にする(これをしないと終了後もアイコンが残ることがあります)
notifyIcon1.Visible = false;
// プロセスを完全に終了させる
Application.Exit();
}
}
}
2重起動の禁止
Program.csを書き換える。
using System;
using System.Threading;
using System.Windows.Forms;
namespace background_app
{
internal static class Program
{
private static Mutex mutex = null;
private const string MutexName = "background_app_singleton_mutex";
/// <summary>
/// アプリケーションのメイン エントリ ポイントです。
/// </summary>
[STAThread]
static void Main()
{
bool createdNew = false;
mutex = new Mutex(true, MutexName, out createdNew);
if (!createdNew)
{
// アプリケーションが既に起動している場合
MessageBox.Show(
"このアプリケーションは既に実行中です。",
"アプリケーション警告",
MessageBoxButtons.OK,
MessageBoxIcon.Warning
);
return;
}
try
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
finally
{
if (mutex != null)
{
// 自分が Mutex を新規作成(所有)した時だけ解放する
if (createdNew)
{
mutex.ReleaseMutex();
}
mutex.Dispose();
}
}
}
}
}