제가 생각할때는 귀신같은 증상..

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Skin
{
    public partial class BaseForms : Form
    {
        private static NotifyIcon commonNotifyIcon; // 공통 NotifyIcon
        private static List<NotifyIcon> notifyIcons = new List<NotifyIcon>();
        protected NotifyIcon notifyIcon;
        private ContextMenuStrip contextMenu;
        protected bool IsLoggedIn { get; set; } = false; // 기본값은 false

        public BaseForms()
        {
            InitializeComponent();
            InitializeNotifyIcon();
            ShowInTaskbar = false;
            this.Resize += BaseForm_Resize;            
        }

        protected void InitializeNotifyIcon()
        {
            if (commonNotifyIcon == null) // 공통 NotifyIcon이 없을 경우에만 생성
            {
                commonNotifyIcon = new NotifyIcon
                {
                    Visible = true,
                    Icon = Properties.Resources.AutoIcon
                };

                contextMenu = new ContextMenuStrip();
                var exitMenuItem = new ToolStripMenuItem("종료");
                exitMenuItem.Click += ExitMenuItem_Click;
                contextMenu.Items.Add(exitMenuItem);
                commonNotifyIcon.ContextMenuStrip = contextMenu;
            }
        }

        private void BaseForm_Resize(object sender, EventArgs e)
        {
            // 폼이 최소화되면 트레이로 숨기기
            if (this.WindowState == FormWindowState.Minimized)
            {
                this.Hide(); // 폼을 숨김
            }
        }

        private void ExitMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                // 모든 NotifyIcon 숨기기
                foreach (var notifyIcon in notifyIcons.ToList())
                {
                    notifyIcon.Visible = false;
                    notifyIcon.Dispose();
                }
                notifyIcons.Clear();

                // 공통 NotifyIcon 숨기기
                if (commonNotifyIcon != null)
                {
                    commonNotifyIcon.Visible = false;
                    commonNotifyIcon.Dispose();
                    commonNotifyIcon = null;
                }

                // 모든 열린 폼을 닫기
                foreach (var form in Application.OpenForms.OfType<Form>().ToList())
                {
                    form.Hide(); // 폼을 숨김
                }

                Application.Exit(); // 애플리케이션 종료
            }
            catch (Exception ex)
            {
                // 예외 로깅
                File.AppendAllText("error_log.txt", $"{DateTime.Now}: {ex.Message}\n{ex.StackTrace}");
            }
        }

    }
}

위는 베이스폼을 새로 만들었구요. 자질구레한 코드는 일단 제외해놓은 상태고 문제의 notifyIcon 코드 입니다.

위 폼의 디자이너.cs 파일은 아래와 같구요.

using System.Windows.Forms;

namespace Skin
{
    partial class BaseForms : Form
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
            if (commonNotifyIcon != null)
            {
                commonNotifyIcon.Visible = false;
                commonNotifyIcon.Dispose();
                commonNotifyIcon = null;
            }
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(800, 450);
            this.Text = "Form1";
        }

        #endregion
    }
}

예를들어서…!!
다른 폼에서

namespace Skin
{
    public partial class Skin : BaseForms

이런식으로 해당 폼을 상속받으면, 프로그램 자체는 뭐 크게 문제없이 잘 돌아갑니다.

그런데… 그런데!!!

비주얼스튜디오 2022로 작업을 하고있는데…

상속을 받은 Skin 폼을 디자이너뷰로 클릭하는순간!

갑자기 트레이에 아이콘이 생기고…
어 이거 뭐지? 하고 우클릭 종료를 하면 비주얼스튜디오가 종료되요…
이 증상을 설명할수있게 찾아내고 특정짓는데만 며칠이 걸렸습니다…

요약하면,
프로그램을 만드는데, 위 베이스폼을 상속받는 폼의 디자인을 비주얼 스튜디오로 보기만 해도, 탭을 클릭만해도, 갑자기 트레이에 프로그램의 아이콘이 생기고 해당 아이콘을 우클릭 종료하면 비주얼스튜디오가 종료됩니다…

살려주실분… 왜이런지… 뭘 잘못했는지 모르겠어요…

초보입장에서는 귀신이 곡할 노릇같이만 보입니다…

원래 vs에서 디자인 모드에서도
해당 클래스의 생성자가 호출 됩니다.
그것을 방지 하기 위해 DesignMode 속성이 있습니다.

Component.DesignMode 속성 (System.ComponentModel) | Microsoft Learn

이런 현상을 방지 하기 위해 생성자에서 DesignMode 속성으로 디자인 모드인지 분기해서 처리 하곤 합니다.

if(Component.DesignMode) {
    return;
}

따라서 vs의 디자인이 열리고,
해당 폼의 생성자가 호출되고,
해당 생성자에서 호출하는 InitializeNotifyIcon() 메서드 호출
인해 트레이아이콘이 생성 되된 것 입니다.

해당 트레이 아이콘을 종료 했을땐 윈도우 핸들이 비주얼스튜디오 핸들로 처리 되어 vs가 종료 된 것이 아닌가 추측 됩니다.

6 Likes

제가 또 기본적인걸 안지킨 질문을 했네요ㅠ_ㅠ

닷넷 4.8. C#. 사용하고 있습니다!

주신 코드로 여기저기 들쑤셔서


protected bool IsInDesignMode()
{
    return LicenseManager.UsageMode == LicenseUsageMode.Designtime ||
           (System.Diagnostics.Process.GetCurrentProcess().ProcessName == "devenv" &&
           !System.Diagnostics.Debugger.IsAttached);
}

protected override void OnLoad(EventArgs e)
{
    base.OnLoad(e);

    if (!IsInDesignMode())
    {
        InitializeNotifyIcon();
    }
}

protected void InitializeNotifyIcon()
{
    if (!IsInDesignMode())
    {
        if (commonNotifyIcon == null)
        {
            commonNotifyIcon = new NotifyIcon
            {
                Visible = true,
                Icon = Properties.Resources.AutoIcon
            };

            commonNotifyIcon.DoubleClick += NotifyIcon_DoubleClick;

            contextMenu = new ContextMenuStrip();
            var exitMenuItem = new ToolStripMenuItem("종료");
            exitMenuItem.Click += ExitMenuItem_Click;
            contextMenu.Items.Add(exitMenuItem);
            commonNotifyIcon.ContextMenuStrip = contextMenu;
        }
    }
}

요렇게 했더니 오우 문제가 해결되었네요.

저는 이 증상이 진짜… 와 이게 말이 되나 싶을정도로 희한한 경험이라…

맨날 챗지피티랑 말싸움하면서 만드는데 이문제 때문에 진짜… 후…

정상적인 증상이었군요…! 감사합니다!!

인간(?)에게 답변들으니 신뢰가 갑니다! 고맙습니다!

3 Likes