반응형

입력 문자열 형식 에러 잡는 방법 두 가지를 알아보자.

Try-Catch 구문을 사용하거나 TryParse()를 사용할 수 있다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace CS
{
    using static System.Console;
 
    class Program
    {
        static void Main(string[] args)
        {
            int age;
            string ageText;
 
            Write("Enter your age: ");
            ageText = ReadLine();
 
            // Try-Catch
            try
            {
                age = int.Parse(ageText);
                WriteLine($"You are {age * 12} months old.");
            }
            catch (FormatException exc)
            {
                WriteLine($"The age entered, {ageText}, is not valid: {exc.Message}");
            }
            catch (Exception exc)
            {
                WriteLine($"Unexpected error: {exc.Message}");
            }
            finally
            {
                WriteLine("Goodbye.");
            }
 
            // TryParse()
            if (int.TryParse(ageText, out age))
            {
                WriteLine($"You are {age * 12} months old.");
            } else
            {
                WriteLine($"The age entered, {ageText}, is not valid.");
            }
        }
    }
}
 

 

소스를 입력하고 빌드한다.

 

실행하고 숫자를 입력하면 아무 문제없이 출력된다.

 

숫자가 아닌 문자가 입력되면 에러가 발생하고 잘 처리된다.

 

반응형
Posted by J-sean
:
반응형

유저 컨트롤(dll)을 만들고 사용해 보자.

 

Windows Forms Control Library 프로젝트를 만든다.

 

폼에 버튼과 레이블을 적당히 배치한다.

 

간단한 코드를 작성한다.

 

빌드하고 실행하면 컨트롤을 테스트하고 속성을 확인 할 수 있는 화면이 나타난다.

 

 

Output 폴더에 dll 파일이 생성 되었다.

 

이번엔 Windows Forms App 프로젝트를 만든다.

 

툴 박스에서 마우스 우클릭 - Choose Items... 를 선택한다.

 

Browse... 를 클릭한다.

 

 

위에서 만든 컨트롤 dll 파일을 선택한다.

 

유저 컨트롤이 추가 되었다. OK를 클릭한다.

 

툴 박스에 자동으로 등록된다.

 

마우스 우클릭 - Rename Item 으로 이름을 바꿀 수 있다.

 

 

폼에 적당히 배치한다.

 

추가 코드 작성 없이 빌드하고 실행하면 잘 작동한다.

실행 파일(exe)과 컨트롤 라이브러리 파일(dll)을 함께 배포해야 한다.

 

반응형
Posted by J-sean
:
반응형

C# 폼 디자이너에서 폼은 더블 버퍼링 속성을 적용할 수 있지만 대부분의 컨트롤은 더블 버퍼링 속성이 보이지 않는다.

컨트롤에 더블 버퍼링을 적용해 보자.

 

폼 속성에 있는 더블 버퍼링

 

폼에 PictureBox, Panel, Timer, Button을 적당히 배치한다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
 
namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        Bitmap myBitmap;
 
        public Form1()
        {
            InitializeComponent();
 
            timer1.Enabled = true;
            timer1.Interval = 100;
        }
 
        private void button1_Click(object sender, EventArgs e)
        {
            try
            {
                OpenFileDialog dlg = new OpenFileDialog();
                if (dlg.ShowDialog() == DialogResult.OK)
                {
                    myBitmap = new Bitmap(dlg.FileName);
                }
                dlg.Dispose();
            }
            catch (Exception exc)
            {
                MessageBox.Show(exc.Message);
            }
        }
 
        private void pictureBox1_Paint(object sender, PaintEventArgs e)
        {
            if (myBitmap != null)
            {
                e.Graphics.DrawImage(myBitmap, 00);
            }
        }
 
        private void panel1_Paint(object sender, PaintEventArgs e)
        {
            if (myBitmap != null)
            {
                e.Graphics.DrawImage(myBitmap, 00);
            }
        }
 
        private void timer1_Tick(object sender, EventArgs e)
        {
            pictureBox1.Invalidate();
            panel1.Invalidate();
        }
    }
}
 

 

소스를 입력하고 빌드한다.

 

실행하면 PictureBox는 깜빡이지 않지만 Panel에 그려진 이미지는 심하게 깜빡인다.

PictureBox는 기본적으로 더블 버퍼링이 적용되어 있다.

 

