<?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>Delphi блог Димаса &#187; Статьи</title>
	<atom:link href="http://parsers.info/cat/stati/feed/" rel="self" type="application/rss+xml" />
	<link>http://parsers.info</link>
	<description>Delphi блог Димаса: программирование на delphi, парсеры, статьи, размышления</description>
	<lastBuildDate>Fri, 20 Jan 2012 19:51:36 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Контролируем буфер обмена</title>
		<link>http://parsers.info/2010/10/kontroliruem-bufer-obmena/</link>
		<comments>http://parsers.info/2010/10/kontroliruem-bufer-obmena/#comments</comments>
		<pubDate>Tue, 05 Oct 2010 18:33:10 +0000</pubDate>
		<dc:creator>crystalbit</dc:creator>
				<category><![CDATA[delphi]]></category>
		<category><![CDATA[Кодинг]]></category>
		<category><![CDATA[Статьи]]></category>
		<category><![CDATA[winapi]]></category>
		<category><![CDATA[буфер обмена]]></category>
		<category><![CDATA[работа с окнами]]></category>
		<category><![CDATA[сообщения]]></category>

		<guid isPermaLink="false">http://parsers.info/?p=739</guid>
		<description><![CDATA[Привет. В delphi для работы с буфером обмена есть модуль ClipBoard, ещё можно работать с буфером через api. Но мы сегодня не будем углубляться в работу с буфером. Наша задача &#8211; отследить изменение буфера обмена. Это всё сводится к обработке сообщения WM_DRAWCLIPBOARD, но дело в том, что никто просто так нам его не отправит.  Немного [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://parsers.info/wp-content/uploads/2010/10/clipbrd.jpg"><img class="alignleft size-full wp-image-741" title="Контролируем буфер обмена на delphi" src="http://parsers.info/wp-content/uploads/2010/10/clipbrd.jpg" alt="" width="200" height="250" /></a>Привет. В delphi для работы с буфером обмена есть модуль ClipBoard, ещё можно работать с буфером через api. Но мы сегодня не будем углубляться в работу с буфером. Наша задача &#8211; <strong>отследить изменение буфера обмена</strong>.</p>
<p>Это всё сводится к обработке сообщения <strong>WM_DRAWCLIPBOARD</strong>, но дело в том, что никто просто так нам его не отправит. <span id="more-739"></span></p>
<h3><strong>Немного теории.</strong></h3>
<p>Есть такое понятие, как <em>&laquo;Clipboard chain&raquo; </em>- назовём это цепочкой буфера обмена. Фактически в ней содержится список handle&#8217;ов окон, которым посылается сообщение<strong> WM_DRAWCLIPBOARD. </strong>На самом деле оно посылается только первому окну в цепочке. И каждое окно в этой цепочке должно (обязано :) ) обрабатывать это сообщение и ещё одно, о котором речь пойдёт дальше.</p>
<h3><strong>Поехали!</strong></h3>
<p>Итак, как же нам попасть в эту цепочку? Для этого есть функция <strong>SetClipboardViewer.</strong><br />
Создадим новый проект, на событие создания формы (или в любой другой нужный нам момент) напишем:</p>
<pre name="code" class="delphi">nhwnd:=SetClipboardViewer(Handle);</pre>
<p>nhwnd &#8211; глобальная переменная типа Cardinal (тот же THandle), в неё мы получили следующий в цепочке handle, она нам пригодится в других процедурах.</p>
<p>Теперь нужно позаботиться о том, чтобы удалять себя из цепочки в том случае, когда нам уже не нужно перехватывать обновление информации в буфере &#8211; например, при закрытии.</p>
<pre name="code" class="delphi">procedure TForm1.FormDestroy(Sender: TObject);
begin
  ChangeClipboardChain(Handle, nwnd);
end;</pre>
<p>Функция  <strong>ChangeClipboardChain</strong> удаляет нас из цепочки. Функция рассылает сообщение <strong>WM_CHANGECBCHAIN</strong> окнам цепочки, нам это сообщение также предстоит обработать. Обычно возвращает false, true только в случае, если наше окно в цепочке было единственным. Нам результат этой функции не очень-то и важен.</p>
<p>Обработаем <strong>WM_CHANGECBCHAIN</strong>. Для тех, кто подзабыл: в раздел private типа TForm1 пишем <em>procedure WMChangeCBChain(var msg: TWMChangeCBChain); message WM_CHANGECBCHAIN;</em> и обрабатываем:</p>
<pre name="code" class="delphi">procedure TForm1.WMChangeCBChain(var msg: TWMChangeCBChain);
begin
 if msg.Remove=nwnd then
   nwnd:=msg.Next
 else
   SendMessage(nwnd, WM_CHANGECBCHAIN, msg.Remove, msg.Next);
end;</pre>
<p>Здесь всё тоже несложно: если удалилось следующее в цепочке окно, берём на заметку &#8211; меняем nwnd на теперь действительное следующее окно. Иначе уведомляем следующее окно, как этого требует цепочка.</p>
<p>Осталось только обработать событие  <strong>WM_DRAWCLIPBOARD</strong>:</p>
<pre name="code" class="delphi">procedure TForm1.WMDrawClipBoard(var msg: TWMDrawClipboard);
begin
 if ClipBoard.HasFormat(CF_TEXT) then
   ShowMessage(ClipBoard.AsText)
 else
   ShowMessage('скопирован не текст');
 SendMessage(nwnd, WM_DRAWCLIPBOARD, 0, 0);
end;</pre>
<p>Вот так вот, всё просто. Смотрим, что скопировано, делаем, что нам нужно, и отправляем сообщение по цепочке дальше.</p>
<p>Не зная об этом, я раньше ставил таймер, который постоянно следил за буфером, &#8211;  систему не тормозило, но это был обходной путь. Всё равно, что арендовать квартиру на месяц, когда нужна только <a href="http://dom2.by/nasutki/">посуточная аренда</a>.</p>
<p>Для ленивых предлагаю <a href="http://parsers.info/pub/parsers_info_clipbrd.rar">скачать исходник</a>.</p>
<p>(c) crystalbit, <a href="http://parsers.info">http://parsers.info<br />
</a>При копировании материала обязательно ставить прямую ссылку на источник.</p>

	<h4>Похожие записи</h4>
	<ul class="st-related-posts">
	<li><a href="http://parsers.info/2009/04/rabotaem-s-oknami-animatewindow-i-flashwindow/" title="Работаем с окнами. AnimateWindow и FlashWindow. (30 Апрель 2009)">Работаем с окнами. AnimateWindow и FlashWindow.</a> (0)</li>
	<li><a href="http://parsers.info/2009/04/rabotaem-s-oknami-i-obektami-chast-4-funkcii-i-procedury/" title="Работаем с окнами и объектами. Часть 4. Функции и процедуры. (29 Апрель 2009)">Работаем с окнами и объектами. Часть 4. Функции и процедуры.</a> (0)</li>
	<li><a href="http://parsers.info/2009/04/rabotaem-s-oknami-i-obektami-chast-3-poisk-obektov/" title="Работаем с окнами и объектами. Часть 3. Поиск объектов. (24 Апрель 2009)">Работаем с окнами и объектами. Часть 3. Поиск объектов.</a> (0)</li>
	<li><a href="http://parsers.info/2009/04/rabotaem-s-oknami-i-obektami-chast-2/" title="Работаем с окнами и объектами. Часть 2 (22 Апрель 2009)">Работаем с окнами и объектами. Часть 2</a> (0)</li>
	<li><a href="http://parsers.info/2009/04/rabotaem-s-oknami-i-obektami-delphi-api-chast-1/" title="Работаем с окнами и объектами. Delphi. Api. Часть 1 (20 Апрель 2009)">Работаем с окнами и объектами. Delphi. Api. Часть 1</a> (0)</li>
</ul>

]]></content:encoded>
			<wfw:commentRss>http://parsers.info/2010/10/kontroliruem-bufer-obmena/feed/</wfw:commentRss>
		<slash:comments>53</slash:comments>
		</item>
		<item>
		<title>Изменение размеров буфера консольного окна</title>
		<link>http://parsers.info/2010/01/getconsolescreenbufferinfo-setconsolescreenbuffersize/</link>
		<comments>http://parsers.info/2010/01/getconsolescreenbufferinfo-setconsolescreenbuffersize/#comments</comments>
		<pubDate>Wed, 20 Jan 2010 17:20:32 +0000</pubDate>
		<dc:creator>crystalbit</dc:creator>
				<category><![CDATA[delphi]]></category>
		<category><![CDATA[Кодинг]]></category>
		<category><![CDATA[Статьи]]></category>
		<category><![CDATA[winapi]]></category>

		<guid isPermaLink="false">http://parsers.info/?p=541</guid>
		<description><![CDATA[Привет! Это второй пост, который был потерян когда-то в июле в связи с переездом на другой хостинг. Речь пойдёт о так называемом Screen Buffer. Консольное окно само по себе имеет определенные размеры, обычно 24 на 80 символов. Также справа есть полоса прокрутки, с помощью неё можно увидеть то, что вышло за рамки экрана, так как [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://parsers.info/wp-content/uploads/2010/01/cmd.png" alt="SetConsoleScreenBufferSize: изменение размеров буфера консольного окна" title="Изменение размеров буфера консольного окна" width="182" height="286" class="alignleft size-full wp-image-543" />Привет! Это второй пост, который был потерян когда-то в июле в связи с переездом на другой хостинг.<br />
Речь пойдёт о так называемом <strong>Screen Buffer</strong>.<br />
Консольное окно само по себе имеет определенные размеры, обычно 24 на 80 символов.<br />
<span id="more-541"></span><br />
Также справа есть полоса прокрутки, с помощью неё можно увидеть то, что вышло за рамки экрана, так как когда мы всё пишем и пишем, например с помощью <em>процедуры writeln</em>, доходим до строки номер 24 и пишем дальше, то всё сдвигается. Или когда с помощью <strong>api функции SetConsoleCursorPosition</strong> или через <em>GotoXY</em> из <a href="http://parsers.info/2009/04/modul-crt-dlya-delphi-2/">модуля crt для delphi </a>ставим курсор на место, расположенное ниже досягаемого нами пространства.<br />
Всё, что можно увидеть с помощью прокрутки, и есть Screen Buffer.</p>
<p>Чтобы поменять его размеры, нужно познакомиться с ним поближе.</p>
<h3>Что нам о нём известно?</h3>
<p>Его размеры можно получить с помощью api функции <strong>GetConsoleScreenBufferInfo</strong>, вот её синтаксис:</p>
<pre name="code" class="delphi">function GetConsoleScreenBufferInfo(hConsoleOutput: THandle; var lpConsoleScreenBufferInfo: TConsoleScreenBufferInfo): BOOL;</pre>
<p>По порядку:<br />
<strong>hConsoleOutput: THandle</strong> &#8211; handle вывода консольного окна, его нам вернёт api функция <strong>GetStdHandle</strong> с параметром <strong>STD_OUTPUT_HANDLE</strong>;<br />
<strong>lpConsoleScreenBufferInfo: TConsoleScreenBufferInfo</strong> &#8211; сюда передаём объект типа TConsoleScreenBufferInfo</p>
<p>Структура <strong>CONSOLE_SCREEN_BUFFER_INFO</strong>, она же TConsoleScreenBufferInfo, она же _CONSOLE_SCREEN_BUFFER_INFO:</p>
<pre name="code" class="delphi">
  _CONSOLE_SCREEN_BUFFER_INFO = packed record
    dwSize: TCoord;
    dwCursorPosition: TCoord;
    wAttributes: Word;
    srWindow: TSmallRect;
    dwMaximumWindowSize: TCoord;
  end;
</pre>
<p>Функция GetConsoleScreenBufferInfo её нам заполнила, что мы получили:<br />
<strong>dwSize: TCoord</strong> &#8211; размер буфера, вот он! (по умолчанию 80 на 300 символов)<br />
<strong>dwCursorPosition: TCoord</strong> &#8211; положение курсора, тоже полезно, вполне заменит паскалевские <strong>WhereX</strong> и <strong>WhereY</strong>, они также реализованы в моём <a href="http://parsers.info/2009/04/modul-crt-dlya-delphi-2/">модуле crt</a><br />
<strong>wAttributes: Word</strong> &#8211; не экспериментировал с этим, вроде цвета<br />
<strong>srWindow: TSmallRect</strong> &#8211; тоже не экспериментировал, по msdn это координаты окна, уточни какого и напиши в комментарии, ок?<br />
<strong>dwMaximumWindowSize: TCoord</strong> &#8211; максимальный размер буфера, в символах, естественно.</p>
<h3>Меняем размер Screen Buffer</h3>
<p>Ну и кульминация, <strong>функция SetConsoleScreenBufferSize</strong>:</p>
<pre name="code" class="delphi">SetConsoleScreenBufferSize(hConsoleOutput: THandle; dwSize: TCoord): BOOL;</pre>
<p>Передаём тот же handle вывода, и структуру TCoord с нужным нам размером.</p>
<h3>Как же без примера?</h3>
<pre name="code" class="delphi">
const
  NewSize: TCoord = (x: 80; y: 10000);

...
  SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), NewSize);
</pre>
<p>Здесь размер буфера окна стал 80 на 10000.</p>
<p><em>Постовой:</em><br />
А тем временем Zdez Bil Ya в своём <a href="http://avtuh.ru">добром-добром блоге</a> пишет про delphi и пароли в qip.</p>

	<h4>Похожие записи</h4>
	<ul class="st-related-posts">
	<li><a href="http://parsers.info/2010/10/kontroliruem-bufer-obmena/" title="Контролируем буфер обмена (5 Октябрь 2010)">Контролируем буфер обмена</a> (51)</li>
</ul>

]]></content:encoded>
			<wfw:commentRss>http://parsers.info/2010/01/getconsolescreenbufferinfo-setconsolescreenbuffersize/feed/</wfw:commentRss>
		<slash:comments>16</slash:comments>
		</item>
		<item>
		<title>Функция copy или восстанавливаем пароль icq после заражения вирусом Piggy.</title>
		<link>http://parsers.info/2010/01/function-copy-ili-vosstanavlivaem-parol-icq-posle-zarazheniya-virusom-piggy/</link>
		<comments>http://parsers.info/2010/01/function-copy-ili-vosstanavlivaem-parol-icq-posle-zarazheniya-virusom-piggy/#comments</comments>
		<pubDate>Tue, 19 Jan 2010 15:28:41 +0000</pubDate>
		<dc:creator>crystalbit</dc:creator>
				<category><![CDATA[delphi]]></category>
		<category><![CDATA[Кодинг]]></category>
		<category><![CDATA[Новости]]></category>
		<category><![CDATA[Статьи]]></category>
		<category><![CDATA[icq]]></category>
		<category><![CDATA[парсер]]></category>

		<guid isPermaLink="false">http://parsers.info/?p=518</guid>
		<description><![CDATA[Привет, ты наверняка уже наслышан о недавно появившемся вирусе Piggy. Если не в курсе, буду краток: он использует принцип спама по цепочке. Вот тебе приходит ссылка от человека, мол, flash игра прикольная. Ты пишешь, мол, ага, знаем, спам. И тебе в ответ: нет, мол, не спам, ага. Качаешь, так как немного пьян, и с твоим [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://parsers.info/wp-content/uploads/2010/01/pig.jpg"><img src="http://parsers.info/wp-content/uploads/2010/01/pig.jpg" alt="" title="Получаем пароль после действия вируса piggy" width="369" height="229" class="aligncenter size-full wp-image-519" /></a></p>
<p>Привет, ты наверняка уже наслышан о недавно появившемся<em> вирусе Piggy</em>. Если не в курсе, буду краток: он использует принцип спама по цепочке.<br />
Вот тебе приходит ссылка от человека, мол, flash игра прикольная. Ты пишешь, мол, ага, знаем, спам. И тебе в ответ: нет, мол, не спам, ага. Качаешь, так как немного пьян, и с твоим номером происходит то же самое: пароль меняется, а эта программа висит некоторое время как icq-бот и предлагает твоим друзьям, которые в контакт-листе, скачать себя. Реагирует на слова &laquo;бот&raquo;, &laquo;спам&raquo; и прочие по-разному, отвечает, даже меняет статус на &laquo;печатает&#8230;&raquo;. Некоторые индивиды окрестили этот вирус как вирус с &laquo;искуственным интеллектом&raquo;, так как сейчас такое &#8211; большая редкость.<span id="more-518"></span><br />
Думаю, со временем такие боты-болтуны захватят этот мир.</p>
<p>Ну что, если такое случилось, то есть возможность вернуть пароль. Автор программы, видимо, ставил эксперимент :) На хабре появилось сообщение о том, как вернуть пароль: piggy меняет также информацию о пользователе, там теперь можно найти 80 цифр в двоичной системе &#8211; 0 или 1.<br />
Например, 01011001100101101010010110100001001100000101101000010110110001011011000101101000 это 57606886. Можно не пытаться переводить в десятичную систему, там просто шифр.<br />
Вот статья &#8211; <a href="http://habrahabr.ru/blogs/infosecurity/81172/" rel="nofollow">link</a></p>
<p>А вот шифр, который уже разлетелся по интернетам:</p>
<pre>0100110010: 1
0101100000: 2
0101100010: 3
0101100100: 4
0101100110: 5
0101101000: 6
0101101010: 7
0101101100: 8
0101101110: 9
0100110000: 0
</pre>
<p>Символы идут подряд, без пробелов.</p>
<p>Итак, суть сегодняшнего поста.</p>
<p><strong>Функция copy</strong><br />
Призвана получить часть строки из целой. Синтаксис:</p>
<pre name="code" class="delphi">function Copy(S; Index, Count: Integer): string;</pre>
<p>S &#8211; строка или массив, а в нашем случае строка. Index &#8211; с какого символа брать кусок (первый символ это первый символ, а не нулевой), Count это, очевидно, количество.<br />
Это конец теории, далее только код и ссылки на скачку.</p>
<p><strong>Введём массив значений</strong></p>
<pre name="code" class="delphi">
const
  csymbs:array[0..9] of string=('0100110000', '0100110010',
                                '0101100000', '0101100010',
                                '0101100100', '0101100110',
                                '0101101000', '0101101010',
                                '0101101100', '0101101110' );
</pre>
<p>Начиная с нуля. Таким приёмом пользуются, чтобы, например, брать имена месяцев из массива.</p>
<p>Теперь получим по шифру его значение. <strong>Сначала для одного символа.</strong></p>
<pre name="code" class="delphi">
function checksymbol(c: string): string;
var
  i:integer;
begin
  result:='n'; // на случай чего-то не того
  for i:=0 to 9 do
    if csymbs[i]=c then Result:=IntToStr(i);
end;
</pre>
<p>Очевидно, мы передадим нашей функции строки из восьми символов.</p>
<p><strong>А теперь общую функцию</strong><br />
Простой цикл, плюс функция copy.</p>
<pre name="code" class="delphi">
function decode(c: string):string;
var
  i:integer;
begin
  for i:=0 to 7 do
    result:=result+checksymbol(copy(c, i*10+1, 10));
end;
</pre>
<p>Само приложение я сделал консольным, использовал модули windows, sysutils и clipbrd. Хоть и консольное, но получилось 368Кб.<br />
<strong>Как оно работает:</strong> копируем в буфер обмена шифр, запускаем программу и получаем результат.</p>
<p><strong><a href="http://parsers.info/pub/hellopiggy/hellopiggy.exe">Скачать парсер пароля :)</a><br />
<a href="http://parsers.info/pub/hellopiggy/hellopiggy.dpr">Скачать исходник</a></strong></p>
<p>(c) crystalbit, <a href="http://parsers.info">http://parsers.info</a></p>
<p>Теперь немного ссылок:</p>
<ul>
<li/>статья по теме на блоге программиста &#8211; <a href="http://eax.me/icq-virus-h1n1-piggy/">link</a><br />
В этой статье я нашел картинку:<br />
<img src="http://eax.me/files/2010/01/piggy-grab.png" alt="piggy :)" /><br />
По ней можно видеть действие вируса.</p>
<li/>и, в качестве постового, я хочу, чтобы ты обратил внимание на <a href="http://greenkaktus.wordpress.com">блог зелёного кактуса</a>, где он выкладывает вкусности интернета.</ul>

	<h4>Похожие записи</h4>
	<ul class="st-related-posts">
	<li><a href="http://parsers.info/2008/06/zparser/" title="zparser (23 Июнь 2008)">zparser</a> (0)</li>
	<li><a href="http://parsers.info/2009/04/vkontakte-friends-gop-stoper/" title="Vkontakte Friends Gop-Stoper by faza02 (27 Апрель 2009)">Vkontakte Friends Gop-Stoper by faza02</a> (2)</li>
	<li><a href="http://parsers.info/2008/11/reparser/" title="reparser (30 Ноябрь 2008)">reparser</a> (4)</li>
	<li><a href="http://parsers.info/2008/06/qa-bot/" title="q/a bot (27 Июнь 2008)">q/a bot</a> (5)</li>
	<li><a href="http://parsers.info/2008/06/ipdcapture-v2final/" title="IPDCapture v2FINAL (21 Июнь 2008)">IPDCapture v2FINAL</a> (1)</li>
</ul>

]]></content:encoded>
			<wfw:commentRss>http://parsers.info/2010/01/function-copy-ili-vosstanavlivaem-parol-icq-posle-zarazheniya-virusom-piggy/feed/</wfw:commentRss>
		<slash:comments>45</slash:comments>
		</item>
		<item>
		<title>WinSock: HTTP-запрос с помощью блокирующего сокета</title>
		<link>http://parsers.info/2010/01/winsock-http-zapros-s-pomoshhyu-blokiruyushhego-soketa/</link>
		<comments>http://parsers.info/2010/01/winsock-http-zapros-s-pomoshhyu-blokiruyushhego-soketa/#comments</comments>
		<pubDate>Tue, 12 Jan 2010 15:25:35 +0000</pubDate>
		<dc:creator>crystalbit</dc:creator>
				<category><![CDATA[delphi]]></category>
		<category><![CDATA[Кодинг]]></category>
		<category><![CDATA[Статьи]]></category>
		<category><![CDATA[winsock]]></category>

		<guid isPermaLink="false">http://parsers.info/?p=508</guid>
		<description><![CDATA[Сегодня хочу начать цикл заметок о winsock. Около года назад я этим заинтересовался, потом незаслуженно забыл и забросил. WinSock &#8211; достаточно мощный инструмент, основа всех основ. Если ты пишешь программу на чистом api, тебе важен конечный размер программы или работаешь с хитрым протоколом, то сокеты просто незаменимы. В этой заметке рассмотрим, как открыть сокет и [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://parsers.info/wp-content/uploads/2010/01/winsock.png" alt="Синхронный сокет winsock. GET запрос" title="HTTP-запрос с помощью блокирующего (синхронного) сокета." width="348" height="144" class="aligncenter size-full wp-image-509" /></p>
<p>Сегодня хочу начать цикл заметок о winsock. Около года назад я этим заинтересовался, потом незаслуженно забыл и забросил.<br />
<strong>WinSock</strong> &#8211; достаточно мощный инструмент, основа всех основ. Если ты пишешь программу на чистом api, тебе важен конечный размер программы или работаешь с хитрым протоколом, то сокеты просто незаменимы. В этой заметке рассмотрим, как открыть сокет и послать GET запрос серверу.<br />
<span id="more-508"></span></p>
<h3>Типы сокетов</h3>
<p>Вкратце. Есть сокеты <strong>синхронные</strong>, с ними работать удобнее. Программа (поток) будет ждать, пока запрос посылается, или же ждать ответа. Такие сокеты также называются <strong>блокирующими</strong>, и речь сегодня пойдёт о них.<br />
Второй тип &#8211; <strong>асинхронные</strong> или <strong>неблокирующие</strong> сокеты. Из названия вполне очевидно, что, посылая запрос, мы не будем ничего ждать. Нам достаточно будет или иногда проверять состояние, или назначить событие, в разных версиях winsock существует две возможные тактики. Также массив асинхронных сокетов вполне заменяет многопоточность.</p>
<h3>Инициализируем winsock</h3>
<p>Сперва подключим модуль <strong>winsock</strong>. Теперь нам необходимо инициализировать winsock, для этого нам потребуется функция WSAStartup. Я использую её следующим образом:</p>
<pre name="code" class="delphi">
  if WSAStartup(MAKEWORD(2,2), WSAData1)<>0 then begin
    writeln('WinSock error');
    readln;
    Exit;
  end;
</pre>
<p>MAKEWORD(2,2) &#8211; просто константа, точнее возвращает константу, можешь писать $101. WSAData1 &#8211; структура типа TWSAData. Не забудь объявить такую :) Как ты уже заметил, в случае успешной инициализации функция возвращает 0, иначе ошибка. Структура TWSAData (WSAData) и коды ошибок есть в msdn, не будем углубляться в голую теорию.<br />
Еще замечу, что я пишу консольное приложение, пусть writeln и readln не смущают читателя.</p>
<h3>Создадим сокет</h3>
<p>Сокет &#8211; как красиво звучит. А это всего лишь число, эх. <strong>Socket1:TSocket</strong>, <strong>Socket1:integer</strong> &#8211; так надо объявить (TSocket сам по себе integer). Создаём функцией <strong>Socket</strong>:</p>
<pre name="code" class="delphi">
  Socket1:=Socket(AF_INET,SOCK_STREAM,0);
  if Socket1=INVALID_SOCKET then begin
    writeln('socket error');
    readln;
    Exit;
  end;
</pre>
<p>Всё достаточно ясно, примем как есть, нудной теорией займёмся как-нибудь потом.</p>
<h3>Устанавливаем соединение.</h3>
<p>Сокет &#8211; это тебе не Indy или Synapse, здесь запрос делается только после установления соединения (мы сейчас про TCP, UDP не будем затрагивать). Как же нам установить соединение? Объявим следующую переменную: <strong>SockAddr1:TSockAddr;</strong>. Это структура, в ней укажем протокол, адрес сервера и порт:</p>
<pre name="code" class="delphi">
  SockAddr1.sin_family:=AF_INET;
  SockAddr1.sin_addr.S_addr:=inet_addr(PChar('62.109.19.221'));
  SockAddr1.sin_port:=htons(80);
</pre>
<p>Таким образом мы можем указать только ip-адрес. Получению dns будет посвящён отдельный пост. IP-адрес я указал своего блога :)<br />
Теперь <strong>функция connect</strong>:</p>
<pre name="code" class="delphi">
  if Connect(Socket1,SockAddr1,SizeOf(SockAddr1))<>0 then begin
    writeln('connection error #',WSAGetLastError);
    readln;
    exit;
  end;
</pre>
<p><strong>WSAGetLastError</strong> выполняет функции, аналогичные GetLastError, то есть возвращает код ошибки winsock.<br />
Если нет никаких ошибок, то на данный момент мы уже подключены к серверу.</p>
<h3>Send &#8211; посылаем запрос</h3>
<p>Объявим две переменных:</p>
<pre name="code" class="delphi">
  Buffer1:string;
  Buffer2:array[1..1024] of char;
</pre>
<p>В одной будем формировать запрос, в другую будем порциями писать ответ сервера.</p>
<p>Сначала, конечно, надо сформировать запрос. Если ты хотя бы поверхностно знаком с http протоколом, то это не составит труда:</p>
<pre name="code" class="delphi">
  Buffer1:='GET / HTTP/1.1'#13#10+
           'host: parsers.info'#13#10+
           'Connection: close'#13#10+
           #13#10;
</pre>
<p>А теперь можно и послать этот запрос:</p>
<pre name="code" class="delphi">
  if send(Socket1,Buffer1[1],Length(Buffer1),0)=SOCKET_ERROR then begin
    writeln('socket error #',WSAGetLastError);
    readln;
    exit;
  end;
</pre>
<p>Спасибо <em>A.Truhin</em> за замечание, код выше исправлен, и теперь проверяется возвращаемое значение функции send. Она возвращает количество переданных байт, а в случае ошибки -1, то есть SOCKET_ERROR.<br />
Мы передали начало буфера и его длину. Так как наш сокет блокирующий, то всё, что написано после send, будет выполнено после того, как пройдёт запрос. А после этого нам предстоит ждать ответа :)</p>
<h3>Reсv &#8211; получаем ответ</h3>
<p>Мы знаем, что ответ должен быть, так как мы работаем с http протоколом. Поэтому сразу претендуем на ответ от сервера. Наш помощник &#8211; <strong>функция recv</strong>.</p>
<pre name="code" class="delphi">
  repeat
    FillChar(Buffer2,SizeOf(Buffer2),0);
    d:=recv(Socket1,Buffer2,SizeOf(Buffer2),0);
    for i:=1 to d do write(Buffer2[i]);
  until d<=0;
