<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>#Shooter &#187; work</title>
	<atom:link href="http://www.sharp-shooter.ru/tag/work/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.sharp-shooter.ru</link>
	<description>Программирование на C# и все такое</description>
	<lastBuildDate>Sun, 11 Dec 2011 20:39:41 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>NotifyIcon в консольном приложении</title>
		<link>http://www.sharp-shooter.ru/2011/02/27/notifyicon-in-console-app/</link>
		<comments>http://www.sharp-shooter.ru/2011/02/27/notifyicon-in-console-app/#comments</comments>
		<pubDate>Sun, 27 Feb 2011 20:31:35 +0000</pubDate>
		<dc:creator>yallie</dc:creator>
				<category><![CDATA[Программирование]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[console]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[tutorial]]></category>
		<category><![CDATA[WinForms]]></category>
		<category><![CDATA[work]]></category>

		<guid isPermaLink="false">http://www.sharp-shooter.ru/?p=205</guid>
		<description><![CDATA[Я постоянно имею дело с консольными программами, которые используются для хостинга служб WCF или .NET Remoting. Для отладки это самый удобный вариант: запускается быстро, консоль при случае используется для отладочной печати, и так далее. Выглядит такая программа обычно как-нибудь так (в случае с Remoting):

static void Main&#40;string&#91;&#93; args&#41;
&#123;
    // Запускаем сервер
   [...]]]></description>
			<content:encoded><![CDATA[<p>Я постоянно имею дело с консольными программами, которые используются для хостинга служб WCF или .NET Remoting. Для отладки это самый удобный вариант: запускается быстро, консоль при случае используется для отладочной печати, и так далее. Выглядит такая программа обычно как-нибудь так (в случае с Remoting):</p>

<div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;"><span style="color: #0600FF;">static</span> <span style="color: #0600FF;">void</span> Main<span style="color: #000000;">&#40;</span><span style="color: #FF0000;">string</span><span style="color: #000000;">&#91;</span><span style="color: #000000;">&#93;</span> args<span style="color: #000000;">&#41;</span>
<span style="color: #000000;">&#123;</span>
    <span style="color: #008080; font-style: italic;">// Запускаем сервер</span>
    var config <span style="color: #008000;">=</span> AppDomain.<span style="color: #0000FF;">CurrentDomain</span>.<span style="color: #0000FF;">SetupInformation</span>.<span style="color: #0000FF;">ConfigurationFile</span><span style="color: #008000;">;</span>
    RemotingConfiguration.<span style="color: #0000FF;">Configure</span><span style="color: #000000;">&#40;</span>config, <span style="color: #0600FF;">false</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
&nbsp;
    <span style="color: #008080; font-style: italic;">// Работаем, пока не нажмут Enter</span>
    Console.<span style="color: #0000FF;">WriteLine</span><span style="color: #000000;">&#40;</span><span style="color: #666666;">&quot;Server started. Press ENTER to quit.&quot;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
    Console.<span style="color: #0000FF;">ReadLine</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
<span style="color: #000000;">&#125;</span></pre></div></div>

<p>Запустил, минимизировал такое окошко и крутится там себе сервер на фоне. Частенько бывает, что таких серверов запущено несколько (штуки три-четыре), и они постоянно торчат на панели задач. Изредка развернешь, чтобы прочитать, что там на консоли напечатано, а большую часть времени они только зря место занимают. Мне, честно говоря, это никогда особо не мешало. Пару недель назад один мой товарищ в разговоре заметил, что такие программки хорошо бы куда-нибудь прятать, оставляя одну иконку в системном трее. И с тех пор меня эти кнопки на панели задач стали раздражать.</p>
<p>Это такой мыслевирус, как кернинг: если человек не знает, что это такое, он живет себе спокойно. А если ему рассказать, да еще и показать на примере, чем плохой кернинг отличается от хорошего, — покой навеки утрачен. Теперь плохой кернинг постоянно будет ему бросаться в глаза на вывесках, объявлениях и рекламе в метро.</p>
<p>Короче говоря, пришлось-таки сделать небольшую библиотечку для сворачивания консоли в трей-иконку. Проблем тут, собственно, немного, но они есть (поэтому наивный вариант решения задачи — добавить компонент NotifyIcon с обработчиком DoubleClick, по которому что-нибудь там делать — не работает):</p>
<ul>
<li>В .NET Framework нету легального способа получить в свое распоряжение окно консоли</li>
<li>В консольных приложениях нет конвейера сообщений</li>
</ul>
<p>То есть, грубо говоря, добавить NotifyIcon можно (и в системном трее она будет нормально показываться), но обработчик события Click или DoubleClick вызываться не будет. Поскольку конвейера нет, событие просто некому переправить на обработку. А если и получится вызвать такой обработчик, непонятно, что в этом обработчике делать с консолью.</p>
<p>Чтобы справиться с этими проблемами, нужно 1) запустить свой конвейер сообщений в отдельном потоке и 2) заполучить хэндл окна консоли и прятать/показывать его средствами WinAPI. Выглядит так, как будто весь компонент будет состоять из сплошных вызовов p/invoke, то есть решение не будет блистать изяществом.</p>
<p>Однако выяснилось, что на деле не все так страшно. Оказывается, конвейеру WinForms — Application.Run(&#8230;) — вовсе не требуется главная форма. Он вполне сносно будет работать, если вместо этой формы ему подсунуть компонент NotifyIcon. То есть, первая часть задачи на самом деле сводится к запуску отдельного потока, в котором будет создаваться NotifyIcon и запускаться конвейер. И никакого p/invoke, что весьма приятно.</p>
<p>Хендл окна консоли, как выяснилось, иногда можно получить вот так: Process.GetCurrentProcess().MainWindowHandle. Здесь, разумеется, все портит слово «иногда»: на моем ноутбуке этот способ работает (Win7 x64), а на рабочем компьютере (WinXP x32) — нет. Вместо хендла возвращается IntPtr.Zero (MSDN говорит, что так задумано). </p>
<p>Так что для второй части задачи — прятать/показывать окно консоли — p/invoke все же нужен. Во-первых, нужен хендл консольного окна, во-вторых — метод ShowWindow(), который прячет или показывает окно по его хендлу. Весь WinAPI-мусор выносится в отдельный файл строчек примерно на 50 — ничего страшного. Жаль, правда, что портабельным этот вариант не будет, ну да хрен с ним, я и не претендовал на универсальность.</p>
<p>А дальше можно сделать приемлемую обертку, на иконку прицепить контекстное меню и заполнять его каким-нибудь fluent-интерфейсом:</p>

<div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;"><span style="color: #0600FF;">using</span> <span style="color: #000000;">&#40;</span>var tools <span style="color: #008000;">=</span> <span style="color: #008000;">new</span> ConsoleTools<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span>
<span style="color: #000000;">&#123;</span>
    <span style="color: #008080; font-style: italic;">// настраиваем иконку в системном трее</span>
    tools.<span style="color: #0000FF;">SetNotifyIcon</span><span style="color: #000000;">&#40;</span>SystemIcons.<span style="color: #0000FF;">Shield</span><span style="color: #000000;">&#41;</span>
        .<span style="color: #0000FF;">SetTooltip</span><span style="color: #000000;">&#40;</span>Console.<span style="color: #0000FF;">Title</span> <span style="color: #008000;">+</span> <span style="color: #666666;">&quot;: double click to toggle visibility&quot;</span><span style="color: #000000;">&#41;</span>
&nbsp;
        <span style="color: #008080; font-style: italic;">// добавляем обработчики событий (конвейер их обработает)</span>
        .<span style="color: #0000FF;">OnClick</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#40;</span>s, e<span style="color: #000000;">&#41;</span> <span style="color: #008000;">=&gt;</span> Console.<span style="color: #0000FF;">WriteLine</span><span style="color: #000000;">&#40;</span><span style="color: #666666;">&quot;NotifyIcon clicked!&quot;</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span>
        .<span style="color: #0000FF;">OnDoubleClick</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#40;</span>s, e<span style="color: #000000;">&#41;</span> <span style="color: #008000;">=&gt;</span> tools.<span style="color: #0000FF;">ConsoleVisible</span> <span style="color: #008000;">=</span> <span style="color: #008000;">!</span>tools.<span style="color: #0000FF;">ConsoleVisible</span><span style="color: #000000;">&#41;</span>
&nbsp;
        <span style="color: #008080; font-style: italic;">// добавляем пункты контекстного меню</span>
        .<span style="color: #0000FF;">AddMenuItem</span><span style="color: #000000;">&#40;</span><span style="color: #666666;">&quot;About&quot;</span>, SystemIcons.<span style="color: #0000FF;">Question</span>, ShowAboutBox<span style="color: #000000;">&#41;</span>
        .<span style="color: #0000FF;">AddMenuSeparator</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span>
        .<span style="color: #0000FF;">AddMenuItem</span><span style="color: #000000;">&#40;</span><span style="color: #666666;">&quot;Hide console&quot;</span>, <span style="color: #000000;">&#40;</span>s, e<span style="color: #000000;">&#41;</span> <span style="color: #008000;">=&gt;</span> tools.<span style="color: #0000FF;">ConsoleVisible</span> <span style="color: #008000;">=</span> <span style="color: #0600FF;">false</span><span style="color: #000000;">&#41;</span>
        .<span style="color: #0000FF;">AddMenuItem</span><span style="color: #000000;">&#40;</span><span style="color: #666666;">&quot;Show console&quot;</span>, <span style="color: #000000;">&#40;</span>s, e<span style="color: #000000;">&#41;</span> <span style="color: #008000;">=&gt;</span> tools.<span style="color: #0000FF;">ConsoleVisible</span> <span style="color: #008000;">=</span> <span style="color: #0600FF;">true</span><span style="color: #000000;">&#41;</span>
        .<span style="color: #0000FF;">AddMenuSeparator</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span>
&nbsp;
        <span style="color: #008080; font-style: italic;">// метод CloseConsole() работает как нажатие кнопки [x] на окне консоли</span>
        .<span style="color: #0000FF;">AddMenuItem</span><span style="color: #000000;">&#40;</span><span style="color: #666666;">&quot;Close console&quot;</span>,
            SystemIcons.<span style="color: #0000FF;">Error</span>, <span style="color: #000000;">&#40;</span>s, e<span style="color: #000000;">&#41;</span> <span style="color: #008000;">=&gt;</span> tools.<span style="color: #0000FF;">CloseConsole</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
&nbsp;
    <span style="color: #008080; font-style: italic;">// А тут все как обычно, к примеру, RemotingConfiguration.Configure(...)</span>
    Console.<span style="color: #0000FF;">WriteLine</span><span style="color: #000000;">&#40;</span><span style="color: #666666;">&quot;Press Enter to exit...&quot;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
    Console.<span style="color: #0000FF;">ReadLine</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
<span style="color: #000000;">&#125;</span></pre></div></div>

<p>Остается только причесать немножко библиотеку и запустить ее куда-нибудь на CodePlex.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.sharp-shooter.ru/2011/02/27/notifyicon-in-console-app/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Коммандозер для всех :)</title>
		<link>http://www.sharp-shooter.ru/2008/11/10/ultima-talk/</link>
		<comments>http://www.sharp-shooter.ru/2008/11/10/ultima-talk/#comments</comments>
		<pubDate>Mon, 10 Nov 2008 18:05:53 +0000</pubDate>
		<dc:creator>yallie</dc:creator>
				<category><![CDATA[Программы]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[tools]]></category>
		<category><![CDATA[ultima]]></category>
		<category><![CDATA[work]]></category>

		<guid isPermaLink="false">http://www.sharp-shooter.ru/?p=34</guid>
		<description><![CDATA[Есть у нашей компании такой продукт — мессенджер для локальной сети, который мы устанавливаем своим клиентам впридачу к информационной системе. 
Крут этот мессенджер тем, что, во-первых, берет список контактов из ActiveDirectory (т. е. в контакт-листе автоматом находятся все доменные пользователи компании), а во-вторых — не требует никакой настройки на клиенте, берешь и запускаешь.  Можно даже с сетевого диска запускать, все равно [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.sharp-shooter.ru/wp-content/uploads/2008/11/ultimatalk.gif" rel="lightbox"><img class="alignleft size-thumbnail wp-image-44" style="margin-right: 16px; margin-bottom: 16px;" title="Скриншот коммандозера" src="http://www.sharp-shooter.ru/wp-content/uploads/2008/11/ultimatalkthumb.gif" alt="" width="117" height="170" align="left" /></a>Есть у нашей компании такой продукт — мессенджер для локальной сети, который мы устанавливаем своим клиентам впридачу к информационной системе. </p>
<p>Крут этот мессенджер тем, что, во-первых, берет список контактов из ActiveDirectory (т. е. в контакт-листе автоматом находятся все доменные пользователи компании), а во-вторых — не требует никакой настройки на клиенте, берешь и запускаешь.  Можно даже с сетевого диска запускать, все равно пользователь автоматом авторизуется под своим доменным логином и будет иметь доступ к контакт-листу и своей личной истории сообщений.</p>
<p>Первый год своего существования (а появился он в конце 2003 года) назывался он Kommandozentrum, и старые пользователи до сих пор его называют коммандозером, или еще проще — дозером. Ну, типа, «Скинь мне в дозер ссылочку на тот сайт».</p>
<p><span id="more-34"></span></p>
<p>Месяц назад наконец решились мы раздавать корпоративный мессенджер вместе с сервером <a title="Скачать Коммандозер" href="http://www.ultima.ru/talk">на халяву всем желающим</a>. Поскольку желающие теперь время от времени скачивают его с нашего сайта и задают всякие вопросы по установке сервера, я решил написать к нему побольше всякой документации и, возможно, провести что-то типа онлайн-лекции по администрированию сервера. Хотя, строго говоря, никакого там администрирования нет, нужно только один раз поставить, чтобы заработало, и забыть.</p>
<p>Так что, в ближайшие дни опубликую на этом блоге, что у меня получилось.</p>
<p>UPD. Написал два документа, но не стал публиковать в этом блоге:</p>
<ul>
<li><a title="Руководство по установке сервера Ultima::Talk" href="http://www.ultima.ru/products/satellites/talk/install/index.html">Установка сервера</a></li>
<li><a title="Конфигурация сервера Ultima::Talk" href="http://www.ultima.ru/products/satellites/talk/server_setup/index.html">Описание файла конфигурации</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.sharp-shooter.ru/2008/11/10/ultima-talk/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