1
2
3
System.Reflection.PropertyInfo controlProperty = typeof(System.Windows.Forms.Control).GetProperty("DoubleBuffered",
    System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
Text = controlProperty.GetValue(pictureBox1).ToString();
 

 

위 명령어를 실행하면 타이틀 바에 True가 표시된다.

 

Panel 클래스를 상속하고 더블 버퍼링 속성을 적용한 클래스를 정의해 보자.

 

 

Panel 클래스를 상속하는 DoubleBufferedPanel 클래스를 정의한다.

DoubleBuffered 프로퍼티는 protected로 지정되어 있기 때문에 자식 클래스에서 접근이 가능하다.

protected virtual bool DoubleBuffered { get; set; }

 

디자이너 소스에서 DoubleBufferedPanel 클래스로 Panel 오브젝트를 생성하도록 수정한다.

다시 컴파일 하고 실행하면 Panel에 표시된 이미지도 더 이상 깜빡이지 않는다.

 

하지만 컴파일 에러는 없지만 폼 디자이너에서 위와 같은 에러가 발생한다.

The service System.Windows.Forms.Design.ISelectionUIService already exists in the service container. Parameter name: serviceType

 

이번엔 컨트롤에 더블 버퍼링을 적용할 수 있는 함수를 만들어 보자.

 

1
2
3
4
5
6
7
// This helper method will not turn on double buffering if the person is running in remote desktop.
public static void SetDoubleBuffering(System.Windows.Forms.Control control, bool value)
{
    System.Reflection.PropertyInfo controlProperty = typeof(System.Windows.Forms.Control).GetProperty("DoubleBuffered",
        System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
    controlProperty.SetValue(control, value, null);
}
 

 

DoubleBufferedPanel 클래스 관련 내용을 삭제하고 SetDoubleBuffering()을 정의한다.

생성자나 다른 필요한 곳에서 SetDoubleBuffering(panel1, true)와 같이 설정하면 컨트롤에 더블 버퍼링이 적용되고 폼 디자이너도 에러가 발생하지 않는다.

 

반응형
Posted by J-sean
:
반응형

시스템 정보를 모두 확인해 보자.

 

폼에 리스트 박스와 텍스트 박스를 적절히 배치한다.

텍스트 박스 속성

Multiline = True

ScrollBars = Vertical

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
 
using System.Reflection;
 
namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
 
            Type t = typeof(System.Windows.Forms.SystemInformation);
            PropertyInfo[] pi = t.GetProperties();
            for (int i = 0; i < pi.Length; i++)
                listBox1.Items.Add(pi[i].Name);
 
            textBox1.Text = "The SystemInformation class has " + pi.Length.ToString() + " properties.\r\n";
 
            // 한 가지 프로퍼티만 필요하다면 아래와 같이 알아낼 수 있다.
            //string propertyName = "CaptionHeight";
            //PropertyInfo propertyValue = t.GetProperty(propertyName);
            //textBox1.Text = "The value of the " + propertyName + " property is: " + propertyValue.GetValue(null, null).ToString();
        }
 
        private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            // Return if no list item is selected.
            if (listBox1.SelectedIndex == -1return;
            // Get the property name from the list item.
            string propname = listBox1.Text;
 
            if (propname == "PowerStatus")
            {
                // Cycle and display the values of each property of the PowerStatus property.
                textBox1.Text += "\r\nThe value of the PowerStatus property is:";
                Type t = typeof(System.Windows.Forms.PowerStatus);
                PropertyInfo[] pi = t.GetProperties();
                for (int i = 0; i < pi.Length; i++)
                {
                    object propval = pi[i].GetValue(SystemInformation.PowerStatus, null);
                    textBox1.Text += "\r\n    PowerStatus." + pi[i].Name + " is: " + propval.ToString();
                }
            }
            else
            {
                // Display the value of the selected property of the SystemInformation type.
                Type t = typeof(System.Windows.Forms.SystemInformation);
                PropertyInfo[] pi = t.GetProperties();
                PropertyInfo prop = null;
                for (int i = 0; i < pi.Length; i++)
                    if (pi[i].Name == propname)
                    {
                        prop = pi[i];
                        break;
                    }
                object propval = prop.GetValue(nullnull);
                textBox1.Text += "\r\nThe value of the " + propname + " property is: " + propval.ToString();
            }
        }
    }
}
 

 

소스를 입력하고 빌드한다.

 

실행하면 위와 같은 화면이 나온다.

 