</pre>
<p>Небольшое пояснение. Recv читает из буфера сокета, в который он получает ответ. То есть мы ждём ответа, а потом читаем из буфера сокета. Если мы не прочитаем, то данные там и останутся, и при следующем вызове recv мы их и получим. Функция recv возвращает нам количество полученных байт, если это ноль, то всё, больше ничего нет. Моё цикл просто выводит на экран ответ сервера, он содержит тело ответа и html-код моего сайта.</p>
<h3>Закроем сокет и подведём итог.</h3>
<pre name="code" class="delphi">
if CloseSocket(Socket1)<>0 then
  writeln('error closing socket');
</pre>
<p>Итог: <em>winsock - это просто!</em><br />
<a href="http://parsers.info/pub/httpget.dpr">Скачать исходник!</a><br />
И в заключение хочу отметить, что вес нашей программы всего 17Кб! Неплохо для работы с интернетом? :)</p>
<p>(c) crystalbit, <a href="http://parsers.info">http://parsers.info</a><br />
Подпишись на <a href="http://feeds.feedburner.com/parsers">RSS ленту</a>, и я обещаю тебе много интересного материала по сокетам!</p>

	<h4>Похожие записи</h4>
	<ul class="st-related-posts">
	<li><a href="http://parsers.info/2010/01/winsock-poluchenie-xosta-po-adresu/" title="WinSock: Получение хоста по адресу (27 Январь 2010)">WinSock: Получение хоста по адресу</a> (13)</li>
