Программирование КПК и смартфонов на .NET Compact Framework — страница 17 из 41

Но мы с вами не расстаемся с программами, написанными Кристианом Форсбергом. На его сайте можно найти еще одну полезную программу, необходимую как разработчику, так и пользователю. Это Диспетчер задач (Task Manager). Программа подобного рода тоже отсутствует в стандартной поставке Windows Mobile. А ведь эта программа очень полезна в работе. Владелец смартфона под управлением системы Windows Mobile может узнать много нового о своей системе после запуска этой утилиты. Диспетчер задач покажет все программы, которые размещаются в памяти смартфона, отбирая системные ресурсы. Диспетчер задач также позволяет удалять из памяти ненужные программы и процессы. Не случайно, многие производители сами снабжают свои устройства программами подобного типа. Если вам не повезло и у вас нет такой программы, то вы можете сами написать Диспетчер задач.

Как и предыдущий пример, оригинальная версия программы была написана на Visual Studio 2003 для смартфонов под управлением Windows Mobile 2003 на платформе .NET Compact Framework 1.0. Следуя нашей традиции, я с согласия автора конвертировал проект для Visual Studio 2005 для целевой системы Windows Mobile 5.0 и с применением .NET Compact Framework 2.0.

Графический интерфейс программы

Диспетчер задач при запуске показывает список запущенных программ (рис. 7.5).

Рис. 7.5. Внешний вид программы

С помощью меню, размещенного в левой части окна, можно активировать выбранное приложение. При этом сам менеджер задач закрывается. Меню, расположенное в правой части окна, предоставляет пользователю несколько больше возможностей. Команды этого меню приведены в следующем списке:

Обновить
— обновляет список запущенных программ;

Процессы
— показывает список запущенных процессов;

Остановить
— останавливает выбранную программу;

Остановить все
— останавливает все запущенные программы;

Вид
— показывает информацию о процессе;

Убить
— закрывает процесс;

О программе
— выводит информацию об авторе программы;

Готово
— закрывает программу. Внешний вид этого меню показан на рис. 7.6.

Рис. 7.6. Команды меню для правой кнопки

Код программы

При активации основной формы

MainForm
программа получает список запущенных программ при помощи процедуры
fillTaskList
, код которой приведен в листинге 7.24.

Листинг 7.24

private void fillTaskList() {

 Cursor.Current = Cursors.WaitCursor;

 // Получим список запущенных приложений

 windows = WindowHelper.EnumerateTopWindows();

 // Заполняем ListView

 ListViewItem lvi;

 listView.BeginUpdate();

 listView.Items.Clear();

 foreach(Window w in windows) {

  lvi = new ListViewItem(w.ToString());

  listView.Items.Add(lvi);

 }

 listView.EndUpdate();

 if (listView.Items.Count > 0) {

  listView.Items[0].Selected = true;

  listView.Items[0].Focused = true;

 }

 Cursor.Current = Cursors.Default;

}

Данная процедура использует класс

WindowHelper
, который позволяет получить информацию о запущенных приложениях. В листинге 7.25 приведен код метода
EnumerateTopWindows
, который находит все окна запущенных в системе приложений.

Листинг 7.25

public static Window[] EnumerateTopWindows() {

 ArrayList windowList = new ArrayList();

 IntPtr hWnd = IntPtr.Zero;

 Window window = null;

 // Получим первое окно

 hWnd = GetActiveWindow();

 hWnd = GetWindow(hWnd, GW_HWNDFIRST);

 while(hWnd != IntPtr.Zero) {

  if (IsWindow(hWnd) && IsWindowVisible(hWnd)) {

   IntPtr parentWin = GetParent(hWnd);

   if ((parentWin == IntPtr.Zero)) {

    int length = GetWindowTextLength(hWnd);

    if (length > 0) {

     string s = new string('\0', length + 1);

     GetWindowText(hWnd, s.length + 1);

     s = s.Substring(0, s.IndexOf('\0'));

     if (s != "Tray" && s != "Start" && s != "Task Manager") {

      window = new Window();

      window.Handle = hWnd;

      window.Text = s;

      windowList.Add(window);

     }

    }

   }

  }

  hWnd = GetWindow(hWnd, GW_HWNDNEXT);

 }

 return (Window[])windowList.ToArray(typeof(Window));

}