리스트 박스의 속성 아이템을 선택하면 텍스트 박스에 속성값이 표시된다.

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
 
namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();            
        }
 
        private void Form1_Paint(object sender, PaintEventArgs e)
        {
            e.Graphics.DrawString(System.Windows.Forms.SystemInformation.BorderSize.ToString(), Font, Brushes.Black, 1010);
            e.Graphics.DrawString(System.Windows.Forms.SystemInformation.CursorSize.ToString(), Font, Brushes.Black, 1030);
            e.Graphics.DrawString(System.Windows.Forms.SystemInformation.CaptionHeight.ToString(), Font, Brushes.Black, 1050);
        }
    }
}
 

 

위와 같이 간단히 몇 개만 조사할 수도 있다.

 

 

반응형
Posted by J-sean
:
반응형

폼을 숨기고 프로그램을 시작해 보자.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
 
namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
 
            timer1.Enabled = true;
            timer1.Interval = 5000;
        }
 
        private void Form1_Load(object sender, EventArgs e)
        {
            // 화면에 보이지 않는 폼 만들기 1
            //Opacity = 0;
            //ShowInTaskbar = false;
 
 
            // 화면에 보이지 않는 폼 만들기 2
            // 아래 두 명령어의 순서를 바꾸면 최소화된 윈도우의
            // 타이틀바가 화면에 남는다.
            WindowState = FormWindowState.Minimized;
            ShowInTaskbar = false;            
        }
 
        private void timer1_Tick(object sender, EventArgs e)
        {
            // 화면에 보이지 않으니 5초 후 자동 종료
            Close();
        }
    }
}
 

 

간단히 두 가지 방법으로 프로그램 시작 시 폼을 숨길 수 있다.

두 번째 방법은 명령 순서에 주의 한다.

 

반응형
Posted by J-sean
:
반응형

C# 코드를 난독화 해 보자.

 

Tools - NuGet Package Manager - Manage NuGet Packages for Solution... 선택

 

Browse에서 Obfuscar 검색 후 설치

 

Project - XXX Properties 선택

 

Build Events - Post-build event command line: 에 위와같이 작성한다.

"$(Obfuscar)" obfuscar.xml

 

 

Hello World!를 출력하는 소스를 입력한다.

 

Output 폴더에 obfuscar.xml 파일을 만들고 아래와 같이 작성한다.

 

간단한 obfuscar.xml 파일 내용

더 많은 세팅값은 아래 링크에서 확인할 수 있다.

Configuration

 

프로젝트를 빌드하면 난독화 되지 않은 실행파일과 함께 Obfuscator_Output 폴더가 생성된다.

 

 

Obfuscator_Output 폴더에는 난독화된 실행파일이 생성된다.

 

반응형
Posted by J-sean
:
반응형

아래 링크의 프로그램과 비슷하지만 바탕화면(Desktop)이 아닌 폼에 이미지를 출력해 바탕화면에 출력한 것처럼 보이는 프로그램을 만들어 보자.

 