</ul>

]]></content:encoded>
			<wfw:commentRss>http://parsers.info/2010/01/winsock-http-zapros-s-pomoshhyu-blokiruyushhego-soketa/feed/</wfw:commentRss>
		<slash:comments>16</slash:comments>
		</item>
		<item>
		<title>Парсим csv и tsv файлы в delphi</title>
		<link>http://parsers.info/2010/01/parsim-csv-i-tsv-v-delphi/</link>
		<comments>http://parsers.info/2010/01/parsim-csv-i-tsv-v-delphi/#comments</comments>
		<pubDate>Tue, 12 Jan 2010 10:31:50 +0000</pubDate>
		<dc:creator>crystalbit</dc:creator>
				<category><![CDATA[delphi]]></category>
		<category><![CDATA[Кодинг]]></category>
		<category><![CDATA[Статьи]]></category>
		<category><![CDATA[csv]]></category>
		<category><![CDATA[tsv]]></category>
		<category><![CDATA[парсинг]]></category>

		<guid isPermaLink="false">http://parsers.info/?p=505</guid>
		<description><![CDATA[Читая иностранные блоги, наткнулся на пост, в котором поднимается проблема парсинга и отображения в TStringGrid tsv файлов (tab-separated values &#8211; значения, разделенные символом табуляции, англ.). В таких файлах элементы в строках разделены знаком табуляции (девятым символом). Также не хочется забывать про не менее популярный формат csv &#8211; comma-separated values &#8211; в нём элементы разделены запятой. [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://parsers.info/wp-content/uploads/2010/01/parsingcsv.png" alt="Парсинг csv на delphi" title="Парсим csv и tsv на delphi" width="252" height="131" class="aligncenter size-full wp-image-504" /><br />
Читая иностранные блоги, наткнулся на пост, в котором поднимается проблема <em>парсинга и отображения</em> в TStringGrid <strong>tsv файлов</strong> (tab-separated values &#8211; значения, разделенные символом табуляции, англ.). В таких файлах элементы в строках разделены знаком табуляции (девятым символом). Также не хочется забывать про не менее популярный <strong>формат csv</strong> &#8211; comma-separated values &#8211; в нём элементы разделены запятой. Стоит сказать, что программы для работы с таблицами просто обязаны читать эти два формата.<br />
<span id="more-505"></span></p>
<h3>[Матчасть]</h3>
<p>Как оказалось, delphi нам уже всё подготовил. Мы будем использовать два объекта <strong>TStringList</strong> и, очевидно, <strong>TStringGrid</strong>.<br />
У объекта TStringList есть свойство <strong>Delimiter</strong> (разделитель &#8211; англ.). А сам TStringList по сути своей &#8211; массив строк.<br />
<strong>DelimitedText</strong> &#8211; string. Строка, присвоенная DelimitedText, разобьётся, согласно Delimiter, и у нас становится TStringList с элементами строки. Впрочем, тот же explode на php.<br />
<strong>QuoteChar</strong> &#8211; это свойство нам сегодня не пригодится, но упомянуть стоит. Например, у нас есть строка <i>&laquo;delimiter&raquo;;&raquo;delimitedtext&raquo;;&raquo;quotechar&raquo;;&raquo;tstringlist&raquo;</i>. Элементы в ней не только разделены точкой с запятой, но еще и заключены в кавычки. В этом случае Delimiter ставим как <b>;</b>, а QuoteChar как <b>&laquo;</b>. И легким движением руки мы получаем список из ключевых слов данного поста :)<br />
Хотел сначала написать, что функция explode на php так не может (ха-ха), а потом прочитал, что там есть готовая функция fgetcsv, Нагайченко Максим написал об этом <a href="http://nagaychenko.com/blog/2009/11/28/парсинг-csv-файлов/">в посте на своём блоге</a>.</p>
<h3>Готовим TStringGrid</h3>
<p>Для будущей загрузки таблицы, в Object Inspector я изначально поставил <em>ColCount=1</em>, а <em>FixedCols</em> и <em>FixedRows</em> обратил в ноль.</p>
<h3>Парсим csv</h3>
<p>Допустим, у нас есть таблица <em>c:\table.csv</em>, которую нам предстоит загрузить в TStringGrid.<br />
Наши действия: каждую строку построчно разбиваем на элементы с помощью вышеописанных свойств и вставляем в TStringGrid.<br />
В примере я использовал второй TStringList для открытия файла. Для больших таблиц также неплохо будет использование стандартного построчного получения файла, перешедшего из паскаля (AssignFile, Reset, ReadLn), но сегодня акцент не на этом.</p>
<p>Код:</p>
<pre name="code" class="delphi">
procedure TForm1.Button1Click(Sender: TObject);
var
  sdata, srow: TStrings;
  i:integer;
begin
  sdata:=TStringList.Create;
  srow:=TStringList.Create;
  srow.Delimiter:=',';
  sdata.LoadFromFile('c:\table.csv');
  StringGrid1.RowCount:=sdata.Count;
  for i:=0 to sdata.Count-1 do begin
    srow.DelimitedText:=sdata[i];
    if srow.Count>StringGrid1.ColCount then
      StringGrid1.ColCount:=srow.Count;
    StringGrid1.Rows[i].Assign(srow);
  end;
  srow.Free;
  sdata.Free;
end;
</pre>
<p>Небольшие пояснения: в sdata загружаем файл, строки из sdata по очереди парсим в srow, который каждый раз присваиваем следующей строке TStringGrid.</p>
<h3>Про tsv и прочее</h3>
<p>Для парсинга tsv свойству Delimiter нужно присвоить значение табуляции. Это девятый символ, #9, chr(9) &#8211; так можно записать. Согласно википедии, csv и tsv объединяет формат dsv &#8211; delimiter-separated values, собственно его мы сегодня и отпарсили.</p>
<p>(c) crystalbit, <a href="http://parsers.info">http://parsers.info</a><br />
<a href="feeds.feedburner.com/parsers" rel="nofollow">RSS поток</a> &#8211; будь в курсе!</p>

	<h4>Похожие записи</h4>
	<ul class="st-related-posts">
	<li><a href="http://parsers.info/2010/01/postrochnyj-parsing/" title="Построчный парсинг (22 Январь 2010)">Построчный парсинг</a> (24)</li>
	<li><a href="http://parsers.info/2010/04/parsim-daty-apdejtov-s-glavnoj-pr-cy/" title="Парсим даты апдейтов с главной pr-cy (13 Апрель 2010)">Парсим даты апдейтов с главной pr-cy</a> (103)</li>
	<li><a href="http://parsers.info/2010/09/opredelyaem-webmoney-bl/" title="Определяем WebMoney BL (28 Сентябрь 2010)">Определяем WebMoney BL</a> (85)</li>
	<li><a href="http://parsers.info/2009/05/kolichestvo-podstrok-v-stroke/" title="Количество подстрок в строке. (21 Май 2009)">Количество подстрок в строке.</a> (3)</li>
</ul>

]]></content:encoded>
			<wfw:commentRss>http://parsers.info/2010/01/parsim-csv-i-tsv-v-delphi/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Перечисление всех компонентов на форме</title>
		<link>http://parsers.info/2009/12/perechislenie-vsex-komponentov-na-forme/</link>
		<comments>http://parsers.info/2009/12/perechislenie-vsex-komponentov-na-forme/#comments</comments>
		<pubDate>Wed, 23 Dec 2009 15:40:12 +0000</pubDate>
		<dc:creator>crystalbit</dc:creator>
				<category><![CDATA[delphi]]></category>
		<category><![CDATA[Кодинг]]></category>
		<category><![CDATA[Статьи]]></category>
		<category><![CDATA[sender]]></category>

		<guid isPermaLink="false">http://parsers.info/?p=452</guid>
		<description><![CDATA[Сегодня рассмотрим вопрос о том, как перечислить все компоненты на форме. Например, как очистить все TEdit одним циклом, как изменить надписи на всех TLabel, как нажать все TButton :) В заметке про создание кнопок с использованием TImage я уже испольовал данный приём, теперь рассмотрим подробнее. 0. Матчасть У объекта TForm (а также других, на которых [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://parsers.info/wp-content/uploads/2009/12/perkomp.png"><img src="http://parsers.info/wp-content/uploads/2009/12/perkomp.png" alt="" title="Перечисление компонентов в delphi. Очистка всех TEdit" width="277" height="174" class="aligncenter size-full wp-image-451" /></a></p>
<p>Сегодня рассмотрим вопрос о том, как перечислить все компоненты на форме. Например, как очистить все TEdit одним циклом, как изменить надписи на всех TLabel, как нажать все TButton :)<br />
В заметке про <a href="http://parsers.info/2009/12/sender-sozdayom-svoj-stil-knopok/">создание кнопок с использованием TImage</a> я уже испольовал данный приём, теперь рассмотрим подробнее.<br />
<span id="more-452"></span></p>
<h3>0. Матчасть</h3>
<p>У объекта TForm (а также других, на которых можно поставить, например, кнопку) есть массив <strong>Components</strong>. Очевидно, так мы можем обращаться ко всем объектам на форме.<br />
Количество объектов &#8211; свойство <strong>ComponentCount</strong>. Первый объект имеет индекс 0, последний ComponentCount-1.</p>
<h3>1. Просто перечислим имена компонентов</h3>
<p>Запишем в Memo, другой наглядной реализации в голову не пришло</p>
<pre name="code" class="delphi">
var
  i:integer;
begin
  for i:=0 to ComponentCount-1 do
    Memo1.Lines.Add(Components[i].Name);
end;
</pre>
<p>Теперь в Memo1 у нас имена всех компонентов.</p>
<h3>2. Конкретизируем задачу</h3>
<p>Будем использовать <a href="http://parsers.info/2009/12/operatory-as-i-is-delphi/">операторы is и as</a>, тут без них никак:</p>
<pre name="code" class="delphi">
var
  i:integer;
begin
  for i:=0 to ComponentCount-1 do
    if Components[i] is TLabel then
	  Memo1.Lines.Add((Components[i] as TLabel).Caption);
end;
</pre>
<p>Вот так просто мы получили все надписи на объектах TLabel. Теперь давай сделаем их невидимыми &#8211; пусть никто не прочитает :)</p>
<pre name="code" class="delphi">
var
  i:integer;
begin
  for i:=0 to ComponentCount-1 do
    if Components[i] is TLabel then
	  (Components[i] as TLabel).Visible:=False;
end;
</pre>
<h3>3. Итог</h3>
<p>Теперь мы крутые, и нам не нужно прописывать:</p>
<pre name="code" class="delphi">
Label1.Visible:=False;
Label2.Visible:=False;
...
</pre>
<p>Наконец, хочу сделать картинку к этому посту в моём <a href="http://parsers.info">delphi блоге</a>. Я поставил на форму в случайном порядке несколько TLabel и TEdit, поставил кнопку, по нажатию на которую написал:</p>
<pre name="code" class="delphi">
procedure TForm1.Button1Click(Sender: TObject);
var
  i:integer;
begin
  for i:=0 to ComponentCount-1 do
    if Components[i] is TLabel then
	    (Components[i] as TLabel).Caption:='http://parsers.info'
    else if Components[i] is TEdit then
      (Components[i] as TEdit).Text:='crystalbit';
end;
</pre>
<p>Запустил, нажал на неё. А результат смотри в начале этого поста :)</p>
<h3>5. Замечание</h3>
<p>Если используешь фреймы на форме, то этот механизм может не сработать.<br />
Спасибо Алексею Тимохину</p>
<h3>6. Вариант с рекурсией от JayDi</h3>
<p>Подходит для фреймов</p>
<pre name="code" class="delphi">
procedure FillChildComponentsList(const SourceComponent: TComponent;
  var ChildsList: TList);
var
  I: Integer;
begin
  //рекурсивный поиск дочерних компонентов
  for I := 0 to SourceComponent.ComponentCount - 1 do
  begin
    ChildsList.Add(SourceComponent.Components[I]);
    FillChildComponentsList(SourceComponent.Components[I], ChildsList);
  end;
end;  

procedure Tf_TestFrameComponents.Button_TestComponentsClick(Sender: TObject);
var
  FoundedComponentsList: TList;
  I: Integer;
  Comp: TComponent;
begin
  //получение списка компонетов
  FoundedComponentsList := TList.Create;
  FillChildComponentsList(Self, FoundedComponentsList);  

  //смена текста у всех лейблов
  for I := 0 to FoundedComponentsList.Count - 1 do
  begin
    Comp := FoundedComponentsList[I];
    if Comp is TLabel then
    begin
      (Comp as TLabel).Caption := 'Its work!';
    end;
  end;  

  FreeAndNil(FoundedComponentsList);
end;
</pre>
<p>(c) crystalbit, <a href="http://parsers.info">http://parsers.info</a><br />
а еще на блоге есть <a href="http://feeds.feedburner.com/parsers" rel="nofollow">rss-лента</a>!</p>
<p>P.S. можно писать посты в блог, можно пытаться <a href="http://www.web-article.com.ua/2008/kak-sdelat-ssilku-flash-banner">сделать ссылку во флеш</a>, в любом случае надо усердно работать.</p>

	<h4>Похожие записи</h4>
	<ul class="st-related-posts">
	<li><a href="http://parsers.info/2009/12/parametr-sender-v-obrabotchikax-sobytij-event-handlers-na-delphi/" title="Параметр Sender в обработчиках событий (event handlers) на delphi. (14 Декабрь 2009)">Параметр Sender в обработчиках событий (event handlers) на delphi.</a> (10)</li>
	<li><a href="http://parsers.info/2009/12/operatory-as-i-is-delphi/" title="Операторы as и is или &laquo;английский язык произошел от дельфи&raquo;. (16 Декабрь 2009)">Операторы as и is или &laquo;английский язык произошел от дельфи&raquo;.</a> (3)</li>
	<li><a href="http://parsers.info/2009/12/sender-sozdayom-svoj-stil-knopok/" title="Sender: немного практики, или создаём свой стиль кнопок. (19 Декабрь 2009)">Sender: немного практики, или создаём свой стиль кнопок.</a> (7)</li>
</ul>

]]></content:encoded>
			<wfw:commentRss>http://parsers.info/2009/12/perechislenie-vsex-komponentov-na-forme/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>Sender: немного практики, или создаём свой стиль кнопок.</title>
		<link>http://parsers.info/2009/12/sender-sozdayom-svoj-stil-knopok/</link>
		<comments>http://parsers.info/2009/12/sender-sozdayom-svoj-stil-knopok/#comments</comments>
		<pubDate>Sat, 19 Dec 2009 19:54:23 +0000</pubDate>
		<dc:creator>crystalbit</dc:creator>
				<category><![CDATA[delphi]]></category>
		<category><![CDATA[Кодинг]]></category>
		<category><![CDATA[Статьи]]></category>
		<category><![CDATA[sender]]></category>

		<guid isPermaLink="false">http://parsers.info/?p=442</guid>
		<description><![CDATA[Полтора года назад писал такую статью на одном форуме, на блоге этого нет. В связи с тем, что на этой неделе поднял тему использования Sender: TObject и операторов as и is, распишу всё заново здесь и сейчас :) Мы используем TImage, столько TImage, сколько нужно кнопок. Подготовка У наших кнопок будет три состояния &#8211; нажата, [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://parsers.info/wp-content/uploads/2009/12/button.jpg" alt="Создаём свои кнопки, используя TImage и параметр Sender. На delphi" title="Создаём свои кнопки, используя TImage и параметр Sender. На delphi" width="199" height="214" class="size-full wp-image-443" /><br />
Полтора года назад писал такую статью на одном форуме, на блоге этого нет. В связи с тем, что на этой неделе поднял тему использования <a href="http://parsers.info/2009/12/parametr-sender-v-obrabotchikax-sobytij-event-handlers-na-delphi/">Sender: TObject</a> и операторов <a href="http://parsers.info/2009/12/operatory-as-i-is-delphi/">as и is</a>, распишу всё заново здесь и сейчас :)<br />
<span id="more-442"></span><br />
Мы используем TImage, столько TImage, сколько нужно кнопок.</p>
<h3>Подготовка</h3>
<p>У наших кнопок будет три состояния &#8211; нажата, не нажата, активна (наведена мышь).<br />
Заранее подготовь три картинки, для трёх этих состояний, и помести в папку программы.<br />
Создадим константы с именами наших картинок:</p>
<pre name="code" class="delphi">
const
  IM_DOWN: string='down.bmp';
  IM_MAIN:  string='main.bmp';
  IM_HOVER: string='hover.bmp';
</pre>
<p>Ии, нам надо их менять, подготовимся:</p>
<pre name="code" class="delphi">
procedure SetState(btn:TImage;vstate:string);
var
  vfile:string;
begin
  vfile:=ExtractFilePath(ParamStr(0))+vstate;
  try
    btn.Picture.LoadFromFile(vfile);
  except
  end;
end;
</pre>
<p>Здесь мы передаём функции имя файла картинки (из созданных констант) и указание на TImage, с которым нужно такое сотворить.</p>
<p>Так-с, поставим теперь на форму Image1, создадим ему следующие обработчики событий:</p>
<pre name="code" class="delphi">
procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
begin
  SetState(Image1,IM_HOVER);
end;

procedure TForm1.Image1MouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  SetState(Image1,IM_MAIN);
end;

procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  SetState(Image1,IM_DOWN);
end;
</pre>
<p>Тут всё понятно (надеюсь): при нажатии, отжатии, наведении мышью. А как быть, когда мышь уходит?</p>
<pre name="code" class="delphi">
procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
begin
  SetState(Image1,IM_MAIN);
end;
</pre>
<p>Да, с одним TImage работает на ура. Только вот мерцает при движении мышью, это плохо, так ведь?</p>
<p>Тогда добавим еще четыре константы:</p>
<pre name="code" class="delphi">
const
  BS_UP=1001;         //последнее событие было mouseup
  BS_DOWN=1002;       //последнее событие было mousedown
  BS_HOVER=1003;      //последнее событие было mousemove
  BS_FORM=1004;  //мышь двигается по форме
</pre>
<p>Куда мы будем их присваивать? Неверно, к <strong>свойству tag</strong> у TImage, оно зарезервировано специально для таких пожарных случаев.</p>
<p>Сразу приведу модифицированный код:</p>
<pre name="code" class="delphi">
procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
begin
  if Image1.Tag<>BS_HOVER then
    SetState(Image1,IM_HOVER);
  Image1.Tag:=BS_HOVER;
end;

procedure TForm1.Image1MouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  if Image1.Tag<>BS_UP then
    SetState(Image1,IM_MAIN);
  Image1.Tag:=BS_UP;
end;

procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  if Image1.Tag<>BS_DOWN then
    SetState(Image1,IM_DOWN);
  Image1.Tag:=BS_DOWN;
end;

procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
begin
  if Image1.Tag<>BS_FORM then
    SetState(Image1,IM_MAIN);
  Image1.Tag:=BS_FORM;
end;
</pre>
<h3>Обобщение</h3>
<p>Вот и настал тот момент&#8230; когда нам надо переходить от одного Image1 к любому TImage, на котором произошло событие. Если ты читал мой блог, то уже знаешь, что надо заменить Image1 на (Sender as TImage) во всех обработчиках событий у Image1.</p>
<p>А что делать при движении мышью по форме? Точно, надо перебрать все компоненты TImage на форме, полезный, кстати, навык:</p>
<pre name="code" class="delphi">
procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
var
  i:integer;
begin
  for i:=0 to ComponentCount-1 do begin
    if Components[i] is TImage then begin
      if (Components[i] as TImage).Tag<>BS_FORM then
        SetState((Components[i] as TImage),IM_MAIN);
     (Components[i] as TImage).Tag:=BS_FORM;
    end;
  end;
end;
</pre>
<p>Вроде всё чисто и ясно, могу про это потом отдельный пост написать.</p>
<p>Ну и назначим события при старте формы:</p>
<pre name="code" class="delphi">
procedure TForm1.FormCreate(Sender: TObject);
var
  i:integer;
begin
  for i:=0 to ComponentCount-1 do begin
    if Components[i] is TImage then begin
      (Components[i] as TImage).OnMouseDown:=Image1MouseDown;
      (Components[i] as TImage).OnMouseUp:=Image1MouseUp;
      (Components[i] as TImage).OnMouseMove:=Image1MouseMove;
    end;
  end;
end;
</pre>
<h3>Итог</h3>
<p>Теперь, сколько бы мы TImage не создали в проекте, столько у нас и будет кнопок :)</p>
<hr/>
<img src="http://parsers.info/wp-content/uploads/2009/12/11.PNG" alt="Свой стиль кнопок на delphi" title="Свой стиль кнопок на delphi" width="386" height="162" class="aligncenter size-full wp-image-444" /><br />
А вы знали, что google &#8211; хиппи? Особенно рано утром :) </p>
<p>Иногда требуется <a href="http://2ip.ru/isp-change/">подключить интернет</a>, но возникают проблемы &#8211; много провайдеров, разные тарифы &#8211; как выбрать? Если ты в Москве, то воспользуйся ссылкой выше.</p>
<hr/>
(c) crystalbit, <a href="http://parsers.info">http://parsers.info</a></p>
<p>Ах, вот проектик &#8211; <strong><a href="http://parsers.info/pub/TImageButtons.rar">скачать</a></strong><br />
А вот rss лента &#8211; <strong><a href="http://feeds.feedburner.com/parsers/">подписаться</a></strong></p>

	<h4>Похожие записи</h4>
	<ul class="st-related-posts">
	<li><a href="http://parsers.info/2009/12/perechislenie-vsex-komponentov-na-forme/" title="Перечисление всех компонентов на форме (23 Декабрь 2009)">Перечисление всех компонентов на форме</a> (12)</li>
	<li><a href="http://parsers.info/2009/12/parametr-sender-v-obrabotchikax-sobytij-event-handlers-na-delphi/" title="Параметр Sender в обработчиках событий (event handlers) на delphi. (14 Декабрь 2009)">Параметр Sender в обработчиках событий (event handlers) на delphi.</a> (10)</li>
	<li><a href="http://parsers.info/2009/12/operatory-as-i-is-delphi/" title="Операторы as и is или &laquo;английский язык произошел от дельфи&raquo;. (16 Декабрь 2009)">Операторы as и is или &laquo;английский язык произошел от дельфи&raquo;.</a> (3)</li>
</ul>

]]></content:encoded>
			<wfw:commentRss>http://parsers.info/2009/12/sender-sozdayom-svoj-stil-knopok/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Операторы as и is или &#171;английский язык произошел от дельфи&#187;.</title>
		<link>http://parsers.info/2009/12/operatory-as-i-is-delphi/</link>
		<comments>http://parsers.info/2009/12/operatory-as-i-is-delphi/#comments</comments>
		<pubDate>Wed, 16 Dec 2009 14:34:41 +0000</pubDate>
		<dc:creator>crystalbit</dc:creator>
				<category><![CDATA[delphi]]></category>
		<category><![CDATA[Кодинг]]></category>
		<category><![CDATA[Статьи]]></category>
		<category><![CDATA[sender]]></category>

		<guid isPermaLink="false">http://parsers.info/?p=434</guid>
		<description><![CDATA[Про Sender: TObject я недавно рассказал. Согласись, что использовать Sender без таких операторов как is и as не очень кавайно. Конечно, для определенных целей они даже не требуются, а вот кое-где уже не обойтись. Ты-то про них знаешь всё, а вот остальным сейчас расскажу. 1. As Да, я в названии не опечатался. Когда я использую [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://parsers.info/wp-content/uploads/2009/12/is.jpg" alt="Использование операторов is и as вместе с параметром Sender." title="Использование операторов is и as вместе с параметром Sender." width="349" height="277" class="aligncenter size-full wp-image-435" /><br />
Про <a href="http://parsers.info/2009/12/parametr-sender-v-obrabotchikax-sobytij-event-handlers-na-delphi/">Sender: TObject</a> я недавно рассказал. Согласись, что использовать <strong>Sender</strong> без таких операторов как <strong>is и as</strong> не очень кавайно. Конечно, для определенных целей они даже не требуются, а вот кое-где уже не обойтись.<br />
Ты-то про них знаешь всё, а вот остальным сейчас расскажу.<br />
<span id="more-434"></span></p>
<h3>1. As</h3>
<p>Да, я в названии не опечатался. Когда я использую <strong>as и is</strong>, мне кажется, что я пишу сочинение на английском на свободную тему &#8211; даже получаются правильно построенные предложения :)<br />
<em>Оператор as</em> &#8211; я бы его перевёл как &laquo;использовать как&raquo;.<br />
Примерчик: при нажатии на кнопку, написать на ней &laquo;нажато&raquo;. Пускай мы не знаем, какая кнопка нажата, так как наше событие вызывают несколько кнопок.</p>
<pre name="code" class="delphi">
procedure TForm1.Button1Click(Sender: TObject);
begin
  (Sender as TButton).Caption:='нажато';
end;
</pre>
<p>Мы используем <em>Sender типа TObject как TButton</em>, потому что мы заранее знаем, что это кнопка. Почему бы просто не написать <em>Sender.Caption</em>? Вот если у вызвавшего события компонента не будет такого свойства, то не имеет смысла. Впрочем, ошибка появится уже на этапе компиляции.<br />
Можно и так:</p>
<pre name="code" class="delphi">
procedure TForm1.Button1Click(Sender: TObject);
var
  vb: TButton;
begin
  vb:=Sender as TButton;
  vb.Caption:='нажато';
end;
</pre>
<p>Подводя итог, после as пишем тип, за который мы хотим принимать объект.</p>
<h3>2. Is</h3>
<p>А как нам быть, если мы не знаем, какого типа объект вызвал наш метод? Допутим, мы поставили еще и <em>Label1 (TLabel)</em> и на <em>OnDblClick</em> присвоили наш Button1Click. <strong>Sender as TButton</strong> &#8211; так для TLabel не получится. В runtime появится ошибка &laquo;<em>invalid class typecas</em>t&raquo;.<br />
Ну что,</p>
<pre name="code" class="delphi">
procedure TForm1.Button1Click(Sender: TObject);
begin
  if (Sender is TButton) then
    (Sender as TButton).Caption:='нажато';
  if (Sender is TLabel) then
    (Sender as TLabel).Caption:='дважды нажато';
end;
</pre>
<p>Вот и всё, нет ошибки. Если говорить по матчасти, <em>(Sender is TButton)</em> возвращает true или false.</p>
<p>В ближайшем будущем хочется привести один замечательный пример, подпишись на <a href="http://feeds.feedburner.com/parsers/" rel="nofollow">rss ленту</a> и узнаешь первым ;)</p>
<p>А я сегодня сдал зачёт по экологии)</p>
<p>(c) crystalbit, <a href="http://parsers.info">http://parsers.info</a></p>
<p>&#8212;&#8212;-</p>
<p>Сердце Парижа, что это? Конечно же, <a href="http://www.turinfo.ru/attractions/notr-dam/">Собор Парижской Богоматери</a>, Notre Dame de Paris, Нотр Дам. Многие слышали о нём, многие наслышаны, многие рассматривали фотографии этого собора. Почему бы и не съездить?</p>

	<h4>Похожие записи</h4>
	<ul class="st-related-posts">
	<li><a href="http://parsers.info/2009/12/perechislenie-vsex-komponentov-na-forme/" title="Перечисление всех компонентов на форме (23 Декабрь 2009)">Перечисление всех компонентов на форме</a> (12)</li>
	<li><a href="http://parsers.info/2009/12/parametr-sender-v-obrabotchikax-sobytij-event-handlers-na-delphi/" title="Параметр Sender в обработчиках событий (event handlers) на delphi. (14 Декабрь 2009)">Параметр Sender в обработчиках событий (event handlers) на delphi.</a> (10)</li>
	<li><a href="http://parsers.info/2009/12/sender-sozdayom-svoj-stil-knopok/" title="Sender: немного практики, или создаём свой стиль кнопок. (19 Декабрь 2009)">Sender: немного практики, или создаём свой стиль кнопок.</a> (7)</li>
</ul>

]]></content:encoded>
			<wfw:commentRss>http://parsers.info/2009/12/operatory-as-i-is-delphi/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Несколько причин, почему люди не оставляют комментарии в блоге.</title>
		<link>http://parsers.info/2009/12/neskolko-prichin-pochemu-lyudi-ne-ostavlyayut-kommentarii-v-bloge/</link>
		<comments>http://parsers.info/2009/12/neskolko-prichin-pochemu-lyudi-ne-ostavlyayut-kommentarii-v-bloge/#comments</comments>
		<pubDate>Tue, 15 Dec 2009 16:31:21 +0000</pubDate>
		<dc:creator>crystalbit</dc:creator>
				<category><![CDATA[SEO, SMO]]></category>
		<category><![CDATA[Статьи]]></category>
		<category><![CDATA[SMO]]></category>

		<guid isPermaLink="false">http://parsers.info/?p=429</guid>
		<description><![CDATA[Привет, читатель! Поздравляю с начавшейся наконец зимой! Сегодня рассмотрим вопрос, который относится скорее к SEO &#8211; почему человек, зашедший на блог, не оставляет комментарий. Пускай ему даже есть что добавить. ME Liz Strauss на своём блоге (источник) в 2006 году опросила своих читателей и сформулировала 10 и одну причину: Твой пост достаточно полон, и сложно [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://parsers.info/wp-content/uploads/2009/12/kkkd.jpg" alt="Почему не комментируют блог? Скандалы, интриги, расследования" title="Почему не комментируют блог? Скандалы, интриги, расследования" width="312" height="275" class="aligncenter size-full wp-image-430" /><br />
Привет, читатель! Поздравляю с начавшейся наконец зимой!<br />
Сегодня рассмотрим вопрос, который относится скорее к SEO &#8211; почему человек, зашедший на блог, не оставляет комментарий. Пускай ему даже есть что добавить.<br />
<span id="more-429"></span><br />
ME Liz Strauss на своём блоге (<a href="http://www.successful-blog.com/1/10-reasons-readers-dont-leave-comments/" rel="nofollow">источник</a>) в 2006 году опросила своих читателей и сформулировала 10 и одну причину:</p>
<ol>
<li/>Твой <strong>пост достаточно полон</strong>, и сложно что-то написать, кроме как &laquo;хорошая работа&raquo;. Я считаю это глупым, читаю пост и иду дальше.
<li/>В посте <strong>я узнал что-то новое, мне нужно это обдумать</strong>, даже перед тем, как сформулировать вопрос. Аналогично предыдущему, не хочу ставить себя в глупое положение. Прохожу мимо.
<li/>Я готов написать комментарий, но замечаю, что ты <strong>ответил только некоторым близким знакомым</strong>. Я не хочу быть высмеянным на публике.
<li/>Люди, комментирующие твои посты, любят <strong>ругаться</strong>, а я &#8211; нет. Я не уверен в своей храбрости сражаться с толпой.
<li/>Ты <strong>редко отвечаешь на комментарии</strong>. Поэтому просто нет смысла писать еще один.
<li/>Ты относишься к комментаторам, как к <strong>глупым.</strong> Я не настолько глуп, чтобы писать в твоём блоге.
<li/>Мне реально понравился твой пост и весь блог, но <strong>я очень устал или занят своими делами</strong>. Я отпишу в следующий раз, как буду проходить мимо.
<li/>Твои посты заканчиваются общим вопросом, типа &laquo;Что ты думаешь про теорию большого взрыва?&raquo;. <strong>Вопрос слишком объемен</strong>, у меня просто нет времени на него ответить. Мне неудобно писать более короткий ответ.
<li/>Между мной и моим комментарием стена в виде <strong>авторизации</strong>. У меня и так много паролей, и мне не очень хочется добавить еще один в мой список.
<li/>Контент <strong>недостаточно свежий и интересный</strong>. Я читал об этом на дестке других блогов. Если комментировать, то расписывать всё заново.
<li/>Пост носит <strong>негативный характер</strong>. Это отпугивает.
</ol>
<p>Блоггер с ником Xager тоже поднимал эту тему в мае.<br />
Почему многие блоги кажутся неживыми? Он приводит следующие причины:</p>
<ol>
<li/><strong>Комментировать некому.</strong> Надо подниматься в топ :)
<li/><strong>Материал не интересен, автор не интересен, блог не интересный.</strong> Надо брать пример с успешных людей в таком случае.
<li/><strong>Непонятно.</strong> Совсем.
<li/><strong>Нечего добавить.</strong> Смотри первую причину в предыдущем обзоре.
<li/><strong>Ты не отвечаешь на комментарии</strong>, зачем тогда комментировать?
<li/><strong>У вас ГС.</strong> Не знаю, что это такое) Xager, о приди и оставь комментарий!
<li/><strong>Ты грубый.</strong> Плохой.
<li/><strong>Нет смысла из SEO соображений.</strong> Если стоит nofollow, а может еще и noindex, то это грустно.
</ol>
<p><a href="http://xager.ru/pochemu-nekotorye-blogi-ne-kommentiruyut" rel="nofollow">Пост от Xager</a> &#8211; там найдешь некоторые советы.</p>
<p>(c) crystalbit, <a href="http://parsers.info">http://parsers.info</a><br />
Комментируй! Гуляем!</p>

	<h4>Похожие записи</h4>
	<ul class="st-related-posts">
	<li><a href="http://parsers.info/2009/04/google-instrumenty-dlya-veb-masterov/" title="Google инструменты для веб-мастеров. (11 Апрель 2009)">Google инструменты для веб-мастеров.</a> (18)</li>
</ul>

]]></content:encoded>
			<wfw:commentRss>http://parsers.info/2009/12/neskolko-prichin-pochemu-lyudi-ne-ostavlyayut-kommentarii-v-bloge/feed/</wfw:commentRss>
		<slash:comments>67</slash:comments>
		</item>
		<item>
		<title>Параметр Sender в обработчиках событий (event handlers) на delphi.</title>
		<link>http://parsers.info/2009/12/parametr-sender-v-obrabotchikax-sobytij-event-handlers-na-delphi/</link>
		<comments>http://parsers.info/2009/12/parametr-sender-v-obrabotchikax-sobytij-event-handlers-na-delphi/#comments</comments>
		<pubDate>Mon, 14 Dec 2009 14:45:03 +0000</pubDate>
		<dc:creator>crystalbit</dc:creator>
				<category><![CDATA[delphi]]></category>
		<category><![CDATA[Кодинг]]></category>
		<category><![CDATA[Переведённое]]></category>
		<category><![CDATA[Статьи]]></category>
		<category><![CDATA[sender]]></category>

		<guid isPermaLink="false">http://parsers.info/?p=424</guid>
		<description><![CDATA[Всем привет. Димон, особенно тебе, рад что ты ссылку запомнил! Итак, сегодня я хочу рассказать про так часто мелькающее перед нашими глазами Sender: TObject. Точнее, своими словами я рассказывать не буду, а переведу с английского доступным языком, копирайт смотри в конце поста, как обычно. Давным-давно, в царстве delphi Жил-был объект по имени Sender [Обработчики событий [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://parsers.info/wp-content/uploads/2009/12/3947976663_3f139c016e.jpg" alt="Sender: TObject на delphi - всё о нём" title="Sender: TObject на delphi - всё о нём" width="500" height="333" class="aligncenter size-full wp-image-422" /><br />
Всем привет. Димон, особенно тебе, рад что ты ссылку запомнил!<br />
Итак, сегодня я хочу рассказать про так часто мелькающее перед нашими глазами <strong>Sender: TObject</strong>.</p>
<p>Точнее, своими словами я рассказывать не буду, а переведу с английского доступным языком, копирайт смотри в конце поста, как обычно.<br />
<span id="more-424"></span><br />
<em>Давным-давно, в царстве delphi<br />
Жил-был объект по имени Sender</em></p>
<h2>[Обработчики событий и Sender]</h2>
<p>Посмотрим на обработчик события OnClick кнопки Button1:</p>
<pre name="code" class="delphi">
procedure TForm1.Button1Click(Sender: TObject) ;
begin
  ...
end;
</pre>
<p>Метод Button1Click указывает на объект <strong>Sender</strong> типа <strong>TObject</strong>. Каждый обработчик в delphi обязательно имеет параметр <strong>Sender</strong>. Функция <strong>Button1Click</strong> вызывается для события <strong>OnClick</strong> каждый раз, когда нажимается кнопка.</p>
<p>Параметр <strong>Sender</strong> ссылается на компонент, который вызвал метод. Если ты нажмёшь на <strong>Button1</strong>, выполнится метод Button1Click. А ссылка или указатель на объект Button1 передастся в параметре <strong>Sender</strong>.</p>
<h2>[На практике]</h2>
<p>Правильное использование <strong>параметра Sender</strong> может придать неимоверную гибкость нашему коду (так же, как и <a href="http://www.str-2000.ru/catalog/18/">фильтр косой</a> иногда позволяет уменьшить размер конструкции из труб). Параметр <strong>Sender</strong> даёт нам знать, какой компонент возбудил наше событие. (возбудил событие &#8211; запомню) Это облегчает использование одного обработчика для двух разных компонентов.</p>
<p>Например, мы хотим, чтобы кнопка и пункт меню выполняли одну и ту же функцию. Люди усомнятся в твоей ориентации, если ты напишешь одно событие дважды.</p>
<p>Для того, чтобы сделать вышеизложенное в Delphi, нужно следующее:</p>
<ul>
<li/>Напиши обработчик события для первого объекта (почему бы не на кнопку в SpeedBar&#8217;е?)
<li/>Выдели еще объекты, а может и несколько объектов (почему бы не MenuItem1, а?)
<li/>В Object Inspector найди Events
<li/>Рядом с нужным событием выбери в списке уже созданный обработчик (Delphi предложит все совместимые функции на форме)
</ul>
<p>Вот мы с тобой и создали единственный метод, который обрабатывает <strong>события OnClick</strong> на кнопке и пункте меню. Теперь нам только и остаётся, что различать, какой компонент вызвал наш метод. К примеру, у тебя мог получиться такой код:</p>
<pre name="code" class="delphi">
procedure TForm1.Button1Click(Sender: TObject) ;
begin
  {общий код для пункта меню и кнопки}
  ...
  {а вот и разделение труда:}
  if Sender = Button1 then
   ShowMessage('Button1 клац!')
  else if Sender = MenuItem1 then
   ShowMessage('MenuItem1 клац!')
  else
   ShowMessage('??? клац!') ;
end;
</pre>
<p>В общих чертах, мы сравниваем <strong>Sender</strong> с компонентом.</p>
<p><u>Замечание</u>:<br />
Второй else в конструкции if-then-else для тех случаев, когда событие вызвано не Button1 и не MenuItem1. Но кто же еще мог вызвать наш метод? Попробуй так, поставь только еще и Button2:</p>
<pre name="code" class="delphi">
procedure TForm1.Button2Click(Sender: TObject) ;
begin
   Button1Click(Button2) ;
   {будет сообщение '??? клац!'}
end;
</pre>
<p>(c) Delphi Programming &#8211; <a href="http://delphi.about.com" rel="nofollow">http://delphi.about.com</a><br />
(c) crystalbit &#8211; <a href="http://parsers.info">http://parsers.info</a></p>
<p>В следующей части данной статьи рассказывается про такие операторы, как as и is, скоро появится у меня на блоге.<br />
Подпишись на <a href="http://feeds.feedburner.com/parsers/" rel="nofollow">rss ленту</a>, чтобы не упустить момент;)</p>

	<h4>Похожие записи</h4>
	<ul class="st-related-posts">
	<li><a href="http://parsers.info/2009/12/perechislenie-vsex-komponentov-na-forme/" title="Перечисление всех компонентов на форме (23 Декабрь 2009)">Перечисление всех компонентов на форме</a> (12)</li>
	<li><a href="http://parsers.info/2009/12/operatory-as-i-is-delphi/" title="Операторы as и is или &laquo;английский язык произошел от дельфи&raquo;. (16 Декабрь 2009)">Операторы as и is или &laquo;английский язык произошел от дельфи&raquo;.</a> (3)</li>
	<li><a href="http://parsers.info/2009/12/sender-sozdayom-svoj-stil-knopok/" title="Sender: немного практики, или создаём свой стиль кнопок. (19 Декабрь 2009)">Sender: немного практики, или создаём свой стиль кнопок.</a> (7)</li>
</ul>

]]></content:encoded>
			<wfw:commentRss>http://parsers.info/2009/12/parametr-sender-v-obrabotchikax-sobytij-event-handlers-na-delphi/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
	</channel>
</rss>