В этом методе вызываются функции Windows API, с помощью которых можно получить список всех открытых окон. Все обнаруженные окна добавляются в список, если они удовлетворяют некоторым условиям. Добавляемые окна не должны иметь родительских окон, они должны быть видимыми и иметь заголовок. При этом сам Диспетчер задач не должен попасть в этот список. Все остальные окна записываются в массив.

Активация и закрытие приложения

Для активации запущенного приложения вызывается функция Windows API

SetForegroundWindow
, которая использует дескриптор окна. Для закрытия приложения используется функция
SendMessage
с соответствующим сообщением закрытия
WM_CLOSE
. Для закрытия сразу всех окон можно использовать функцию Windows API
SHCloseApps
, которая закрывает все запущенные программы, кроме самого Диспетчера задач. Код, выполняющий эти действия, приведен в листинге 7.26.

Листинг 7.26

public static void ActivateWindow(IntPtr hWnd) {

 // Активируем приложение

 SetForegroundWindow(hWnd);

}


public static void CloseWindow(IntPtr hWnd) {

 // Закрываем приложение

 SendMessage(hWnd, WM_CLOSE, 0, 0);

}


public static void CloseApps() {

 // Закрываем все приложения

 SHCloseApps(int.MaxValue);

}

Перечисление процессов

Для отображения списка процессов используется функция, код которой приведен в листинге 7.27.

Листинг 7.27

private void fillProcessList() {

 Cursor.Current = Cursors.WaitCursor;

 // Получаем список запущенных процессов

 processes = Process.GetProcesses();

 // Заполняем ListView

 ListViewItem lvi;

 listView.BeginUpdate();

 listView.Items.Clear();

 foreach (Process p in processes) {

  lvi = new ListViewItem(p.ProcessName);

  //lvi.SubItems.Add("ID");

  listView.Items.Add(lvi);

 }

 listView.EndUpdate();

 if (listView.Items.Count > 0) {

  listView.Items[0].Selected = true;

  listView.Items[0].Focused = true;

 }

 Cursor.Current = Cursors.Default;

}

Список активных процессов извлекается при помощи класса

Process
. Основой класса является метод
GetProcesses
, приведенный в листинге 7.28.

Листинг 7.28

public static Process[] GetProcesses() {

 ArrayList procList = new ArrayList();

 IntPtr handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

 if ((int)handle > 0) {

  try {

   PROCESSENTRY32 peCurrent;

   PROCESSENTRY32 pe32 = new PROCESSENTRY32();

   byte[] peBytes = pe32.ToByteArray();

   int retval = Process32First(handle, peBytes);

   while(retval == 1) {

    peCurrent = new PROCESSENTRY32(peBytes);

    Process proc =

     new Process(new IntPtr((int)peCurrent.PID), peCurrent.Name,

     (int)peCurrent.ThreadCount, (int)peCurrent.BaseAddress);

     procList.Add(proc);

    retval = Process32Next(handle, peBytes);

   }

  } catch(Exception ex) {

   throw new Exception("Exception: " + ex.Message);

  }

  CloseToolhelp32Snapshot(handle);

  return (Process[])procList.ToArray(typeof(Process));

 } else {

  throw new Exception("Unable to get processes!");

 }

}

С помощью данного метода можно узнать детальную информацию о каждом процессе.

Закрытие процесса

Чтобы закрыть процесс, используется метод

Kill
, код которого приведен в листинге 7.29.

Листинг 7.29

public void Kill() {

 IntPtr hProcess;

 hProcess = OpenProcess(PROCESS_TERMINATE, false, (int) processId);

 if (hProcess != (IntPtr) INVALID_HANDLE_VALUE) {

  bool bRet;

  bRet = TerminateProcess(hProcess, 0);

  CloseHandle(hProcess);

 }

}

Данный метод также использует вызовы функций Windows API. Функция

OpenProcess
получает дескриптор процесса, который затем передается функции
TerminateProcess
для уничтожения процесса.

Код, отвечающий за внешний вид элемента управления

ListView
, полностью идентичен коду из предыдущего примера, поэтому его можно просто скопировать и не рассматривать отдельно. Теперь с помощью Диспетчера задач пользователь сможет узнать список запущенных программ и процессов и даже управлять ими.

Маленький блокнот