2021.11.27 - [C#] - C# Desktop Image Display Program - 바탕화면 이미지 출력 프로그램

 

폼과 버튼을 적당히 배치한다.

폼에는
FormBorderStyle - None
ShowInTaskBar - False
TopMost - True
등의 조건을 준다.

 

이미지, 음악등 리소스를 추가한다.

 

Images.zip
2.32MB

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
 
using System.Runtime.InteropServices;
using System.Media;
 
namespace Christmas
{
    public partial class Form1 : Form
    {
        int screenWidth;
        int screenHeight;
 
        Random R;   // 눈 위치 지정
        int snowflakeCount;
 
        // 대부분 이미지 파일은 화면과 해상도가 달라서 작거나 크게 표시된다.
        // Image로 받지 말고 비트맵으로 변환해 사용하면 된다.
        Bitmap[] snowflakes;
        Bitmap tree;                
        Bitmap leftTop;
        Bitmap rightTop;
        Bitmap rightDeer;
        Bitmap cane;
        Bitmap bulb;
        Bitmap snowMan;
        Bitmap merry;
        Bitmap screen;  // 프로그램 시작 전 전체 화면
        Bitmap buffer;  // 더블 버퍼링
 
        public Form1()
        {
            InitializeComponent();
 
            screenWidth = Screen.PrimaryScreen.Bounds.Width;
            screenHeight = Screen.PrimaryScreen.Bounds.Height;
 
            R = new Random();
            snowflakeCount = 0;
 
            snowflakes = new Bitmap[] { Properties.Resources.snowflake1, Properties.Resources.snowflake2,
                Properties.Resources.snowflake3, Properties.Resources.snowflake4 };
            tree = new Bitmap(Properties.Resources.tree1);
            rightDeer = new Bitmap(Properties.Resources.RightDeer);
            leftTop = new Bitmap(Properties.Resources.LeftTop);
            rightTop = new Bitmap(Properties.Resources.RightTop);
            cane = new Bitmap(Properties.Resources.cane);
            bulb = new Bitmap(Properties.Resources.bulb);
            snowMan = new Bitmap(Properties.Resources.BottomSnowMan);
            merry = new Bitmap(Properties.Resources.Merry);
            screen = ScreenCapture.Capture();
            buffer = new Bitmap(screenWidth, screenHeight);
        }
                
        private void Form1_Load(object sender, EventArgs e)
        {
            // 폼의 시작 위치를 생성자에서 설정하면 크기가 줄어드는 등 비정상적으로 동작한다.
            StartPosition = FormStartPosition.Manual;            
            Location = new Point(00);
            Size = new Size(screenWidth, screenHeight);
 
            button1.Location = new Point(screenWidth - button1.Size.Width - 10, screenHeight - button1.Size.Height - button2.Size.Height - 20);
            button2.Location = new Point(screenWidth - button2.Size.Width - 10, screenHeight - button2.Size.Height - 10);
 
            // Gets or sets a value indicating whether the form will receive key events before the event is passed to the control that has focus.
            // true if the form will receive all key events; false if the currently selected control on the form receives key events. The default is false.
            // 키가 눌렸을때 포커스를 갖고 있는 컨트롤보다 폼이 먼저 키 이벤트를 받을 수 있게 한다. 단축키 지정을 위해.
            KeyPreview = true;
 
            // 탭 스탑이 가능하면 포커스된 버튼에 파란색 테두리가 보인다.
            button1.TabStop = false;
            button2.TabStop = false;
 
            // 항상 위.
            TopMost = true;
 
            // 타이머 실행.
            timer1.Enabled = true;
            timer1.Interval = 100;
 
            drawBuffer();
 
            SoundPlayer p = new SoundPlayer();
            p.Stream = Properties.Resources.Song;
            p.Play();            
        }
 
        private void drawBuffer()
        {
            using (Graphics G = Graphics.FromImage(buffer))
            {
                G.DrawImage(screen, 00);
                G.DrawImage(bulb, screenWidth - rightDeer.Width - bulb.Width, 0);
                G.DrawImage(leftTop, 00);
                G.DrawImage(rightTop, screenWidth - rightTop.Width, 0);
                G.DrawImage(rightDeer, screenWidth - rightDeer.Width, (screenHeight - rightDeer.Height) / 2);
                G.DrawImage(cane, cane.Width / 4, (screenHeight - cane.Height) / 2);
                G.DrawImage(snowMan, 0, screenHeight - snowMan.Height);
                G.DrawImage(merry, screenWidth - merry.Width, screenHeight - merry.Height - 40);
                G.DrawImage(tree, (screenWidth - tree.Width) / 240);
            }
        }
 
        private void Form1_KeyDown(object sender, KeyEventArgs e)
        {
            switch (e.KeyCode)
            {
                case Keys.Escape:
 
                case Keys.Q:
                    Close();
                    break;
 
                case Keys.B:
                    TopMost = false;
                    System.Diagnostics.Process.Start("https://s-engineer.tistory.com/");
                    break;
 
                default:
                    break;
            }
        }
        
        private void button1_Click(object sender, EventArgs e)
        {
            Close();
        }
 
        private void button2_Click(object sender, EventArgs e)
        {
            TopMost = false;
            System.Diagnostics.Process.Start("https://s-engineer.tistory.com/");
        }
 
        private void Form1_Paint(object sender, PaintEventArgs e)
        {
            if (buffer != null)
            {
                e.Graphics.DrawImage(buffer, 00);
            }
        }
 
        protected override void OnPaintBackground(PaintEventArgs e)
        {
            // 전체 화면에 대해 더블 버퍼링을 하므로 배경화면을 다시 그리지 않도록 이 함수를 빈 함수로 재정의.
            //base.OnPaintBackground(e);
        }
 
        private void timer1_Tick(object sender, EventArgs e)
        {
            using (Graphics G = CreateGraphics())
            {
                G.DrawImage(snowflakes[R.Next(4)], R.Next(screenWidth), R.Next(screenHeight));
                snowflakeCount++;
            }
 
            // snowflake를 처음 100개 까지만 빨리 그리기
            if (snowflakeCount > 100 && timer1.Interval != 1000)
            {
                timer1.Interval = 1000;
            }
        }
    }
 
    public class ScreenCapture
    {
        [DllImport("user32.dll", ExactSpelling = true, SetLastError = true)]
        private static extern IntPtr GetDC(IntPtr hWnd);
 
        [DllImport("user32.dll", ExactSpelling = true)]
        private static extern IntPtr ReleaseDC(IntPtr hWnd, IntPtr hDC);
 
        [DllImport("gdi32.dll", ExactSpelling = true)]
        private static extern IntPtr BitBlt(IntPtr hDestDC, int x, int y, int nWidth, int nHeight, IntPtr hSrcDC, int xSrc, int ySrc, int dwRop);
 
        [DllImport("user32.dll", EntryPoint = "GetDesktopWindow")]
        private static extern IntPtr GetDesktopWindow();
 
        public static Bitmap Capture()
        {
            int screenWidth = Screen.PrimaryScreen.Bounds.Width;
            int screenHeight = Screen.PrimaryScreen.Bounds.Height;
 
            Bitmap screenBmp = new Bitmap(screenWidth, screenHeight);
            Graphics g = Graphics.FromImage(screenBmp);
 
            IntPtr desktopDC = GetDC(GetDesktopWindow());
            IntPtr hDC = g.GetHdc();
 
            BitBlt(hDC, 00, screenWidth, screenHeight, desktopDC, 000x00CC0020);    //SRCCOPY (DWORD)0x00CC0020
 
            ReleaseDC(GetDesktopWindow(), desktopDC);
            g.ReleaseHdc(hDC);
            g.Dispose();
 
            return screenBmp;
        }
    }
}
 

 

소스를 입력하고 빌드한다.

 

 

실행하면 현재 화면이 캡쳐되어 리소스들과 함께 표시된다.

 

2021.12.23 - [C#] - C# Desktop(Screen) Capture - 스크린 캡쳐

 

반응형
Posted by J-sean
:
반응형

트레이 아이콘에 간단한 메뉴를 등록해 보자.

 

NotifyIcon, ContextMenuStrip, Timer를 폼에 배치한다.

 

ContextMenuStrip을 위와 같이 편집한다.

 

NotifyIcon의 Properties를 위와 같이 편집한다.

Icon - 원하는 아이콘 선택

ContextMenuStrip - 폼에 배치한 contexMenuStrip1 선택

Visible - 처음 실행 시 보이지 않도록 False

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
 
namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
 
            timer1.Enabled = true;
            timer1.Interval = 10000;
        }
 
        private void showToolStripMenuItem_Click(object sender, EventArgs e)
        {
            notifyIcon1.Visible = false;
            Show();
        }
 
        private void hideToolStripMenuItem_Click(object sender, EventArgs e)
        {
            // Hide 메뉴의 의미는 없다.
            notifyIcon1.Visible = true;
            Hide();
        }
 
        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            // Close()로 종료를 시도하면 Form1_FormClosing() 때문에 종료되지 않는다.
            Application.Exit();
        }
 
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            // 폼의 종료 아이콘 클릭시 종료하지 않고 숨김, 트레이 아이콘 활성화.
            notifyIcon1.Visible = true;
            
            if (e.CloseReason == CloseReason.UserClosing)
            {
                Hide();
                e.Cancel = true;
            }
        }
 
        private void timer1_Tick(object sender, EventArgs e)
        {
            // 타이머 인터벌이 10초 이므로 트레이 아이콘이 활성화 되어 있을때 10초마다 2초간 알림.
            if (notifyIcon1.Visible == true)
            {
                notifyIcon1.ShowBalloonTip(2000"알림""트레이에 숨어 있습니다!!", ToolTipIcon.Info);
            }            
        }
    }
}
 

 

소스를 입력하고 빌드한다.

 

실행하면 폼만 나타난다. 종료 아이콘(X)을 클릭해 보자.

 

트레이 아이콘이 나타난다.

 

매 10초마다 알림이 나타난다.

 

반응형
Posted by J-sean
: