C# — Cвернуть коносльное приложение в трей

2011-03-24 papirosnik C#

Наслаждаясь программированием на языке C#  и исповедуя традиционные подходы в решении повседневных задач, столкнулся в своей практике только с двумя моментам, которые немного напрягли: отсутсвие полноценной поддержки старых добрых ini-файлов и неожиданно неочевидный способ для кооперирования консольного приложения и системного трея.

Что касается первого пункта, то я уже высказался здесь. Теперь разберём и сворачивание консольного приложения в системный трэй. В «Корпорации» почему-то эту возможность тоже исключили из перечня поддерживаемых, прикрываясь благими намерениями: мол, консольное приложение предназначено для работы с командной строкой и простейшиего интерактивного диалога с пользователем. Если же вам нужно приложение, работающее в фоне, то используйте Service. Если хотите полноценное WindowsForm приложение в трее, то вот  пожалуйста — компонента NotifyIcon к вашим услугам. Но как раз то в трэй иногда и надо свернуть что-то простейшее, не отвлекающее. Доставть его оттуда в редких случаях и обратно оставлять работать. Короче настолько простое, что использование махины WindowsForm и Service в этом случае неоправданно дорого.

Ничего не мешает использовать NotifyIcon и в коносльном приложении. Единственное неудобство заключается в том, что эта компонента находится в пространстве имён (и соответственно в сборке) Systems.Windows.Forms, а студия при создании консольного проекта не подрубает эту сборку к нему автоматически. Это неудобство легко обойти, добавив в исходный текст вашего приложения следующую строчку: using System.Windows.Forms; а в проект эксплорере в папку References — одноимённую сборку (References—>Add Reference—>.NET—>Sysytem.Windows.Form). Всё — ваше приложение теперь способно работать с компонентой TrayIcon.

Но остался ещё нюанс, который надо разобрать, если вы намерены прятать своё консольное приложение. В случае WindowsForm проблем здесь никаких — свойство Visible у формы ещё никто не отменял. Но в консольном приложении придётся всё это делать вручную. Так как чтобы показать/спрятать окно, нужен его дескриптор, котрого у нас таки нет. Придётся заиметь.

Для этого импортируем нативную функцию GetConsoleWindow() из kernel32.dll. Эта функция вернёт нам хэндл нашего консольного окошка. А чтобы его показать/скрыть, — воспользуемся другой импортированной из user32.dll функцией: ShowWindow(IntPtr hWnd, int nCmdShow). Эта функция прячет или показывает (это зависит от nCmdShow)  окошко с хэнддлом hWnd.

И последнее, что надо сделать, это запрограммировать реакцию на клик по иконке приложения в системном трее. У NotifyIcon много делегатов, предназначенных для интеракции с пользователем. Мы, не мудрствуя лукаво, задействуем Click (срабатывает при клике мышкой). Эти несколько простых действий можно выразить следующими строчками кода:

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
using System;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
static class Program
{
      static void Main(string[] args)
      {
           [DllImport("kernel32.dll", ExactSpelling = true)]
           private static extern IntPtr GetConsoleWindow();
           private static IntPtr mThisConsole = GetConsoleWindow();
 
           [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
           private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
           private static bool mWinVisible = false;
           private const int HIDE = 0;
           private const int SHOW = 9;
 
         	NotifyIcon tray = new NotifyIcon(); // Создали иконку для трея
           tray.Icon = new Icon("Icon1.ico");  // Файл Icon1.ico в моём случае лежит рядом с exe-шником.
           tray.MouseDown += new MouseEventHandler(trayClick); // Будет реагировать на клик мышкой
           tray.Visible = true;        // Показать иконку
           showWindow(false);      // Спрятать окно
           Application.Run();      // Запустить цикл ожидания событий
       }
 
      // --------------------------------------
      static void showWindow(bool Yes)
      {
           mWinVisible = Yes;
           ShowWindow(mThisConsole, Yes?SHOW:HIDE);
      }
 
      // --------------------------------------
      static void trayClick(object sender, EventArgs e)
      {
           showWindow(!mVisible);
      }
}

Здесь мы экспортировали нужные функции из dll, задали вид иконки для трея (из файла Icon1.ico), обработчик клика по ней (trayClick), показали её (икону в трее) и спрятали наше главное консольное окно. Теперь при клике на иконке в трее это окошко будет показано вновь, при следующем клике — снова спрятано.

Надеюсь, этот простой пример поможет вам в вашей творческой деятельности и подвигнет на дальнейшее развитие идеи. Например, можно повесить на иконку в трее контекстное меню, снабдить её всплывающими сообщениями и т.д. и т.п.  Главная же цель этой статьи — показать основную идею совмещения консольного приложения на C# и системного трея. Остальное за вами.

delegates, namespace, Sytem tray,

11 комментариев to “C# — Cвернуть коносльное приложение в трей”


Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Powered by WordPress. Designed by elogi.