코드 작성 중 모든 예외를 다 처리할 수는 없을 것이다.


예상치 못한 예외가 발생했을 때 알 수 있도록 메시지로 출력되도록 할 수 있다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
static void Main()
{
    Application.ThreadException += Application_ThreadException;
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Application.Run(new MainForm());
}
 
private static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
{
    MessageBox.Show($"{e.Exception.Message}{Constants.HardCoding.lineDivision}{e.Exception.StackTrace}",
                     Constants.HardCoding.messageCaption, MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
 
cs


Application.ThreadException  이벤트를 추가하고 그 안에 메시지를 출력하는 코드를 작성하면 된다.

프로그램 실행 시 폼이 출력 안되고 트레이 아이콘만 출력되게 해야할 경우가 있다.


그래서 처음에 시도해본 방법이


폼 생성되었을 때 Visible 값을 fasle로 하였는데 이렇게 했음에도 그대로 화면이 출력 되었다.(opacity = 0 으로 하는 방법도 있으나 이 방법은 제외 하였다.)


찾아보니 Visible 속성이 매우 중요한 속성이라 하면서 실제로는 OnLoad()가 실행된다고 한다.


그래서 Visible 속성을 아무리 바꾸려는 시도가 무시된다고 한다.



그래서 찾아보니 SetVisibleCore 를 사용하여 폼 출력 안되게 하였다.


문제는 이렇게 하니 종료할 때 아래의 동작이 한번 더 되는 문제가 발생하였다. 찾다보면 해결 방법이 있겠지만 잠시 테스트 해본거라 아


직은 모르겠다.


1
2
3
4
protected override void SetVisibleCore(bool value)
{
    base.SetVisibleCore(value);
}
cs



그 다음에 찾아보고 적용한게 기존의 메인폼을 뒤로 두고 새로 만들 폼을 메인으로 만드는 방법이다.


ApplicationContext를 상속 받는 클래스를 만들고 그 클래스를 메인으로 두면 된다.


그리고 나서 새로 만든 클래스에서 트레이 아이콘이나 컨텍스트 메뉴를 추가 하고 옵션으로 기존 메인폼을 보여주게 하면 된다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class TraySample : ApplicationContext
{
    public TraySample()
    {
        // 알림 영역에서의 아이콘의 값들을 설정합니다.
        notifyIcon.Visible = true;
        notifyIcon.Icon = null;
        notifyIcon.ContextMenuStrip.Items.Add("Show");
        notifyIcon.ContextMenuStrip.Items.Add("Exit");
 
        // 이벤트를 생성합니다.
        notifyIcon.ContextMenuStrip.ItemClicked += ContextMenuStrip_ItemClicked;
    }
 
    NotifyIcon notifyIcon = new NotifyIcon();
}
cs


중복 실행 방지 2가지 방법


생성된 실행파일을 반복해서 실행하니까 실행 시키는 족족 계속 프로그램이 열립니다.


이럴 필요까지는 없는데 말이죠...


찾아보니 어려운 내용들도 아닙니다. 4가지 정도 있던데 그 중 두개만 테스트 해보고, 첫번째 것을 적용 했습니다.



1. 프로세스를 가져와서 프로세스의 이름으로 중복 실행을 방지합니다.


같은 이름의 프로세스 이름이 2개 이상 있으면 경고 메시지 출력 되게 하였습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
static void Main()
{
    Process[] procs = Process.GetProcessesByName("실행될 프로세스 이름");
    // 두번 이상 실행되었을 때 처리할 내용을 작성합니다.
    if (procs.Length > 1)
    {
        MessageBox.Show("프로그램이 이미 실행되고 있습니다.\n다시 한번 확인해주시기 바랍니다.");
        return;
    }
    // 정상 동작 될 내용을 작성하면 됩니다.
    else
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());
    }
}
cs


2. Mutex 사용


특정 코드, 특정 자원에 대해 동시 접근을 차단하고 한번에 하나의 쓰레드만 수행하도록 하는 것이 뮤텍스라 한다 합니다.


그래서 아래의 코드 처럼 작성해보니 진짜 동시 실행이 안됩니다.


그냥 느낌상 뮤텍스는 안끌려서 저는 프로세스 이름 검색하는 걸로 중복 실행 방지 했습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    bool createdNew;
    // mutex 객체 생성합니다. 아래와 같이 생성해두면 된다.
    Mutex mutex = new Mutex(true"프로그램 이름"out createdNew);
    if (createdNew)
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new TrayApplication());
        mutex.ReleaseMutex();
    }
    else
    {
        MessageBox.Show("프로그램이 이미 실행되고 있습니다.");
        return;
    }
cs


TextBox나 NumericUpDown 에서 간혹 양수만 입력 받아야 할 때가 있다.


디자이너에서는 기본값이 0 ~ 100까지 위아래 화살표로 입력 받을 수 있도록 되어 있지만


키보드로 입력 시에는 -가 입력이 된다.


-키를 입력 받지 못하게 하려면 아래와 같이 작성해두면 된다.


1
2
3
4
5
6
7
private void NumericUpDown1_KeyPress(object sender, KeyPressEventArgs e)
{
    if (e.KeyChar == '-')
    {
        e.Handled = true;
    }
}
cs


보통 폼의 'x' 표시를 누르게 되면 프로그램이 종료 된다.


그런데 간혹 폼을 종료하지 않고 화면을 사라지게 한다던가 최소화를 시켜야 할 때가 있다.


우선 아래와 같은 방법으로 폼을 사라지게 하지 않게 한다.


1
2
3
4
5
6
7
8
9
#region MainForm_FormClosing
/// <summary>
/// 폼이 닫히기 전에 발생합니다.
/// </summary>
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
    e.Cancel = true;
}
#endregion
cs


이렇게 하면 폼에서 'x' 눌러도 종료가 되지 않고 최소화가 된다.


그리고 종료를 할 때는 트레이 아이콘에서 컨텍스트메뉴를 띄워 종료를 할 수 있게 만들었다.


문제는 저렇게 만들었을 때 문제가 발생했는데 최소화를 시킨 다음에 종료를 시켰음에도 프로그램 종료가 되지 않았다.


그래서 어떻게 하나 찾아보니 두가지 방법이 나오는데


첫번째는 아래와 같이 Close 사유를 명시해주는 것인데 CloseReason이 UserClosing가 된다. 이렇게 수정을 하니 바로 종료가 된다.


1
2
3
4
5
6
7
8
9
10
11
12
13
#region MainForm_FormClosing
/// <summary>
/// 폼이 닫히기 전에 발생합니다.
/// </summary>
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
    // 'X' 눌렀을 때 Form이 사라지고, 작업표시줄이 사라집니다.
if (e.CloseReason == CloseReason.UserClosing)
    {
        e.Cancel = true;
    }
}
#endregion
cs



두번째로는 전역변수로 isClose bool 변수를 하나 만들고 isClose 가 false 일 때만 동작되도록 만들면 된다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
bool isClose = false;

#region MainForm_FormClosing
/// <summary>
/// 폼이 닫히기 전에 발생합니다.
/// </summary>
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
    if (this.isClose == false)            
    {
        e.Cancel = true;
        this.Visible = false;
        this.ShowInTaskbar = false;
    }
}
#endregion
cs


둘 다 테스트 했을 때 동작이 되었는데 아무래도 첫번째 것이 더 직관적이기에 쓰는게 좋지 않을까 싶다.

+ Recent posts