2006년 07월 16일
간단히 만들어보는 작업관리자~
오랫동안 코딩을 안한 탓에 감각도 살려볼 겸 프로세스 모니터링 툴을 만들어 보았다. 흔히 윈도우 작업관리자에서 프로세스 탭에서 나오는 내용을 연상하면 될 것 같다. 많은 기능은 없고 현재 사용자 Context에서 수행중인 프로세스의 목록을 읽어온 후 Timer를 이용하여 정기적으로 프로세스 목록을 갱신시켜주는 정도만 구현되어 있다.
프로세스 목록을 읽어오기 위해서는 System.Diagnostics NameSpace를 추가해 주어야 한다. 미처 화면을 캡쳐하지 못했는데, WinForm에는 4개의 컬럼을 가진 ListView 컨트롤(lvTasks)이 올려져 있고 프로세스의 목록을 나타내기 위한 TextBox 컨트롤(txtProcess)이 올려져 있다. 회사에 출근하면 화면을 캡쳐해서 올리도록 하겠다.
일정시간 주기로 ListView를 갱신해야 하는데, 이를 위하여 두가지 전역변수를 선언해 줘야 한다. 하나는 Timer이고 다른 하나는 bool형 변수인 IsChecked이다.
WinForm 객체가 생성될때 Timer에 관한 몇가지 작업을 해줘야 한다. 우선, 타이머를 활성화 시키고 1초마다 업데이트를 하기 위해서 Interval을 1000으로 잡아주었다. 1초마다 Timer 이벤트가 발생하게 되는데, 이를 위해서 timer_Tick이라는 이름의 이벤트 핸들러를 추가해 주었다.
lvTasks 객체에 Process를 읽어서 보여주는 코드는 아래와 같다. System.Diagnostics에 포함되어 있는 Process 클래스는 Process와 관련한 많은 메소드, 프라퍼티를 가지고 있다. 이 코드에서는 그 일부만을 이용하여 작업관리자와 비슷한 항목을 추출하는데 사용했다. 실제로 작업관리자에서는 Process 클래스가 제공하는 수많은 항목들을 사용자의 취향에 따라 넣거나 뺄 수 있다. 이런 기능들도 물론 구현이 가능하겠지만, 귀차니즘으로 인하여 비슷한 모양만 나오도록 항목을 선정했다.
GetProcesses()라는 메소드는 이름에서 풍기는 느낌 그대로, 프로세스들을 가져오는 역할을 한다. 각각의 프로세스는 Process라는 클래스의 인스턴스라고 보면 되는데, 프로세스의 갯수만큼 정보를 얻기 위하여 foreach문을 사용하였다. 어려운 코드가 아니므로, 한번 보고 응용해볼 수 있을 것이다.
사실, 프로세스 모니터링 툴에서 그나마 난이도가 있는 부분은 목록에 프로세스를 추가하고 제거하는 부분이 아닐까 싶다. 그 중에서 추가는 아주 쉽고, 제거가 조금 머리를 써야하는 부분이 아닌가 싶다. 여기서 다시한번 작업관리자를 들어가보면, 작업관리자의 프로세스 목록에 있는 프로세스들은 변화된 정보(메모리사용, CPU사용율 등)만 업데이트 해주는 모습을 볼 수 있다. 말 그대로 구현해 보자. 1초 단위로 timer_Tick 이벤트 핸들러가 호출이 되면, 잠시 timer를 멈춰놓고 lvTasks의 Item들을 점검하여 필요한 녀석들은 업데이트를 시켜주도록 하자. 혹, 더쉬운 방법으로 "lvTasks를 날리고 다시 전부 Item 추가하면 쉽지 않나요?" 하실 분들이 있을지 모르겠는데, 직접 해보면 뭐가 문제인지 쉽게 파악할 수 있을 것이다.
업데이트는 좋은데, 새롭게 추가된 프로세스는 어떻게 넣어야 할까? 역시 별거 없지 않겠는가? lvTasks의 Item에 해당 항목이 없으면 걍 생각없이 추가해주면 된다. Simple 그 자체이다.
오늘의 그나마 난이도 있는 부분인 종료 프로세스의 제거는 어떻게 손을 보면 될까? 프로세스 추가 코드를 유심히 봤다면 알 수 있었겠지만, 필자는 lvTasks의 Item 별로 가지고 있는 Checked라는 속성을 사용해 보았다. 이 필드는 timer_Tick 이벤트 핸들러가 호출될 때 마다 반전되는 필드이다. 간단히 얘기하면, 프로세스가 죽은 녀석들은 이 필드가 다른 Item의 프로세스들과 반대의 값을 가지고 있게 될 것이다. 우리는 간단한 foreach문을 통하여 혼자 튀는 녀석들만 가볍게 제거 해줌으로써 프로세스 제거를 구현할 수 있다.
대충 이렇게 만들어보면 간단하나마 프로세스 모니터링을 할 수 있는 프로그램이 나온다. 하지만, 누가 프로세스 관리를 위해서 이렇게 무거운 코드를 쓰겠는가? 일반적인 작업관리자의 용도 이외에 서버관리도구를 만든다거나, 기타 프로세스의 관리가 필요한 프로그램 제작시에 응용하면 좋을 것 같다. 또, 자기 자신의 프로세스를 점검하여 1개 이상의 인스턴스가 생성되지 못하게 하는 코드도 쉽게 만들 수 있지 않을까 싶다.
오랜만에 해보는 코딩이라(어언..1년이 넘은 것 같다. ㅠㅠ 안습...나 개발자 맞나? -_-+) 뭔가 어설프고 불필요한 캐스팅과 Heap/Stack 점유가 많이 보인다. 이 모든 것은 감각을 살리고 다시 달릴 수 있도록 하는 작업의 일환이므로 코드가 엉망이라고 뭐라고 하진 말자! :) 음흣... 다들 행복한 일요일들 되시길...
- NoPD -
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Diagnostics; // 추가
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Diagnostics; // 추가
프로세스 목록을 읽어오기 위해서는 System.Diagnostics NameSpace를 추가해 주어야 한다. 미처 화면을 캡쳐하지 못했는데, WinForm에는 4개의 컬럼을 가진 ListView 컨트롤(lvTasks)이 올려져 있고 프로세스의 목록을 나타내기 위한 TextBox 컨트롤(txtProcess)이 올려져 있다. 회사에 출근하면 화면을 캡쳐해서 올리도록 하겠다.
일정시간 주기로 ListView를 갱신해야 하는데, 이를 위하여 두가지 전역변수를 선언해 줘야 한다. 하나는 Timer이고 다른 하나는 bool형 변수인 IsChecked이다.
private Timer timer = new Timer();
private bool IsChecked = false;
private bool IsChecked = false;
WinForm 객체가 생성될때 Timer에 관한 몇가지 작업을 해줘야 한다. 우선, 타이머를 활성화 시키고 1초마다 업데이트를 하기 위해서 Interval을 1000으로 잡아주었다. 1초마다 Timer 이벤트가 발생하게 되는데, 이를 위해서 timer_Tick이라는 이름의 이벤트 핸들러를 추가해 주었다.
public frmMain()
{
InitializeComponent();
//
timer.Enabled = true;
timer.Interval = 1000;
timer.Tick += new EventHandler(timer_Tick);
timer.Tick += new System.EventHandler(this.timer_Tick);
}
{
InitializeComponent();
//
timer.Enabled = true;
timer.Interval = 1000;
timer.Tick += new EventHandler(timer_Tick);
timer.Tick += new System.EventHandler(this.timer_Tick);
}
lvTasks 객체에 Process를 읽어서 보여주는 코드는 아래와 같다. System.Diagnostics에 포함되어 있는 Process 클래스는 Process와 관련한 많은 메소드, 프라퍼티를 가지고 있다. 이 코드에서는 그 일부만을 이용하여 작업관리자와 비슷한 항목을 추출하는데 사용했다. 실제로 작업관리자에서는 Process 클래스가 제공하는 수많은 항목들을 사용자의 취향에 따라 넣거나 뺄 수 있다. 이런 기능들도 물론 구현이 가능하겠지만, 귀차니즘으로 인하여 비슷한 모양만 나오도록 항목을 선정했다.
GetProcesses()라는 메소드는 이름에서 풍기는 느낌 그대로, 프로세스들을 가져오는 역할을 한다. 각각의 프로세스는 Process라는 클래스의 인스턴스라고 보면 되는데, 프로세스의 갯수만큼 정보를 얻기 위하여 foreach문을 사용하였다. 어려운 코드가 아니므로, 한번 보고 응용해볼 수 있을 것이다.
private void ViewProcess()
{
string[] tmpStr = new String[5];
foreach(Process tmp in Process.GetProcesses())
{
tmpStr[0] = tmp.ProcessName;
tmpStr[1] = tmp.Id.ToString();
tmpStr[2] = (tmp.WorkingSet/1024).ToString();
tmpStr[3] = (tmp.VirtualMemorySize/1024).ToString();
tmpStr[4] = tmp.StartInfo.EnvironmentVariables["username"];
ListViewItem tmpItem = new ListViewItem(tmpStr,0);
lvTasks.Items.Add(tmpItem);
}
lvTasks.Sorting = SortOrder.Ascending;
txtProcess.Text = lvTasks.Items.Count.ToString();
}
{
string[] tmpStr = new String[5];
foreach(Process tmp in Process.GetProcesses())
{
tmpStr[0] = tmp.ProcessName;
tmpStr[1] = tmp.Id.ToString();
tmpStr[2] = (tmp.WorkingSet/1024).ToString();
tmpStr[3] = (tmp.VirtualMemorySize/1024).ToString();
tmpStr[4] = tmp.StartInfo.EnvironmentVariables["username"];
ListViewItem tmpItem = new ListViewItem(tmpStr,0);
lvTasks.Items.Add(tmpItem);
}
lvTasks.Sorting = SortOrder.Ascending;
txtProcess.Text = lvTasks.Items.Count.ToString();
}
사실, 프로세스 모니터링 툴에서 그나마 난이도가 있는 부분은 목록에 프로세스를 추가하고 제거하는 부분이 아닐까 싶다. 그 중에서 추가는 아주 쉽고, 제거가 조금 머리를 써야하는 부분이 아닌가 싶다. 여기서 다시한번 작업관리자를 들어가보면, 작업관리자의 프로세스 목록에 있는 프로세스들은 변화된 정보(메모리사용, CPU사용율 등)만 업데이트 해주는 모습을 볼 수 있다. 말 그대로 구현해 보자. 1초 단위로 timer_Tick 이벤트 핸들러가 호출이 되면, 잠시 timer를 멈춰놓고 lvTasks의 Item들을 점검하여 필요한 녀석들은 업데이트를 시켜주도록 하자. 혹, 더쉬운 방법으로 "lvTasks를 날리고 다시 전부 Item 추가하면 쉽지 않나요?" 하실 분들이 있을지 모르겠는데, 직접 해보면 뭐가 문제인지 쉽게 파악할 수 있을 것이다.
업데이트는 좋은데, 새롭게 추가된 프로세스는 어떻게 넣어야 할까? 역시 별거 없지 않겠는가? lvTasks의 Item에 해당 항목이 없으면 걍 생각없이 추가해주면 된다. Simple 그 자체이다.
private void timer_Tick(object sender, EventArgs e)
{
timer.Stop();
string[] tmpStr = new string[5];
ListViewItem tmpListViewItem = new ListViewItem();
bool IsMatch;
// 수행중인 프로세스 Update 및 신규 프로세스 추가
foreach(Process tmp in Process.GetProcesses())
{
IsMatch = false;
tmpStr[0] = tmp.ProcessName;
tmpStr[1] = tmp.Id.ToString();
foreach(ListViewItem tmp2 in lvTasks.Items)
{
if((tmp2.SubItems[0].Text == tmpStr[0]) &&
tmp2.SubItems[1].Text == tmpStr[1])
{
tmpStr[2] = (tmp.WorkingSet/1024).ToString();
tmpStr[3] = (tmp.VirtualMemorySize/1024).ToString();
tmpStr[4] = tmp.StartInfo.EnvironmentVariables["username"];
lvTasks.Items[lvTasks.Items.IndexOf(tmp2)].SubItems[2].Text = tmpStr[2];
lvTasks.Items[lvTasks.Items.IndexOf(tmp2)].SubItems[3].Text = tmpStr[3];
lvTasks.Items[lvTasks.Items.IndexOf(tmp2)].Checked = IsChecked;
IsMatch = true;
break;
}
}
if(!IsMatch)
{
tmpStr[2] = (tmp.WorkingSet/1024).ToString();
tmpStr[3] = (tmp.VirtualMemorySize/1024).ToString();
tmpStr[4] = tmp.StartInfo.EnvironmentVariables["username"];
ListViewItem tmpItem = new ListViewItem(tmpStr,0);
int index = lvTasks.Items.Add(tmpItem).Index;
lvTasks.Items[index].Checked = IsChecked;
lvTasks.Sorting = SortOrder.Ascending;
}
}
{
timer.Stop();
string[] tmpStr = new string[5];
ListViewItem tmpListViewItem = new ListViewItem();
bool IsMatch;
// 수행중인 프로세스 Update 및 신규 프로세스 추가
foreach(Process tmp in Process.GetProcesses())
{
IsMatch = false;
tmpStr[0] = tmp.ProcessName;
tmpStr[1] = tmp.Id.ToString();
foreach(ListViewItem tmp2 in lvTasks.Items)
{
if((tmp2.SubItems[0].Text == tmpStr[0]) &&
tmp2.SubItems[1].Text == tmpStr[1])
{
tmpStr[2] = (tmp.WorkingSet/1024).ToString();
tmpStr[3] = (tmp.VirtualMemorySize/1024).ToString();
tmpStr[4] = tmp.StartInfo.EnvironmentVariables["username"];
lvTasks.Items[lvTasks.Items.IndexOf(tmp2)].SubItems[2].Text = tmpStr[2];
lvTasks.Items[lvTasks.Items.IndexOf(tmp2)].SubItems[3].Text = tmpStr[3];
lvTasks.Items[lvTasks.Items.IndexOf(tmp2)].Checked = IsChecked;
IsMatch = true;
break;
}
}
if(!IsMatch)
{
tmpStr[2] = (tmp.WorkingSet/1024).ToString();
tmpStr[3] = (tmp.VirtualMemorySize/1024).ToString();
tmpStr[4] = tmp.StartInfo.EnvironmentVariables["username"];
ListViewItem tmpItem = new ListViewItem(tmpStr,0);
int index = lvTasks.Items.Add(tmpItem).Index;
lvTasks.Items[index].Checked = IsChecked;
lvTasks.Sorting = SortOrder.Ascending;
}
}
오늘의 그나마 난이도 있는 부분인 종료 프로세스의 제거는 어떻게 손을 보면 될까? 프로세스 추가 코드를 유심히 봤다면 알 수 있었겠지만, 필자는 lvTasks의 Item 별로 가지고 있는 Checked라는 속성을 사용해 보았다. 이 필드는 timer_Tick 이벤트 핸들러가 호출될 때 마다 반전되는 필드이다. 간단히 얘기하면, 프로세스가 죽은 녀석들은 이 필드가 다른 Item의 프로세스들과 반대의 값을 가지고 있게 될 것이다. 우리는 간단한 foreach문을 통하여 혼자 튀는 녀석들만 가볍게 제거 해줌으로써 프로세스 제거를 구현할 수 있다.
// 종료 프로세스 제거
foreach(ListViewItem tmp in lvTasks.Items)
{
if(tmp.Checked != IsChecked)
{
lvTasks.Items[lvTasks.Items.IndexOf(tmp)].Remove();
}
}
txtProcess.Text = lvTasks.Items.Count.ToString();
IsChecked = !IsChecked;
timer.Start();
}
}
}
foreach(ListViewItem tmp in lvTasks.Items)
{
if(tmp.Checked != IsChecked)
{
lvTasks.Items[lvTasks.Items.IndexOf(tmp)].Remove();
}
}
txtProcess.Text = lvTasks.Items.Count.ToString();
IsChecked = !IsChecked;
timer.Start();
}
}
}
대충 이렇게 만들어보면 간단하나마 프로세스 모니터링을 할 수 있는 프로그램이 나온다. 하지만, 누가 프로세스 관리를 위해서 이렇게 무거운 코드를 쓰겠는가? 일반적인 작업관리자의 용도 이외에 서버관리도구를 만든다거나, 기타 프로세스의 관리가 필요한 프로그램 제작시에 응용하면 좋을 것 같다. 또, 자기 자신의 프로세스를 점검하여 1개 이상의 인스턴스가 생성되지 못하게 하는 코드도 쉽게 만들 수 있지 않을까 싶다.
오랜만에 해보는 코딩이라(어언..1년이 넘은 것 같다. ㅠㅠ 안습...나 개발자 맞나? -_-+) 뭔가 어설프고 불필요한 캐스팅과 Heap/Stack 점유가 많이 보인다. 이 모든 것은 감각을 살리고 다시 달릴 수 있도록 하는 작업의 일환이므로 코드가 엉망이라고 뭐라고 하진 말자! :) 음흣... 다들 행복한 일요일들 되시길...
- NoPD -
# by | 2006/07/16 11:12 | [IT] .NET Framework | 트랙백



