C# 에서 정상적으로 프로그램이 종료되면 Tray 아이콘이 제거 되긴 합니다만,
프로세스 킬, 비정상적인 종료 방법이라면 위와 같이 트레이 아이콘이 남는 경우가 있습니다.
해당 아이콘은 mouse hover 이벤트 시 윈도우 내부적으로 해당 프로그램이 동작하고 있는지 판별하기에
mouse move 이벤트를 통해 해당 tray들을 정리할 수 있습니다. 아래는 코드!
[생성, 정리 후]
![]() |
![]() |
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
class TrayRefresher
{
[StructLayout(LayoutKind.Sequential)]
struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
[DllImport("user32.dll")]
static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowName);
[DllImport("user32.dll")]
static extern bool GetWindowRect(IntPtr hWnd, out RECT rect);
[DllImport("user32.dll")]
static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
const int WM_MOUSEMOVE = 0x0200;
public void RefreshTray()
{
/*
Shell_TrayWnd (하단의 작업 표시줄)
├─ TrayNotifyWnd (시스템 트레이 영역 - 시계, 네트워크 아이콘, 볼륨 조절 등)
│ └─ SysPager (아이콘을 스크롤하거나 관리)
│ └─ ToolbarWindow32 (보이는 트레이 아이콘들)
│
└─ NotifyIconOverflowWindow (숨겨진 아이콘 영역) - 숨기기/펼치기 영역
└─ ToolbarWindow32 (숨겨진 아이콘들)
*/
//보여지는 영역
IntPtr toolbar = FindToolbar("Shell_TrayWnd", "TrayNotifyWnd", "SysPager", "ToolbarWindow32");
SendMouseMove(toolbar);
//감춰진 영역도 추가
toolbar = FindToolbar("NotifyIconOverflowWindow", "ToolbarWindow32");
SendMouseMove(toolbar);
}
private IntPtr FindToolbar(params string[] targets)
{
IntPtr hWnd = IntPtr.Zero;
foreach (string target in targets)
{
hWnd = FindWindowEx(hWnd, IntPtr.Zero, target, null);
if (hWnd == null)
{
break;
}
}
return hWnd;
}
private void SendMouseMove(IntPtr hWnd)
{
if (hWnd == null)
{
return;
}
if (GetWindowRect(hWnd, out RECT rect))
{
int width = rect.Right - rect.Left;
int height = rect.Bottom - rect.Top;
int offset = 5; //아이콘 간격
for (int x = 0; x < width; x += offset)
{
for (int y = 0; y < height; y += offset)
{
//4byte lParam에 2byte씩 마우스 위치를 넣어줍니다.
//mouse y 2byte, mouse x 2byte
IntPtr lParam = (IntPtr)((y << 16) | (x & 0xFFFF));
SendMessage(hWnd, WM_MOUSEMOVE, IntPtr.Zero, lParam);
}
}
}
}
}
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Task.Run(async () => //테스트용 트레이 아이콘 생성!
{
//테스트용 프로그램
Process process = Process.Start(@"...\trayTest.exe");
await Task.Delay(1000);
process.Kill(); //강제 종료 시 트레이 아이콘이 남습니다.
});
}
private void button2_Click(object sender, EventArgs e)
{
new TrayRefresher().RefreshTray(); //트레이 아이콘 정리!
}
}
}
'C# > Windows Form' 카테고리의 다른 글
[C# Windows Form] Drag & Drop 기능 사용하기 (파일, 폴더 불러오기) (1) | 2025.08.15 |
---|---|
[C# Windows Form] Win32 API EnumWindows 를 사용한 프로그램 타이틀 가져오기 (웹 브라우저 따라다니기) (1) | 2025.07.28 |
[C# Windows Form] 프로그램 Tray 아이콘 만들기, 감추기 (0) | 2025.07.16 |
[C# Window Forms] App.config, appsettings.json 파일 값 저장 (0) | 2025.06.25 |
[C# Windows Form] 32bit 프로그램 메모리 사용량 늘리기 (editbin.exe) (0) | 2025.05.29 |