<?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>ZetBlog&#187; Delphi</title>
	<atom:link href="http://zetblog.ru/tag/delphi/feed/" rel="self" type="application/rss+xml" />
	<link>http://zetblog.ru</link>
	<description>Зеты говорят. Блог о программировании, администрировании и безопасности.</description>
	<lastBuildDate>Sat, 29 Oct 2011 18:59:40 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Delphi: Пишем шаблон клиент-серверного приложения.</title>
		<link>http://zetblog.ru/programming/201004/delphi-%d0%bf%d0%b8%d1%88%d0%b5%d0%bc-%d1%88%d0%b0%d0%b1%d0%bb%d0%be%d0%bd-%d0%ba%d0%bb%d0%b8%d0%b5%d0%bd%d1%82-%d1%81%d0%b5%d1%80%d0%b2%d0%b5%d1%80-%d0%bf%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd/</link>
		<comments>http://zetblog.ru/programming/201004/delphi-%d0%bf%d0%b8%d1%88%d0%b5%d0%bc-%d1%88%d0%b0%d0%b1%d0%bb%d0%be%d0%bd-%d0%ba%d0%bb%d0%b8%d0%b5%d0%bd%d1%82-%d1%81%d0%b5%d1%80%d0%b2%d0%b5%d1%80-%d0%bf%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd/#comments</comments>
		<pubDate>Fri, 02 Apr 2010 07:47:37 +0000</pubDate>
		<dc:creator>C0ffe1n</dc:creator>
				<category><![CDATA[прикладное]]></category>
		<category><![CDATA[Программирование]]></category>
		<category><![CDATA[сетевое]]></category>
		<category><![CDATA[ClientSocket]]></category>
		<category><![CDATA[Delphi]]></category>
		<category><![CDATA[ServerSocket]]></category>
		<category><![CDATA[сеть]]></category>
		<category><![CDATA[файлы]]></category>

		<guid isPermaLink="false">http://zetblog.ru/?p=913</guid>
		<description><![CDATA[Продолжая тему разработки собственной утилиты администрирования, в данной статье я рассмотрю типовой шаблон программы клиент-сервер, на базе которой можно разрабатывать собственные клиент-серверные приложения. Данный типовой шаблон для простоты понимания и удобства применения будет рассмотрен на примере компонентов ClientSocket и ServerSocket. Примечание Для тех, кто не в курсе, что значит клиент-серверное приложение, поясню: это комплекс программ [...]]]></description>
			<content:encoded><![CDATA[<p>Продолжая тему разработки собственной утилиты администрирования, в данной статье я рассмотрю типовой шаблон программы клиент-сервер, на базе которой можно разрабатывать собственные клиент-серверные приложения. Данный типовой шаблон для простоты понимания и удобства применения будет рассмотрен на примере компонентов <strong>ClientSocket</strong> и <strong>ServerSocket</strong>.<br />
<span id="more-913"></span><strong></strong></p>
<p><strong>Примечание</strong></p>
<div class="codesnip-container" >Для тех, кто не в курсе, что значит клиент-серверное приложение, поясню: это комплекс программ (модулей) состоящий из двух частей &#8212; клиентской и серверной. Серверная часть является &#171;главной&#187;- так называемый командный пункт, на который возложена задача поддержания связи со всеми клиентами и раздача команд управления, соответствующих их функционалу (управление клиентами). Клиентская же часть является второстепенной, но не менее важной, так как является важным и связующим элементом, позволяющим выполнять удаленные команды (функции) на компьютере, на котором установлен.</div>
<div class="codesnip-container" >Компоненты <strong>ClientSocket</strong> и <strong>ServerSocket</strong>, которые мы будем использовать, находятся на вкладке <strong>Internet</strong>. Если на этой вкладке у Вас нет этих компонентов (а по умолчанию при установке <strong>Delphi7</strong> они не ставятся), необходимо установить их самостоятельно (пакет <strong>dclsocketsXX.bpl</strong>). Данный пакет можно найти на установочном диске<strong> Delphi7</strong> (или в папке<span style="text-decoration: underline;"> C:\Temp</span>, куда распаковывается дистрибутив перед установкой &#8212; <span style="text-decoration: underline;">C:\Temp\delphi7\install\program files\borland\delphi7\bin\</span>) или можете его скачать <a href="/forum/downloadf/components/dclsockets70.rar">отсюда</a>. Чтобы установить данный пакет, запустите <strong>Delphi7</strong>. Зайдите в меню <span style="text-decoration: underline;">Component-&gt;Install Packages</span>. В появившемся окне нажмите кнопку <strong>&#171;Add&#187;</strong> и укажите место, где расположен пакет <strong>dclsocketsXX.bpl</strong>. После этого жмите<strong> ОК</strong>. Компонент на месте. ;)</div>
<p>Надеюсь все объяснил доступно =). А теперь приступим к делу и начнем мы с серверной части. Для этого создадим проект и скинем на форму компонент <strong>ServerSocket</strong>. В настройках компонента <strong>ServerSocket</strong> укажем следующее:</p>
<div class="codesnip-container" >Active = false<br />
Name = ss<br />
Port = 4321<br />
ServerType = stNonBlocking</div>
<p>А также для удобства скинем компонент <strong>Memo</strong>, в который будем выводить всякую инфу. Дадим имя компоненту <strong>log</strong>.</p>
<p>Далее, для компонента <strong>ServerSocket</strong> определяем метод <strong>onClientConnect</strong>, чтобы определять момент подключения клиентов. Вставим следующий код:</p>
<pre class=".brush: pascal">procedure TForm1.ssClientConnect(Sender: TObject;
  Socket: TCustomWinSocket);
var
  myDate : TDateTime;
  formattedDateTime : string;
begin
  mydate:=Now;
  DateTimeToString(formattedDateTime, 'c', myDate);
  log.Lines.Add(formattedDateTime+': Есть коннект c '+Socket.RemoteAddress);
  { далее вы можете вставить свой код }
end;</pre>
<p>А теперь определим метод <strong>onClientRead</strong>, в котором будем обрабатывать получаемые сообщения от клиентов:</p>
<pre class=".brush: pascal">procedure TForm1.ssClientRead(Sender: TObject; Socket: TCustomWinSocket);
var
  s:string;
begin
  s:=Socket.ReceiveText;
  log.Lines.Add(s);
end;</pre>
<p>Определим метод<strong> onClientDisconnect</strong>, чтобы фиксировать факт отключения клиента:</p>
<pre class=".brush: pascal">procedure TForm1.ssClientDisconnect(Sender: TObject;
  Socket: TCustomWinSocket);
var
  myDate : TDateTime;
  formattedDateTime : string;
begin
  mydate:=Now;
  DateTimeToString(formattedDateTime, 'c', myDate);
  log.Lines.Add(formattedDateTime+': Клиент '+socket.RemoteAddress+' отключился.');
end;</pre>
<p>На этом с серверной частью покончено =).</p>
<p>Приступим к клиентской части. Для этого создадим новый проект, скинем на форму компонент <strong>ClientSocket</strong> и таймер. В настройках компонента укажем следующее:</p>
<div class="codesnip-container" >Active = false<br />
Name = сs<br />
Port = 4321<br />
ClientType = ctNonBlocking<br />
Address = 127.0.0.1</div>
<p>Для простоты пояснения я в <strong>Address</strong> указал <strong>&#171;петлю&#187;</strong>. Но для гибкости приложения рекомендую это поле обрабатывать программно, во время <strong>CreateForm</strong> при обработке конфигурационного файла, в котором можно указывать нужный <strong>IP-адрес сервера</strong>.</p>
<p>Здесь также для удобства скинем на форму компонент <strong>Memo</strong>, в который будем выводить техническую инфу. Имя дадим соответствующее<strong> log</strong>.</p>
<p>Для компонента <strong>ClientSocket</strong> определяем метод <strong>onError</strong> для того, чтобы обрабатывать исключения, возникшие в момент подключения клиента к серверу. Вставим следующий код:</p>
<pre class=".brush: pascal">procedure TForm1.csError(Sender: TObject; Socket: TCustomWinSocket;
  ErrorEvent: TErrorEvent; var ErrorCode: Integer);
var
  myDate : TDateTime;
  formattedDateTime : string;
begin
 if ErrorEvent= eeConnect  then
  begin
    cs.Active:=false;
      {добавить запись в журнал};
    mydate:=Now;
    DateTimeToString(formattedDateTime, 'c', myDate);
    log.lines.Add(formattedDateTime+': Невозможно установить соединение с сервером - '+cs.Address);
  end;
  ErrorCode:=0;
  { далее вы можете вставить свой код }
end;</pre>
<p>Теперь определим метод <strong>onConnect</strong>. Вставим следующий код:</p>
<pre class=".brush: pascal">procedure TForm1.csConnect(Sender: TObject; Socket: TCustomWinSocket);
var
  myDate : TDateTime;
  formattedDateTime : string;
begin
  mydate:=Now;
  DateTimeToString(formattedDateTime, 'c', myDate);
  log.lines.Add(formattedDateTime+': Соединение с сервером - '+socket.RemoteAddress+' установлено.');
end;</pre>
<p>И чтобы фиксировать момент потери связи с сервером, определим метод <strong>onDisconnect</strong>:</p>
<pre class=".brush: pascal">procedure TForm1.csDisconnect(Sender: TObject; Socket: TCustomWinSocket);
var
  myDate : TDateTime;
  formattedDateTime : string;
begin
  mydate:=Now; //получим текущее время
  DateTimeToString(formattedDateTime, 'c', myDate); //преобразуем в строку
  log.Lines.Add(formattedDateTime+': Соединение с сервером '+socket.RemoteAddress+' потеряно.');
end;</pre>
<p>Таймер настроим так:</p>
<div class="codesnip-container" >Enabled = true<br />
Name = te<br />
Interval = 5000</div>
<p>И определяем метод <strong>onTimer</strong>. Вставим следующий код:</p>
<pre class=".brush: pascal">procedure TForm1.Timer1Timer(Sender: TObject);
begin
if not cs.Active then
  begin
    cs.Active:=true;
  end;
  cs.Socket.SendText('ping client');
end;</pre>
<p>Данный код проверяет наличие соединения с сервером и в случае его отсутствия пытается его установить.<br />
И каждые 5 секунд отправляет серверу сообщение <strong>&#171;ping client&#187;</strong>.</p>
<p>Вот примерно так выглядит типовой шаблон приложения <strong>&#171;клиент-сервер&#187;</strong>.</p>
<p><strong>Примечание</strong></p>
<div class="codesnip-container" >Хотел бы обратить внимание на обработчик <strong>onError</strong> тех, кто ранее не знал как избавиться от злосчастного сообщения &#8212; <strong>&#171;Asynchronous socket error 10061&#8243;</strong>, возникающее при попытке осуществления подключения к серверу, который недоступен.</div>
<p>Рабочий пример можно скачать <a title="Рабочий пример" href="/forum/downloadf/simples/client-server.rar">отсюда</a>.</p>
<p>Если есть кому что добавить или задать вопрос по теме &#8212; прошу отписываться в комментах ;)</p>
]]></content:encoded>
			<wfw:commentRss>http://zetblog.ru/programming/201004/delphi-%d0%bf%d0%b8%d1%88%d0%b5%d0%bc-%d1%88%d0%b0%d0%b1%d0%bb%d0%be%d0%bd-%d0%ba%d0%bb%d0%b8%d0%b5%d0%bd%d1%82-%d1%81%d0%b5%d1%80%d0%b2%d0%b5%d1%80-%d0%bf%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>Delphi: Пишем собственную утилиту для администрирования. Часть 1.</title>
		<link>http://zetblog.ru/programming/200905/%d0%bf%d0%b8%d1%88%d0%b5%d0%bc-%d1%81%d0%be%d0%b1%d1%81%d1%82%d0%b2%d0%b5%d0%bd%d0%bd%d1%83%d1%8e-%d1%83%d1%82%d0%b8%d0%bb%d0%b8%d1%82%d1%83-%d0%b4%d0%bb%d1%8f-%d0%b0%d0%b4%d0%bc%d0%b8%d0%bd%d0%b8/</link>
		<comments>http://zetblog.ru/programming/200905/%d0%bf%d0%b8%d1%88%d0%b5%d0%bc-%d1%81%d0%be%d0%b1%d1%81%d1%82%d0%b2%d0%b5%d0%bd%d0%bd%d1%83%d1%8e-%d1%83%d1%82%d0%b8%d0%bb%d0%b8%d1%82%d1%83-%d0%b4%d0%bb%d1%8f-%d0%b0%d0%b4%d0%bc%d0%b8%d0%bd%d0%b8/#comments</comments>
		<pubDate>Mon, 11 May 2009 12:02:16 +0000</pubDate>
		<dc:creator>C0ffe1n</dc:creator>
				<category><![CDATA[Программирование]]></category>
		<category><![CDATA[системное]]></category>
		<category><![CDATA[Delphi]]></category>
		<category><![CDATA[WinAPI]]></category>

		<guid isPermaLink="false">http://zetblog.ru/?p=683</guid>
		<description><![CDATA[Как я не однократно упоминал, любой программист должен знать, или хотя бы представлять себе как работает та или иная программа и уж тем более системная утилита. Это в первую очередь помогает понимать сам процесс взаимодействия операционной системы и программы. И следовательно создавать для себя, в качестве удобства администрирования свои собственные утилиты. Ну не пользоваться же [...]]]></description>
			<content:encoded><![CDATA[<p>Как я не однократно упоминал, любой программист должен знать, или хотя бы представлять себе как работает та или иная программа и уж тем более системная утилита. Это в первую очередь помогает понимать сам процесс взаимодействия операционной системы и программы. И следовательно создавать для себя, в качестве удобства администрирования свои собственные утилиты. Ну не пользоваться же в конце концов встроенными? Оо<br />
<span id="more-683"></span><br />
В этой статье и в последующих я рассмотрю разработку собственной утилиты для администрирования  под управлением операционных систем  Windows 2000/XP, которая позволит создавать пользователей, удалять их,  редактировать профиль, изменять пароль и много другое.<br />
А теперь приступим. Начнем с того, как научить нашу прогу получать список зарегистрированных пользователей. Для этого рассмотрим такую системную API-функцию как <strong>NetUserEnum</strong>. В <a href="http://msdn.microsoft.com/en-us/library/aa370652.aspx">MSDN</a>’е она описана таким образом:</p>
<div class="codesnip-container" >NET_API_STATUS NetUserEnum(<br />
__in     LPCWSTR servername,<br />
__in     DWORD level,<br />
__in     DWORD filter,<br />
__out    LPBYTE *bufptr,<br />
__in     DWORD prefmaxlen,<br />
__out    LPDWORD entriesread,<br />
__out    LPDWORD totalentries,<br />
__inout  LPDWORD resume_handle<br />
);</div>
<p>Где первый параметр указывает на компьютер в сети. Если в качестве этого параметра указать nil, то система определит локальное имя компьютера.<br />
Параметр level указывает системе о том, какого уровня требуется информация об аккаунте, более подробно их мы рассмотрим позже, но кому не терпится, могут почитать на MSDN’e. Но в примере мы рассмотрим уровень – 10. Он нам вернет имя аккаунта, информацию об аккаунте.<br />
Далее используется параметр, в котором нужно указать по какому признаку фильтровать системную информацию. Как гласит справка MSDN их  всего 6:</p>
<div class="codesnip-container" >FILTER_TEMP_DUPLICATE_ACCOUNT<br />
FILTER_NORMAL_ACCOUNT<br />
FILTER_PROXY_ACCOUNT<br />
FILTER_INTERDOMAIN_TRUST_ACCOUNT<br />
FILTER_WORKSTATION_TRUST_ACCOUNT<br />
FILTER_SERVER_TRUST_ACCOUNT</div>
<p>Подробней о них в следующей статье, а в примере мы будем использовать FILTER_NORMAL_ACCOUNT.<br />
В следующий параметр будет возвращен результат работы функции.<br />
В следующем параметре указываем размер буфера.<br />
В entriesread будет возвращено количество актуальных прочтенных записей, а в параметре totalentries – общее количество записей(зарегистрированных пользователей).<br />
В последнем параметре будет возвращен указатель для возможности продолжения работы.<br />
В лсдучае успешной отработки данной функции будет возвращено нулевое значение. В случае же ошибки будет возвращен один из следующих кодов ошибок:</p>
<div class="codesnip-container" >ERROR_ACCESS_DENIED<br />
NERR_InvalidComputer<br />
ERROR_MORE_DATA</div>
<p>В связи с выбранным уровнем 10, будем исследовать следующую структуру, которая описана в справке MSDN:</p>
<div class="codesnip-container" >typedef struct _USER_INFO_10 {<br />
LPWSTR usri10_name;<br />
LPWSTR usri10_comment;<br />
LPWSTR usri10_usr_comment;<br />
LPWSTR usri10_full_name;<br />
} USER_INFO_10, *PUSER_INFO_10, *LPUSER_INFO_10;</div>
<p>Так как наш язык программирования Delphi, все вышеописанное следует переделать под него, ну и недолго тянув кота за яйки, рассмотрим исходник получения списка пользователей в ОС Windows:</p>
<pre><strong>Delphi</strong>
<div class="codesnip-container" >unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs,Stdctrls, Comctrls;

{$EXTERNALSYM NetUserEnum}
function NetUserEnum(servername: LPWSTR;
  level,
  filter: DWORD;
  bufptr: Pointer;
  prefmaxlen: DWORD;
  entriesread,
  totalentries,
  resume_handle: LPDWORD): DWORD; stdcall;
external 'NetApi32.dll' Name 'NetUserEnum';
function NetApiBufferFree(Buffer: Pointer): DWORD; stdcall;
external 'NetApi32.dll' Name 'NetApiBufferFree';

type
  TForm1 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    procedure FormCreate(Sender: TObject);
     private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
const
  NERR_SUCCESS = 0;
  FILTER_TEMP_DUPLICATE_ACCOUNT = $0001;
  FILTER_NORMAL_ACCOUNT = $0002;

  FILTER_PROXY_ACCOUNT = $0004;
  FILTER_INTERDOMAIN_TRUST_ACCOUNT = $0008;
  FILTER_WORKSTATION_TRUST_ACCOUNT = $0010;
  FILTER_SERVER_TRUST_ACCOUNT = $0020;
type
  TUSER_INFO_10 = record
    usri10_name,
      usri10_comment,
      usri10_usr_comment,
      usri10_full_name: PWideChar;
  end;
  PUSER_INFO_10 = ^TUSER_INFO_10;
var
  dwERead, dwETotal, dwRes, res: DWORD;
  inf: PUSER_INFO_10;
  info: Pointer;
  p: PChar;
  i: Integer;
begin
  info := nil;
  dwRes := 0;
  res := NetUserEnum(nil,
    10,
    FILTER_NORMAL_ACCOUNT,
    @info,
    65536,
    @dwERead,
    @dwETotal,
    @dwRes);
  if (res &lt;&gt; NERR_SUCCESS) or (info = nil) then
    Exit;
  p := PChar(info);
  for i := 0 to dwERead - 1 do
  begin
    inf := PUSER_INFO_10(p + i * SizeOf(TUSER_INFO_10));
    memo1.Lines.Add(WideCharToString(PWideChar((inf^).usri10_name)));
    memo1.Lines.Add(WideCharToString(PWideChar((inf^).usri10_comment)));
    memo1.Lines.Add(WideCharToString(PWideChar((inf^).usri10_usr_comment)));
    memo1.Lines.Add(WideCharToString(PWideChar((inf^).usri10_full_name)));
  end;
  NetApiBufferFree(info);
end;</div>
</pre>
<p>Когда вы взгляните на результат работы функции, у вас появиться вопрос, а зачем нам нужны технические пользователи созданные системой автоматически для своих нужд? Абсолютно с вами соглашусь, возвращенный результат содержит много побочной и ненужной инфы, однако, стоит знать все, что известно о пользователе, зарегистрированном в системе, все может пригодиться ;). А в следующей статье мы рассмотрим более подробно используемые структуры, другие системные функции для работы с пользователями и, естественно, возможность отсеивания ненужной инфы.Ну а пока, предлагаю вам возможность поковырять исходник =).</p>
]]></content:encoded>
			<wfw:commentRss>http://zetblog.ru/programming/200905/%d0%bf%d0%b8%d1%88%d0%b5%d0%bc-%d1%81%d0%be%d0%b1%d1%81%d1%82%d0%b2%d0%b5%d0%bd%d0%bd%d1%83%d1%8e-%d1%83%d1%82%d0%b8%d0%bb%d0%b8%d1%82%d1%83-%d0%b4%d0%bb%d1%8f-%d0%b0%d0%b4%d0%bc%d0%b8%d0%bd%d0%b8/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>WinAPI: Работа с файлами (основные функции).</title>
		<link>http://zetblog.ru/programming/200902/winapi-%d1%80%d0%b0%d0%b1%d0%be%d1%82%d0%b0-%d1%81-%d1%84%d0%b0%d0%b9%d0%bb%d0%b0%d0%bc%d0%b8-%d0%be%d1%81%d0%bd%d0%be%d0%b2%d0%bd%d1%8b%d0%b5-%d1%84%d1%83%d0%bd%d0%ba%d1%86%d0%b8%d0%b8/</link>
		<comments>http://zetblog.ru/programming/200902/winapi-%d1%80%d0%b0%d0%b1%d0%be%d1%82%d0%b0-%d1%81-%d1%84%d0%b0%d0%b9%d0%bb%d0%b0%d0%bc%d0%b8-%d0%be%d1%81%d0%bd%d0%be%d0%b2%d0%bd%d1%8b%d0%b5-%d1%84%d1%83%d0%bd%d0%ba%d1%86%d0%b8%d0%b8/#comments</comments>
		<pubDate>Mon, 09 Feb 2009 23:27:55 +0000</pubDate>
		<dc:creator>C0ffe1n</dc:creator>
				<category><![CDATA[прикладное]]></category>
		<category><![CDATA[Программирование]]></category>
		<category><![CDATA[системное]]></category>
		<category><![CDATA[C/C++]]></category>
		<category><![CDATA[Delphi]]></category>
		<category><![CDATA[WinAPI]]></category>
		<category><![CDATA[файлы]]></category>

		<guid isPermaLink="false">http://zetblog.ru/?p=227</guid>
		<description><![CDATA[Категорически всех приветствую! На этот раз в наше поле зрения попала группа API-функций для работы с файлами. Ибо, как мне кажется, помимо меня многие программисты сталкиваются с необходимостью их использования в своих программах. Но откровенно скажу в голове все эти функции вместе с их возможными параметрами и не упомнишь, а иметь возможность &#171;вспомнить все&#187; ;) [...]]]></description>
			<content:encoded><![CDATA[<p>Категорически всех приветствую! На этот раз в наше поле зрения попала группа API-функций для работы с файлами. Ибо, как мне кажется, помимо меня многие программисты сталкиваются с необходимостью их использования в своих программах. Но откровенно скажу в голове все эти функции вместе с их возможными параметрами и не упомнишь, а иметь возможность &#171;вспомнить все&#187; ;)  прочитав эту статью &#8212; очень неплохая затея. За сим и приступаю к рассмотрению оного =).<br />
<span id="more-227"></span><br />
В этой статье мы рассмотрим следующие API-функции:</p>
<ol>
<li>CreateFile</li>
<li>OpenFile</li>
<li>ReadFile</li>
<li>WriteFile</li>
<li>CloseFile</li>
<li>DeleteFile</li>
<li>CopyFile</li>
<li>FindFirstFile</li>
<li>FindNextFile</li>
<li>GetFileSize</li>
</ol>
<p><strong>Замечание</strong></p>
<p>Но прежде чем  приступить к делу, замечу для случая, когда действия над файлами происходят удаленно.  За счет реализации в ОС Windows механизма прозрачного доступа к файлам,  данные функции работают и с удаленными файлами, отличием является задание сетевого пути к файлу, а именно для С/С++ необходимо указывать путь в следующем формате:   &#171;\\\\имя_удаленного_компа\\путь_к_ файлу\\ имя_файла&#187;.<br />
<strong>Пример:</strong></p>
<pre class=".brush: cpp">
DeleteFile("\\\\comp1\\user1\\test\\test1.txt");
</pre>
<p>Для Delphi необходимо указывать путь в следующем формате:   &#171;\\имя_удаленного_компа\путь_к_ файлу\имя_файла&#187;.</p>
<p><strong>Пример:</strong></p>
<pre class=".brush: pascal">
DeleteFile('\\comp1\user1\test\test1.txt');
</pre>
<p><strong>Функция CreateFile</strong></p>
<p>Функция создаёт указатель на новое устройство типа:</p>
<ul>
<li>Файл</li>
<li>Канал</li>
<li>mailslot (почтовый канал)</li>
<li>комуникационный ресурс (например COM порт)</li>
<li>дисковые устройства (только для Windows NT)</li>
<li>консоли</li>
<li>директории (открывает их)</li>
</ul>
<p>Все эти функции описаны в одном файле. Для С/С++ в хедере (заголовочный файл) winbase.h, для Delphi в модуле windows.pas.  Чтобы использовать в своей программе эти функции, достаточно подключить их к своему проекту и вперед. Замечу для тех, кто кодит на С/С++ &#8212; кроме winbase.h надо подключить еще windows.h.</p>
<p><strong>Описание</strong>:<br />
<strong>С/С++</strong></p>
<pre class=".brush: cpp">HANDLE CreateFile(
   LPCTSTR lpFileName,        // Указатель на имя файла (устройства)
   DWORD dwDesiredAccess,  //Параметры доступа
   DWORD dwShareMode,        //Разделяемый доступ
   LPSECURITY_ATTRIBUTES lpSecurityAttributes,    //безопасность
   DWORD dwCreationDistribution,// Описание
   DWORD dwFlagsAndAttributes,     // Атрибуты файла
   HANDLE hTemplateFile      // Файл шаблона
);</pre>
<p><strong>Delphi</strong></p>
<pre class=".brush: pascal">
function CreateFile(
   lpFileName: PChar;   // Указатель на имя файла (устройства)
   dwDesiredAccess,     //Параметры доступа
   dwShareMode: DWORD;  //Разделяемый доступ
   lpSecurityAttributes: PSecurityAttributes; //безопасность
   dwCreationDisposition,       // Описание
   dwFlagsAndAttributes: DWORD; // Атрибуты файла
   hTemplateFile: THandle       // Файл шаблона
): THandle; stdcall;
</pre>
<p>Теперь к главному &#8212; как создать файл? Делается это так:<br />
<strong>C/C++</strong></p>
<pre class=".brush: cpp">
{
   Handle FileHandle;
   FileHandle=CreateFile("file1.txt",GENERIC_READ |
      GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, CREATE_NEW,
      FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, 0);
   CloseHandle(FileHandle);
}
</pre>
<p><strong>Delphi</strong></p>
<pre class=".brush: pascal">
var
  FileHandle:THandle;
begin
   FileHandle:=CreateFile(PChar('file1.txt'),GENERIC_READ or
      GENERIC_WRITE, FILE_SHARE_WRITE or FILE_SHARE_READ, nil, CREATE_NEW,
      FILE_ATTRIBUTE_NORMAL or FILE_FLAG_OVERLAPPED, 0);
   CloseHandle(FileHandle);
end;
</pre>
<p>Теперь расмотрим используемые параметры:</p>
<ul>
<li>параметры <strong>GENERIC_READ</strong> и      <strong>GENERIC_WRITE</strong> определяют доступ на чтение и запись. Однако, можно указать что то одно в зависимости от ваших потребностей. Если в качестве этого параметра указать 0, то в этом случае функция отработает успешно, однако никакого доступа к файлу не получит. Этот вариант удобно использовать для теста существования файла.</li>
<li>параметры <strong>FILE_SHARE_WRITE</strong> or <strong>FILE_SHARE_READ</strong> &#8212; общий доступ на чтение и запись к данному файлу. То есть файл будет доступен при одновременном использовании несколькими процессами.</li>
<li>следующий параметр &#8212; атрибут безопасности неопределен. То есть все дескрипторы будут доступны дочерним процессам вашего приложения.</li>
<li>параметр <strong>CREATE_NEW</strong> указывает на создание нового файла. Если файл с заданным именем существует, то будет возвращен код ошибки. Если использовать параметр <strong>CREATE_ALWAYS</strong>, то в этом случае, если файл существует, то он будет перезаписан.</li>
<li>параметр <strong>FILE_ATTRIBUTE_NORMAL</strong> определяет файлу стандартные атрибуты. А если указывать флаг <strong>FILE_FLAG_OVERLAPPED</strong>, то файл будет доступен в асинхронном режиме.</li>
<li>так как мы не используем шаблоны, то в качестве этого параметра указываем ноль.</li>
</ul>
<p><strong>Функция OpenFile</strong></p>
<p>Данная функция, по сути своей, предназначена для открытия файлов или устройств. Функция OpenFile в случае успеха возвращает дескриптор (указатель) открываемого файла. В случае неудачи мы получим в качестве дескриптора значение <strong>INVALID_HANDLE_VALUE</strong>.<br />
<strong>C/C++</strong></p>
<pre class=".brush: cpp">
 HFILE WINAPI OpenFile(
  LPCSTR lpFileName,
  LPOFSTRUCT lpReOpenBuff,
  UINT uStyle
);
</pre>
<p><strong>Delphi</strong></p>
<pre class=".brush: pascal">
function OpenFile(
   lpFileName: LPCSTR,   //имя файла (устройства)
   lpReOpenBuff: TOFStruct,  //специальная структура открываемого файла
   uStyle: UINT //флаги доступа к файлу
): HFILE; stdcall;
</pre>
<p>Теперь рассмотрим используемые параметры:</p>
<ul>
<li>в качестве первого параметра указывается имя открываемого файла.</li>
<li>вторым параметром является специальная структура открываемого файла, в которую заносится полезная инфа о файле.</li>
<li>3 параметр представляет собой совокупность флагов для работы с файлом.</li>
</ul>
<p>Собственно, как открыть файл:<br />
<strong>C/C++</strong></p>
<pre class=".brush: cpp">
{
   Handle FileHandle;
   FileHandle= OpenFile("Settings.ini", Buf, OF_Create |
                            OF_READWRITE | OF_SHARE_EXCLUSIVE);
   CloseHandle(FileHandle);
}
</pre>
<p><strong>Delphi</strong></p>
<pre class=".brush: pascal">
var
  FileHandle:THandle;
begin
   FileHandle:=OpenFile(PChar('Settings.ini'), Buf, OF_Create
                     Or OF_READWRITE Or OF_SHARE_EXCLUSIVE);
   CloseHandle(FileHandle);
end;
</pre>
<p>В данном примере стоит уделить внимание флагам. Первые 2 из которых определяют доступ к файлу, а флаг <strong>OF_SHARE_EXCLUSIVE</strong> сообщает системе, что доступ к этому файлу запрещен до тех пор, пока указатель на этот файл не освободится.</p>
<p><strong>Функция ReadFile</strong></p>
<p>Данная функция предназначена для чтения файлов или с устройств ввода/вывода. В случае успешного выполнения операции  чтения, возвращается логическое значение true, иначе false. А функция <strong>GetLastError</strong> вернет <strong>ERROR_HANDLE_EOF</strong>.<br />
<strong>C/C++</strong></p>
<pre class=".brush: cpp">
BOOL ReadFile(HANDLE hFile, //собственно указатель на файл
         LPVOID lpBuffer,  // указатель на буфер - куда записываем считанные данные
         DWORD nNumberOfBytesToRead, //объем считываемых данных, не может превышать размер буфера
         LPDWORD lpNumberOfBytesRead, //фактический размер считанных данных
         LPOVERLAPPED lpOverlapped   // флаг режима доступа к файлу: асинхронный(<strong>FILE_FLAG_OVERLAPPED</strong>)
                                    //или синхронный(<strong>NULL</strong>)
);
</pre>
<p><strong>Delphi</strong>
<pre class=".brush: pascal">
function ReadFile(
         hFile: THandle;   //собственно указатель на файл
         var Buffer;       // указатель на буфер - куда записываем считанные данные
         nNumberOfBytesToRead: DWORD;  //объем считываемых данных, не может превышать размер буфера
         var lpNumberOfBytesRead: DWORD; //фактический размер считанных данных
         lpOverlapped: POverlapped// флаг режима доступа к файлу: асинхронный(<strong>FILE_FLAG_OVERLAPPED</strong>)
                                    //или синхронный(<strong>nil</strong>)
): BOOL; stdcall;
</pre>
<p>Теперь поглядим рабочий пример:<br />
<strong>C/C++</strong></p>
<pre class=".brush: cpp">
{
Handle FileHandle;
char Buf[1000];
...
     ReadFile(FileHandle, Buf, sizeof(buf),NULL);
...
}
</pre>
<p><strong>Delphi</strong></p>
<pre class=".brush: pascal">
var
  FileHandle:THandle;
  Buf:array[1..1000] of char;
begin
...
   ReadFile(FileHandle, Buf, sizeof(buf),NULL);
...
end;
</pre>
<p><strong>Функция WriteFile</strong></p>
<p>Данная функция предназначена для записи в файл или устройство ввода/вывода. С ней все аналогично что и с функцией ReadFile(). В случае успешного выполнения операции  чтения, возвращается логическое значение true, иначе false. А функция <strong>GetLastError</strong> вернет <strong>ERROR_HANDLE_EOF</strong>.<br />
<strong>C/C++</strong></p>
<pre class=".brush: cpp">
BOOL WriteFile(HANDLE hFile, //собственно указатель на файл
         LPVOID lpBuffer,  // указатель на буфер - откуда записываем данные в  файл
         DWORD nNumberOfBytesToWrite, //объем записываемых данных
         LPDWORD lpNumberOfBytesWrite, //фактический размер записанных данных
         LPOVERLAPPED lpOverlapped   // флаг режима доступа к файлу: асинхронный(<strong>FILE_FLAG_OVERLAPPED</strong>)
                                    //или синхронный(<strong>NULL</strong>)
);
</pre>
<p><strong>Delphi</strong></p>
<pre class=".brush: pascal">
function WriteFile(
         hFile: THandle;   //собственно указатель на файл
         var Buffer;       // указатель на буфер - откуда записываем данные в  файл
         nNumberOfBytesToWrite: DWORD;  //объем записываемых данных
         var lpNumberOfBytesWrite: DWORD; //фактический размер записанных данных
         lpOverlapped: POverlapped// флаг режима доступа к файлу: асинхронный(<strong>FILE_FLAG_OVERLAPPED</strong>)
                                    //или синхронный(<strong>nil</strong>)
): BOOL; stdcall;
</pre>
<p>Теперь поглядим рабочий пример:<br />
<strong>C/C++</strong></p>
<pre class=".brush: cpp">
{
Handle FileHandle;
char Buf[1000];
...
     ReadFile(FileHandle, Buf, sizeof(buf),NULL);
...
}
</pre>
<p><strong>Delphi</strong></p>
<pre class=".brush: pascal">
var
  FileHandle:THandle;
  Buf:array[1..1000] of char;
begin
...
   ReadFile(FileHandle, Buf, sizeof(buf),NULL);
...
end;
</pre>
<p><strong>Функция CloseFile</strong></p>
<p>Эта функция достаточно проста. Выполняет действия по освобождению указателя на файл. Ее необходимость очевидна &#8212; чтобы не засорять память ненужными указателями и позволять работу с файлами другим процессам. В качестве ее единственного параметра передается указатель на ранее открытый файл.</p>
<p>Теперь поглядим рабочий пример:<br />
<strong>C/C++</strong></p>
<pre class=".brush: cpp">
{
   Handle FileHandle;
   FileHandle= OpenFile("Settings.ini", Buf, OF_Create |
                            OF_READWRITE | OF_SHARE_EXCLUSIVE);
...
   CloseHandle(FileHandle);
}
</pre>
<p><strong>Delphi</strong></p>
<pre class=".brush: pascal">
var
  FileHandle:THandle;
begin
   FileHandle:=OpenFile(PChar('Settings.ini'), Buf, OF_Create
                     Or OF_READWRITE Or OF_SHARE_EXCLUSIVE);
...
   CloseHandle(FileHandle);
end;
</pre>
<p><strong>Функция DeleteFile</strong></p>
<p>Эта функция так же не отличается особой сложностью. Данная функция удаляет файл, который указан в параметре.  Функция возвращает значение true если выполняется успешно. Иначе возвращает false, а код ошибки можно получить с помощью <strong>GetLastError</strong>.<br />
<strong>C/C++</strong></p>
<pre class=".brush: cpp">
BOOL WINAPI DeleteFile(
      LPCTSTR lpFileName // имя файла, который надо удалить
);
</pre>
<p><strong>Delphi</strong></p>
<pre class=".brush: pascal">
function DeleteFile(
      lpFileName: PChar; // имя файла, который надо удалить
 ): BOOL; stdcall;
</pre>
<p>Теперь поглядим рабочий пример:<br />
<strong>C/C++</strong></p>
<pre class=".brush: cpp">
{
...
     DeleteFile("C:\Temp\test.txt");// если указать только
// имя файла, то будет осуществлена попытка удалить файл из папки, откуда была запущена программа

...
}
</pre>
<p><strong>Delphi</strong></p>
<pre class=".brush: pascal">
begin
...
     DeleteFile('C:\Temp\test.txt');// если указать только
// имя файла, то будет осуществлена попытка удалить файл из папки, откуда была запущена программа
...
end;
</pre>
<p><strong>Функция CopyFile</strong></p>
<p>Основное назначение этой функции &#8212; копирование файла. В случае успеха возвращает true, иначе &#8212; false. Код ошибки можно получить с помощью <strong>GetLastError</strong>.<br />
<strong>C/C++</strong></p>
<pre class=".brush: cpp">
BOOL CopyFile(
     LPCTSTR lpExistingFileName,// Указатель на файл, который надо копировать
     LPCTSTR lpNewFileName, // Указатель на имя файла, куда надо копировать
     BOOL bFailIfExists //если указать true, то в случае существования такого файла,
      // произойдет ошибка, если false - то существующий файл будет перезаписан.
);
</pre>
<p><strong>Delphi</strong></p>
<pre class=".brush: pascal">
function CopyFile(
     lpExistingFileName, // Указатель на файл, который надо копировать
     lpNewFileName: PChar; // Указатель на имя файла, куда надо копировать
     bFailIfExists: BOOL //если указать true, то в случае существования такого файла,
      // он будет перезаписан, если false - то произойдет ошибка.
): BOOL; stdcall;
</pre>
<p>Теперь поглядим рабочий пример:<br />
<strong>C/C++</strong></p>
<pre class=".brush: cpp">
{
...
     CopyFile("C:\Temp\test1.txt","C:\Temp\test2.txt", true); // если указать только
// имя файла, то все действия будут выполнены в папке из которой запущена прога
...
}
</pre>
<p><strong>Delphi</strong></p>
<pre class=".brush: pascal">
begin
...
     CopyFile('C:\Temp\test1.txt','C:\Temp\test2.txt', false);// если указать только
// имя файла, то все действия будут выполнены в папке из которой запущена прога...
end;
</pre>
<p><strong>Функция FindFirstFile</strong></p>
<p>Данная функция запускает поиск в указанной директории. Функция возвращает указатель на найденный файл, если нет, то возврат будет типа ERROR_NO_MORE_FILES.<br />
<strong>C/C++</strong></p>
<pre class=".brush: cpp">
HANDLE FindFirstFile(
    LPCTSTR lpFileName,	// Строка, содержащая путь для поиска файлов.
    LPWIN32_FIND_DATA lpFindFileData // Информация о найденном файле
);
</pre>
<p><strong>Delphi</strong></p>
<pre class=".brush: pascal">
function FindFirstFile(
   lpFileName: PChar; // Строка, содержащая путь для поиска файлов.
   var lpFindFileData: TWIN32FindData // Информация о найденном файле
): THandle; stdcall;
</pre>
<p>Теперь рассмотрим параметры подробней:</p>
<ul>
<li> lpFileName &#8212; строка, содержащая путь для поиска файла. Эта строка может указывать наконкретный файл типа &#8216;c:\filename.txt&#8217; или может хранить шаблон &#8216;c:\*.*&#8217;. Если указывать шаблон, то это даёт возможность перечислить все файлы удовлетворяющие шаблону.</li>
</ul>
<ul>
<li> lpFindFileData &#8212; структура WIN32_FIND_DATA, в которую будет записана инфа о найденом файле.</li>
</ul>
<p>Расмотрим структуру WIN32_FIND_DATA немного подробнее:</p>
<pre class=".brush: cpp">
typedef struct _WIN32_FIND_DATA {
          DWORD dwFileAttributes;  // Атрибуты файла
          FILETIME ftCreationTime; // Время создания
          FILETIME ftLastAccessTime;  //Время последнего доступа
          FILETIME ftLastWriteTime;   //Время последней записи в файл
          DWORD    nFileSizeHigh;     //Верхний байт размера файла
          DWORD    nFileSizeLow;      //Нижний байт размера файла
          DWORD    dwReserved0;       //Зарезервировано
          DWORD    dwReserved1;       //Зарезервировано
          TCHAR    cFileName[ MAX_PATH ];    //Имя файла
          TCHAR    cAlternateFileName[ 14 ]; //Имя файла для отображения в DOS (8:3)
} WIN32_FIND_DATA;
</pre>
<p>Атрибутами файла может быть комбинация из флагов:</p>
<ul>
<li>FILE_ATTRIBUTE_ARCHIVE &#8212; архивный</li>
</ul>
<ul>
<li> FILE_ATTRIBUTE_COMPRESSED &#8212; сжатый</li>
</ul>
<ul>
<li> FILE_ATTRIBUTE_HIDDEN &#8212; скрытый</li>
</ul>
<ul>
<li> FILE_ATTRIBUTE_NORMAL &#8212; нормальный</li>
</ul>
<ul>
<li> FILE_ATTRIBUTE_OFFLINE &#8212; данные файла недоступны</li>
</ul>
<ul>
<li> FILE_ATTRIBUTE_READONLY &#8212; только для чтения</li>
</ul>
<ul>
<li> FILE_ATTRIBUTE_SYSTEM &#8212; системный</li>
</ul>
<ul>
<li> FILE_ATTRIBUTE_TEMPORARY &#8212; временный</li>
</ul>
<p>Размер файла разложен на два байта. Чтоб получить полный размер файла нужно выполнить действие (FInfo.nFileSizeHigh * MAXDWORD) + FInfo.nFileSizeLow. Это не самый эффективный (эффективнее сдвигать), но самый понятный способ.</p>
<p>Теперь поглядим рабочий пример:<br />
<strong>C/C++</strong></p>
<pre class=".brush: cpp">
{
   WIN32_FIND_DATA sss;
   HANDLE f;
   f = FindFirstFile("C:\*.*", &amp;sss);
...
   FindClose(f);
}
</pre>
<p><strong>Delphi</strong></p>
<pre class=".brush: pascal">
var
  sss: TWIN32FindData;
  f:THandle;
begin
...
  f:=FindFirstFile(PChar('C:\*.*'), sss);
...
  Windows.FindClose(f);
end;
</pre>
<p><strong>Функция FindNextFile</strong></p>
<p>Данная функция продолжает поиск начатый функцией FindFirstFile(). Если очередной файл найден, то функция возвращает значение true, иначе  возврат будет типа ERROR_NO_MORE_FILES.<br />
<strong>C/C++</strong></p>
<pre class=".brush: cpp">
BOOL FindNextFile(
    HANDLE hFindFile,	// Указатель на файл из предыдущего поиска
    LPWIN32_FIND_DATA lpFindFileData // Информация об очередном найденном файле
);
</pre>
<p><strong>Delphi</strong></p>
<pre class=".brush: pascal">
function FindNextFile(
    hFindFile: THandle; // Указатель на файл из предыдущего поиска
    var lpFindFileData: TWIN32FindData // Информация об очередном найденном файле
): BOOL; stdcall;
</pre>
<p>Со вторым параметром всё ясно, из описания функции FindFirstFile. А вот первый &#8212; это указатель на файл из предыдущего поиска. Он нужен, чтобы функция FindNextFile знала на каком файле был остановлен поиск и какой надо найти следующим.</p>
<p>Теперь поглядим рабочий пример:<br />
<strong>C/C++</strong></p>
<pre class=".brush: cpp">
{
   WIN32_FIND_DATA sss;
   HANDLE f;
   f = FindFirstFile("C:\*.*", &amp;sss);
   if(f != INVALID_HANDLE_VALUE)
      do{
         ...
      }while(FindNextFile(f,&amp;sss));
   FindClose(f);
}
</pre>
<p>А теперь пример рекурсивного поиска файлов:<br />
<strong>Delphi</strong></p>
<pre class=".brush: pascal">
function find(put: string):integer;
var
  sss: TWIN32FindData;
  f:THandle;
  result:Boolean;
begin
...
  f:=FindFirstFile(PChar('C:\*.*'), sss);
  if f&lt;&gt;INVALID_HANDLE_VALUE then
  begin
    result:=true;
    while(result)do
    begin
      if not((sss.cFileName = '.')or(sss.cFileName = '..')) then
        if (sss.dwFileAttributes and faDirectory) &gt; 0  then
          find(put+'\'+sss.cFileName)
        else
          writeln(sss.cFileName);
       ...
      result:=FindNextFile(f,sss);
    end;
  end;
  Windows.FindClose(f);
end;
</pre>
<p><strong>Функция GetFileSize</strong></p>
<p>Данная функция определяет размер файла, на который ссылается переданный указатель. Если размер файла меньше 4 Гб, то функция возвращает размер файла. Если размер файла больше 4Гб, то размер файла записан во втором параметре. В случае возникновения исключения будет возвращено значение типа INVALID_FILE_SIZE.<br />
<strong>C/C++</strong></p>
<pre class=".brush: cpp">
DWORD GetFileSize(
   HANDLE hFile,	   // Указатель на файл
   LPDWORD lpFileSizeHigh // старший байт размера файла, в качестве
            // этого парамметра можно указать <strong>NULL</strong>
);
</pre>
<p><strong>Delphi</strong></p>
<pre class=".brush: pascal">
function GetFileSize(
    hFile: THandle;         // Указатель на файл
    lpFileSizeHigh: Pointer //старший байт размера файла, в качестве
             // этого парамметра можно указать <strong>nil</strong>
): DWORD; stdcall;
</pre>
<p>Теперь поглядим рабочий пример:<br />
<strong>C/C++</strong></p>
<pre class=".brush: cpp">
{
DWORD FileSize;
Handle f;
...
FileSize=GetFileSize(f,NULL);
...
}
</pre>
<p><strong>Delphi</strong></p>
<pre class=".brush: pascal">
var
  FileSize:DWORD;
  f:THandle;
begin
  ...
  FileSize:=GetFileSize(f,nil);
  ...
end
</pre>
<p>На этом пока все, если вдруг возникли какие нибуть вопросы или замечания, прошу их высказывать на <a href="/forum/">форуме</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://zetblog.ru/programming/200902/winapi-%d1%80%d0%b0%d0%b1%d0%be%d1%82%d0%b0-%d1%81-%d1%84%d0%b0%d0%b9%d0%bb%d0%b0%d0%bc%d0%b8-%d0%be%d1%81%d0%bd%d0%be%d0%b2%d0%bd%d1%8b%d0%b5-%d1%84%d1%83%d0%bd%d0%ba%d1%86%d0%b8%d0%b8/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Безопасность: Инспектор файлов.</title>
		<link>http://zetblog.ru/programming/200902/%d0%b1%d0%b5%d0%b7%d0%be%d0%bf%d0%b0%d1%81%d0%bd%d0%be%d1%81%d1%82%d1%8c-%d0%b8%d0%bd%d1%81%d0%bf%d0%b5%d0%ba%d1%82%d0%be%d1%80-%d1%84%d0%b0%d0%b9%d0%bb%d0%be%d0%b2/</link>
		<comments>http://zetblog.ru/programming/200902/%d0%b1%d0%b5%d0%b7%d0%be%d0%bf%d0%b0%d1%81%d0%bd%d0%be%d1%81%d1%82%d1%8c-%d0%b8%d0%bd%d1%81%d0%bf%d0%b5%d0%ba%d1%82%d0%be%d1%80-%d1%84%d0%b0%d0%b9%d0%bb%d0%be%d0%b2/#comments</comments>
		<pubDate>Tue, 03 Feb 2009 13:54:11 +0000</pubDate>
		<dc:creator>C0ffe1n</dc:creator>
				<category><![CDATA[Программирование]]></category>
		<category><![CDATA[системное]]></category>
		<category><![CDATA[Delphi]]></category>
		<category><![CDATA[файлы]]></category>

		<guid isPermaLink="false">http://zetblog.ru/?p=509</guid>
		<description><![CDATA[В этой статье мы немного углубимся в дебри компьютерной безопасности. И на повестке дня повис вопрос, как вы уже догадались &#8212; &#171;Инспектор файлов&#187;. Что это и для чего он нужен я расскажу по мере чтения вами этой статьи, но замечу сразу, что испокон веков компьютерной эры, с тех самых времен, когда операционная система содрогнулась от [...]]]></description>
			<content:encoded><![CDATA[<p>В этой статье мы немного углубимся в дебри компьютерной безопасности. И на повестке дня повис вопрос, как вы уже догадались &#8212; &#171;Инспектор файлов&#187;. Что это и для чего он нужен я расскажу по мере чтения вами этой статьи, но замечу сразу, что испокон веков компьютерной эры, с тех самых времен, когда операционная система содрогнулась от вирусной эпидемии, на стражу ваших и системных файлов встал гроза контроля и целостности &#8212; &#171;Инспектор&#187;. Прошу прощение за эпическое отступление ;).<br />
<span id="more-509"></span><br />
Так вот, помимо установленных антивирусов и прочих специальных программ, которые выполняют кучу всяких полезностей, порой даже абсолютно не нужных в данный момент и только лишь отнимают наше драгоценное время. А мы то знаем, что время &#8212; деньги!<br />
Что же меня побудило написать статью на эту тему? Во-первых, я считаю, и вам даю на заметку, что пользоваться готовым софтом &#8212; это утеха юзеров и прочих бездельников. Каждый уважающий себя программист должен иметь в своем арсенале собственноручно написанный инструментарий отвечающий его задачам и требованием, и не одной команды лишней. Да и кроме того вы сами знаете, что делает ваша программа, и в любой момент можете вспороть ее и что то подправить, добавить или удалить, в отличие от чужих программулек. Во-вторых, зная, а кто не знал запомните, что ни один антивирус не может вас защитить на 100% от свеженькой вредоносной информационной субстанции, то бишь вирус и прочая нечисть, так как антивирусная индустрия всегда позади на шаг впереди идущих создателей этой дряни. Поэтому вашу безопасность можете обеспечить только вы сами и одним из средств обеспечения в этом деле является &#171;Инспектор файлов&#187;, который непоколебимо несет свою службу на полях информационного пространства и &#171;своих&#187; знает в &#171;лицо&#187;.</p>
<p>После недолгих эпических отступлений, вы уж простите меня, без лишних слов приступаем к реализации нашего стражника &#171;Инспектора&#187;. В первую очередь нам необходимо поставить задачу. Ей будет:<br />
- реализовать поиск файлов<br />
- проверку файлов на наличие их в банке данных, по соответствующим признакам(путь к файлу, дата создания, изменения и контрольная сумма)<br />
- добавление в новых кандидатов на прописку в банк данных<br />
- реализация интерфейса, связывающего предыдущие описанные задачи и действия пользователя.</p>
<p>В целом, получается вот такое тех. задание. А теперь от слов к делу. Для начала определимся с дизайном формы. Здесь я полагаюсь на ваш вкус, но потребуется нам две кнопки и поле вывода информации(Memo или ListBox).<br />
Однуиз кнопок определим под выбор папки &#8212; &#171;Обзор&#187;, и для нее напишем следующий код</p>
<pre><strong>Delphi</strong>
<div class="codesnip-container" >
<div class="pascal codesnip" style="font-family:monospace;"><span class="kw1">procedure</span> TForm1.<span class="me1">Button1Click</span><span class="br0">&#40;</span>Sender<span class="sy0">:</span> TObject<span class="br0">&#41;</span>;
<span class="kw1">begin</span>
&nbsp; Path <span class="sy0">:=</span> GetPath<span class="br0">&#40;</span><span class="st_h">'Выберите папку'</span><span class="br0">&#41;</span>;
&nbsp; <span class="kw1">if</span> Path &amp;lt;&amp;gt; <span class="st_h">''</span>
&nbsp; &nbsp; &nbsp;<span class="kw1">then</span> Label4.<span class="me1">Caption</span> <span class="sy0">:=</span> Path;
<span class="kw1">end</span>;</div>
</div>
</pre>
<p>А теперь опишем используемую функцию GetPath():</p>
<pre><strong>Delphi</strong>
<div class="codesnip-container" >
<div class="pascal codesnip" style="font-family:monospace;"><span class="kw1">function</span> GetPath<span class="br0">&#40;</span>mes<span class="sy0">:</span> <span class="kw4">string</span><span class="br0">&#41;</span><span class="sy0">:</span><span class="kw4">string</span>;
<span class="kw1">var</span>
&nbsp; Root<span class="sy0">:</span> <span class="kw4">string</span>; &nbsp; &nbsp; &nbsp;<span class="co1">// корневой каталог</span>
&nbsp; pwRoot <span class="sy0">:</span> PWideChar;
&nbsp; Dir<span class="sy0">:</span> <span class="kw4">string</span>;
<span class="kw1">begin</span>
&nbsp; Root <span class="sy0">:=</span> <span class="st_h">''</span>; <span class="co1">// по умолчанию корневой каталог - рабочий стол</span>
&nbsp; GetMem<span class="br0">&#40;</span>pwRoot<span class="sy0">,</span> <span class="br0">&#40;</span>Length<span class="br0">&#40;</span>Root<span class="br0">&#41;</span><span class="sy0">+</span>1<span class="br0">&#41;</span> <span class="sy0">*</span> 2<span class="br0">&#41;</span>;
&nbsp; pwRoot <span class="sy0">:=</span> StringToWideChar<span class="br0">&#40;</span>Root<span class="sy0">,</span>pwRoot<span class="sy0">,</span>MAX_PATH<span class="sy0">*</span>2<span class="br0">&#41;</span>;
&nbsp; <span class="kw1">if</span> SelectDirectory<span class="br0">&#40;</span>mes<span class="sy0">,</span> pwRoot<span class="sy0">,</span> Dir<span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp;<span class="kw1">then</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> length<span class="br0">&#40;</span>Dir<span class="br0">&#41;</span> <span class="sy0">=</span> <span class="nu0">2</span> &nbsp;<span class="co1">// пользователь выбрал корневой каталог</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">then</span> GetPath <span class="sy0">:=</span> Dir<span class="sy0">+</span><span class="st_h">'\'</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">else</span> GetPath <span class="sy0">:=</span> Dir
&nbsp; &nbsp; &nbsp;<span class="kw1">else</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; GetPath <span class="sy0">:=</span> <span class="st_h">''</span>;
<span class="kw1">end</span>;</div>
</div>
</pre>
<p>Итак, процедура выбора каталога для проверки реализована. Теперь приступим к реализации проверки файлов. Но сначала для второй кнопки опишем следующий код:</p>
<pre><strong>Delphi</strong>
<div class="codesnip-container" >
<div class="pascal codesnip" style="font-family:monospace;"><span class="kw1">procedure</span> TForm1.<span class="me1">Button2Click</span><span class="br0">&#40;</span>Sender<span class="sy0">:</span> TObject<span class="br0">&#41;</span>;
<span class="kw1">begin</span>
&nbsp; Form1.<span class="me1">ListBox1</span>.<span class="me1">Items</span>.<span class="me1">Add</span><span class="br0">&#40;</span>TimeToStr<span class="br0">&#40;</span>Time<span class="br0">&#41;</span><span class="sy0">+</span><span class="st_h">' :&amp;gt; Сканирование началось.'</span><span class="br0">&#41;</span>;
&nbsp; ListFiles.<span class="me1">Clear</span>;
&nbsp; FindF<span class="br0">&#40;</span>Path<span class="br0">&#41;</span>;
&nbsp; Scan_File;
&nbsp; Form1.<span class="me1">ListBox1</span>.<span class="me1">Items</span>.<span class="me1">Add</span><span class="br0">&#40;</span><span class="st_h">'==================================================='</span><span class="br0">&#41;</span>;
&nbsp; Form1.<span class="me1">ListBox1</span>.<span class="me1">Items</span>.<span class="me1">Add</span><span class="br0">&#40;</span>TimeToStr<span class="br0">&#40;</span>Time<span class="br0">&#41;</span><span class="sy0">+</span><span class="st_h">' :&amp;gt; Сканирование завершено.'</span><span class="br0">&#41;</span>;
<span class="kw1">end</span>;</div>
</div>
</pre>
<p>А теперь последовательно опишем используемые функции и первой будет процедура FindF(). Эта процедура осуществляет рекурсивный поиск файлов относительно выбранного корневого каталога и добавляет их в список для проверки. Смотрим листинг:</p>
<pre><strong>Delphi</strong>
<div class="codesnip-container" >
<div class="pascal codesnip" style="font-family:monospace;"><span class="kw1">procedure</span> FindF<span class="br0">&#40;</span>path_f<span class="sy0">:</span><span class="kw4">string</span><span class="br0">&#41;</span>;
<span class="kw1">begin</span>
<span class="co1">//Инициируем поиск</span>
&nbsp; <span class="kw1">if</span><span class="br0">&#40;</span>FindFirst<span class="br0">&#40;</span>path_f<span class="sy0">+</span><span class="st_h">'\*.*'</span><span class="sy0">,</span>faAnyFile<span class="sy0">,</span>SearchRec<span class="br0">&#41;</span> <span class="sy0">=</span> 0<span class="br0">&#41;</span> <span class="kw1">then</span>
&nbsp; <span class="kw1">begin</span>
&nbsp; &nbsp; <span class="kw1">repeat</span>
&nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="kw1">not</span><span class="br0">&#40;</span><span class="br0">&#40;</span>SearchRec.<span class="kw1">name</span> <span class="sy0">=</span> <span class="st_h">'.'</span><span class="br0">&#41;</span><span class="kw1">or</span><span class="br0">&#40;</span>SearchRec.<span class="kw1">name</span> <span class="sy0">=</span> <span class="st_h">'..'</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="kw1">then</span>
&nbsp; &nbsp; &nbsp; <span class="kw1">begin</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> SearchRec.<span class="me1">Attr</span> &amp;lt;&amp;gt; faDirectory <span class="kw1">then</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">begin</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ListFiles.<span class="me1">Add</span><span class="br0">&#40;</span>path_f<span class="sy0">+</span><span class="st_h">'\'</span><span class="sy0">+</span>SearchRec.<span class="kw1">Name</span><span class="br0">&#41;</span>; <span class="co1">//если файл, добавляем в список</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Inc<span class="br0">&#40;</span>Count_file<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">end</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">else</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; FindF<span class="br0">&#40;</span>path_f<span class="sy0">+</span><span class="st_h">'\'</span><span class="sy0">+</span>SearchRec.<span class="kw1">Name</span><span class="br0">&#41;</span>; <span class="co1">//если папка, запускаем рекурсию</span>

&nbsp; &nbsp; &nbsp; <span class="kw1">end</span>;
&nbsp; &nbsp; <span class="kw1">until</span> <span class="br0">&#40;</span>FindNext<span class="br0">&#40;</span>SearchRec<span class="br0">&#41;</span>&amp;lt;&amp;gt;0<span class="br0">&#41;</span>;
&nbsp; &nbsp; FindClose<span class="br0">&#40;</span>SearchRec<span class="br0">&#41;</span>;
&nbsp; <span class="kw1">end</span>;
<span class="kw1">end</span>;</div>
</div>
</pre>
<p>Далее рассмотрим процедуру Scan_File(). Ее задача проверить каждый найденный файл на наличие в своей базе данных, сверить контрольную сумму, дату создания и дату последнего изменения файла. В случае если будут обнаружены какие-либо несоответсвия, немедля бьет тревогу. Смотрим:</p>
<pre><strong>Delphi</strong>
<div class="codesnip-container" >
<div class="pascal codesnip" style="font-family:monospace;"><span class="kw1">procedure</span> Scan_File;
<span class="kw1">var</span>
&nbsp; crc32T<span class="sy0">,</span>dataCT<span class="sy0">,</span>dataMT<span class="sy0">:</span>Cardinal;
&nbsp; i<span class="sy0">:</span><span class="kw4">integer</span>;
&nbsp; f<span class="sy0">:</span> THandle;
&nbsp; SearchF<span class="sy0">:</span>TWIN32FindData;
&nbsp; temp<span class="sy0">:</span><span class="kw4">boolean</span>;
<span class="kw1">begin</span>
&nbsp; i<span class="sy0">:=</span><span class="nu0">0</span>;
<span class="co1">//проверка на первый запуск, а точнее была база только что создана или нет.</span>
&nbsp; <span class="kw1">if</span> newBase <span class="sy0">=</span> <span class="kw2">true</span> <span class="kw1">then</span>
&nbsp; <span class="co1">//если да, то заносим список найденых файлов с их</span>
&nbsp; <span class="co1">//параметрами(путь, контрольная сумма, дата создания, дата изменения) в базу</span>
&nbsp; &nbsp; <span class="kw1">while</span> i &amp;lt;<span class="sy0">=</span> Count_file<span class="sy0">-</span>1 <span class="kw1">do</span>
&nbsp; &nbsp; <span class="kw1">begin</span>
&nbsp; &nbsp; &nbsp; WriteIB<span class="br0">&#40;</span>ListFiles.<span class="me1">Strings</span><span class="br0">&#91;</span>i<span class="br0">&#93;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; Inc<span class="br0">&#40;</span>i<span class="br0">&#41;</span>;
&nbsp; &nbsp; <span class="kw1">end</span>;
<span class="co1">//далее производим проверку</span>
&nbsp; i<span class="sy0">:=</span><span class="nu0">0</span>;
&nbsp; <span class="kw1">while</span> i &amp;lt;<span class="sy0">=</span> Count_file<span class="sy0">-</span>1 <span class="kw1">do</span>
&nbsp; <span class="kw1">begin</span>
&nbsp; &nbsp; <span class="kw1">try</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">//проверяем наличие файла</span>
&nbsp; &nbsp; &nbsp; FS<span class="sy0">:=</span>TFileStream.<span class="me1">Create</span><span class="br0">&#40;</span>ListFiles.<span class="me1">Strings</span><span class="br0">&#91;</span>i<span class="br0">&#93;</span><span class="sy0">,</span>fmOpenRead <span class="kw1">or</span> fmShareDenyNone<span class="br0">&#41;</span>;
&nbsp; &nbsp; <span class="kw1">except</span>
&nbsp; &nbsp; &nbsp; on Exception <span class="kw1">do</span>
&nbsp; &nbsp; &nbsp; <span class="kw1">begin</span>
&nbsp; &nbsp; &nbsp; &nbsp; Form1.<span class="me1">ListBox1</span>.<span class="me1">Items</span>.<span class="me1">Add</span><span class="br0">&#40;</span><span class="st_h">'не открывается '</span><span class="sy0">+</span>ListFiles.<span class="me1">Strings</span><span class="br0">&#91;</span>i<span class="br0">&#93;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">break</span>;
&nbsp; &nbsp; &nbsp; <span class="kw1">end</span>;
&nbsp; &nbsp; <span class="kw1">end</span>;
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">//Вычисляем контрольную сумму</span>
&nbsp; &nbsp; crc32T<span class="sy0">:=</span>CRC32Stream<span class="br0">&#40;</span>FS<span class="sy0">,</span>0<span class="br0">&#41;</span>;
&nbsp; &nbsp; FS.<span class="me1">Free</span>;
&nbsp; &nbsp; f<span class="sy0">:=</span>FindFirstFile<span class="br0">&#40;</span>PChar<span class="br0">&#40;</span>ListFiles.<span class="me1">Strings</span><span class="br0">&#91;</span>i<span class="br0">&#93;</span><span class="br0">&#41;</span><span class="sy0">,</span>SearchF<span class="br0">&#41;</span>;
&nbsp; &nbsp; <span class="kw1">if</span> f &amp;lt;&amp;gt; INVALID_HANDLE_VALUE <span class="kw1">then</span>
&nbsp; &nbsp; <span class="kw1">begin</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">//определяем дату создания и дату изменения файла</span>
&nbsp; &nbsp; &nbsp; dataCT<span class="sy0">:=</span>SearchF.<span class="me1">ftCreationTime</span>.<span class="me1">dwLowDateTime</span>;
&nbsp; &nbsp; &nbsp; dataMT<span class="sy0">:=</span>SearchF.<span class="me1">ftLastWriteTime</span>.<span class="me1">dwLowDateTime</span>;
&nbsp; &nbsp; <span class="kw1">end</span>;
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">//запускаем процедуру поиска файла с найденными параметрами</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">//по базе</span>
&nbsp; &nbsp; temp<span class="sy0">:=</span>FindIB<span class="br0">&#40;</span>ListFiles.<span class="me1">Strings</span><span class="br0">&#91;</span>i<span class="br0">&#93;</span><span class="sy0">,</span>crc32T<span class="sy0">,</span>dataCT<span class="sy0">,</span>dataMT<span class="br0">&#41;</span>;
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw1">Not</span> temp <span class="kw3">and</span> <span class="br0">&#40;</span>FindFlagB<span class="sy0">=</span>0<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="kw1">then</span>
&nbsp; &nbsp; <span class="kw1">begin</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">//если файл отсутсвует то выводим тревожное сообщение</span>
&nbsp; &nbsp; &nbsp; Form1.<span class="me1">ListBox1</span>.<span class="me1">Items</span>.<span class="me1">Add</span><span class="br0">&#40;</span><span class="st_h">'ВНИМАНИЕ! Данный файл в базе отсутствует: '</span><span class="sy0">+</span>ListFiles.<span class="me1">Strings</span><span class="br0">&#91;</span>i<span class="br0">&#93;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; <span class="kw1">end</span>;
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">//Если файл в наличии то выводим результат проверки</span>
&nbsp; &nbsp; <span class="kw1">if</span> temp <span class="kw3">and</span> <span class="br0">&#40;</span>FindFlagB<span class="sy0">=</span>1<span class="br0">&#41;</span> <span class="kw1">then</span>
&nbsp; &nbsp; &nbsp; Form1.<span class="me1">ListBox1</span>.<span class="me1">Items</span>.<span class="me1">Add</span><span class="br0">&#40;</span>ListFiles.<span class="me1">Strings</span><span class="br0">&#91;</span>i<span class="br0">&#93;</span><span class="sy0">+</span><span class="st_h">' - файл проверен. ОК.'</span><span class="br0">&#41;</span>
&nbsp; &nbsp; <span class="kw1">else</span>
&nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw1">not</span> temp<span class="br0">&#41;</span> <span class="kw3">and</span> <span class="br0">&#40;</span>FindFlagB<span class="sy0">=</span>1<span class="br0">&#41;</span> <span class="kw1">then</span>
&nbsp; &nbsp; &nbsp; Form1.<span class="me1">ListBox1</span>.<span class="me1">Items</span>.<span class="me1">Add</span><span class="br0">&#40;</span>ListFiles.<span class="me1">Strings</span><span class="br0">&#91;</span>i<span class="br0">&#93;</span><span class="sy0">+</span><span class="st_h">' - файл был изменен.'</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; Inc<span class="br0">&#40;</span>i<span class="br0">&#41;</span>;
&nbsp; &nbsp; Form1.<span class="me1">Update</span>;
&nbsp; <span class="kw1">end</span>;
<span class="kw1">end</span>;</div>
</div>
</pre>
<p>Далее опишем функции для работы с базой. И первая функция FindIB(). Она осуществляет проверку наличия интересующего файла в базе и сверку переданных параметров искомого файла с теми, что соответствуют ему.</p>
<pre><strong>Delphi</strong>
<div class="codesnip-container" >
<div class="pascal codesnip" style="font-family:monospace;"><span class="kw1">function</span> FindIB<span class="br0">&#40;</span>strS<span class="sy0">:</span><span class="kw4">string</span>;crc32<span class="sy0">,</span>dataC<span class="sy0">,</span>dataM<span class="sy0">:</span>Cardinal<span class="br0">&#41;</span><span class="sy0">:</span><span class="kw4">Boolean</span>;
<span class="kw1">var</span>
&nbsp; fileS<span class="sy0">:</span>TextFile;
&nbsp; nameD<span class="sy0">,</span>fn<span class="sy0">:</span><span class="kw4">string</span>;
&nbsp; crc32D<span class="sy0">,</span>dataCD<span class="sy0">,</span>dataMD<span class="sy0">:</span>Cardinal;
&nbsp; i<span class="sy0">,</span>it<span class="sy0">:</span><span class="kw4">integer</span>;
<span class="kw1">begin</span>
&nbsp; FindFlagB<span class="sy0">:=</span><span class="nu0">0</span>;
&nbsp; AssignFile<span class="br0">&#40;</span>fileS<span class="sy0">,</span><span class="st_h">'IFdb.db'</span><span class="br0">&#41;</span>;
&nbsp; Reset<span class="br0">&#40;</span>fileS<span class="br0">&#41;</span>;
&nbsp; <span class="kw1">While</span> <span class="kw1">Not</span> <span class="kw3">EOF</span><span class="br0">&#40;</span>fileS<span class="br0">&#41;</span> <span class="kw1">do</span>
&nbsp; <span class="kw1">begin</span>
&nbsp; <span class="co1">//считываем данные из базы</span>
&nbsp; &nbsp; <span class="kw3">ReadLn</span><span class="br0">&#40;</span>fileS<span class="sy0">,</span>nameD<span class="br0">&#41;</span>;
&nbsp; <span class="co1">// получаем имя файла</span>
&nbsp; &nbsp; it<span class="sy0">:=</span>Pos<span class="br0">&#40;</span><span class="st_h">'$'</span><span class="sy0">,</span>nameD<span class="br0">&#41;</span>;
&nbsp; &nbsp; fn<span class="sy0">:=</span>copy<span class="br0">&#40;</span>nameD<span class="sy0">,</span>1<span class="sy0">,</span>it<span class="sy0">-</span>1<span class="br0">&#41;</span>;
&nbsp; &nbsp; Delete<span class="br0">&#40;</span>nameD<span class="sy0">,</span>1<span class="sy0">,</span>it<span class="br0">&#41;</span>;
&nbsp; <span class="co1">//получаем контрольную сумму</span>
&nbsp; &nbsp; it<span class="sy0">:=</span>Pos<span class="br0">&#40;</span><span class="st_h">'$'</span><span class="sy0">,</span>nameD<span class="br0">&#41;</span>;
&nbsp; &nbsp; crc32D<span class="sy0">:=</span>StrToInt64<span class="br0">&#40;</span>copy<span class="br0">&#40;</span>nameD<span class="sy0">,</span>1<span class="sy0">,</span>it<span class="sy0">-</span>1<span class="br0">&#41;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; Delete<span class="br0">&#40;</span>nameD<span class="sy0">,</span>1<span class="sy0">,</span>it<span class="br0">&#41;</span>;
&nbsp; <span class="co1">//получаем дату создания файла</span>
&nbsp; &nbsp; it<span class="sy0">:=</span>Pos<span class="br0">&#40;</span><span class="st_h">'$'</span><span class="sy0">,</span>nameD<span class="br0">&#41;</span>;
&nbsp; &nbsp; dataCD<span class="sy0">:=</span>StrToInt64<span class="br0">&#40;</span>copy<span class="br0">&#40;</span>nameD<span class="sy0">,</span>1<span class="sy0">,</span>it<span class="sy0">-</span>1<span class="br0">&#41;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; Delete<span class="br0">&#40;</span>nameD<span class="sy0">,</span>1<span class="sy0">,</span>it<span class="br0">&#41;</span>;
&nbsp; <span class="co1">//получаем дату последнего изменения</span>
&nbsp; &nbsp; dataMD<span class="sy0">:=</span>StrToInt64<span class="br0">&#40;</span>copy<span class="br0">&#40;</span>nameD<span class="sy0">,</span>1<span class="sy0">,</span>length<span class="br0">&#40;</span>nameD<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; <span class="kw1">if</span> strS <span class="sy0">=</span> fn <span class="kw1">then</span>
&nbsp; &nbsp; <span class="kw1">begin</span>
&nbsp; &nbsp; &nbsp; FindFlagB<span class="sy0">:=</span><span class="nu0">1</span>;
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> crc32 <span class="sy0">=</span> crc32D <span class="kw1">then</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> dataC <span class="sy0">=</span> dataCD <span class="kw1">then</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> dataM <span class="sy0">=</span> dataMD <span class="kw1">then</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">begin</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; FindIB<span class="sy0">:=</span><span class="kw2">true</span>;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CloseFile<span class="br0">&#40;</span>fileS<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; exit;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">end</span>;
&nbsp; &nbsp; <span class="kw1">end</span>;
&nbsp; <span class="kw1">end</span>;
&nbsp; FindIB<span class="sy0">:=</span><span class="kw2">false</span>;
&nbsp; CloseFile<span class="br0">&#40;</span>fileS<span class="br0">&#41;</span>;
<span class="kw1">end</span>;</div>
</div>
</pre>
<p>Теперь рассмотрим функцию WriteIB(). Которая заносит в базу путь к файлу, его контрольную сумму, дату создания и дату последнего изменения.</p>
<pre><strong>Delphi</strong>
<div class="codesnip-container" >
<div class="pascal codesnip" style="font-family:monospace;"><span class="kw1">procedure</span> WriteIB<span class="br0">&#40;</span><span class="kw1">name</span><span class="sy0">:</span><span class="kw4">string</span><span class="br0">&#41;</span>;
<span class="kw1">var</span>
&nbsp; dbf<span class="sy0">:</span>TextFile;
&nbsp; i<span class="sy0">:</span>Cardinal;
&nbsp; s<span class="sy0">:</span><span class="kw4">string</span>;
&nbsp; f<span class="sy0">:</span> THandle;
&nbsp; SearchF<span class="sy0">:</span>TWIN32FindData;
<span class="kw1">begin</span>
<span class="co1">//открываем базу</span>
&nbsp; AssignFile<span class="br0">&#40;</span>dbf<span class="sy0">,</span><span class="st_h">'IFdb.db'</span><span class="br0">&#41;</span>;
&nbsp; Append<span class="br0">&#40;</span>dbf<span class="br0">&#41;</span>;
&nbsp; <span class="co1">//инициализируем переменные</span>
&nbsp; s<span class="sy0">:=</span><span class="kw1">name</span><span class="sy0">+</span><span class="st_h">'$'</span>;
&nbsp; <span class="kw1">try</span>
&nbsp; <span class="co1">//проверяем наличие добавляемого файла</span>
&nbsp; &nbsp; FS<span class="sy0">:=</span>TFileStream.<span class="me1">Create</span><span class="br0">&#40;</span><span class="kw1">name</span><span class="sy0">,</span>fmOpenRead <span class="kw1">or</span> fmShareDenyNone<span class="br0">&#41;</span>;
&nbsp; <span class="kw1">except</span>
&nbsp; &nbsp; on Exception <span class="kw1">do</span>
&nbsp; &nbsp; <span class="kw1">begin</span>
&nbsp; &nbsp; &nbsp; Form1.<span class="me1">ListBox1</span>.<span class="me1">Items</span>.<span class="me1">Add</span><span class="br0">&#40;</span><span class="st_h">'не открывается '</span><span class="sy0">+</span><span class="kw1">name</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; exit;
&nbsp; &nbsp; <span class="kw1">end</span>;
&nbsp; <span class="kw1">end</span>;
&nbsp; <span class="co1">//вычисляем контрольную сумму</span>
&nbsp; i<span class="sy0">:=</span>CRC32Stream<span class="br0">&#40;</span>FS<span class="sy0">,</span>0<span class="br0">&#41;</span>;
&nbsp; s<span class="sy0">:=</span>s<span class="sy0">+</span>IntToStr<span class="br0">&#40;</span>i<span class="br0">&#41;</span>;
&nbsp; f<span class="sy0">:=</span>FindFirstFile<span class="br0">&#40;</span>PChar<span class="br0">&#40;</span><span class="kw1">name</span><span class="br0">&#41;</span><span class="sy0">,</span>SearchF<span class="br0">&#41;</span>;
&nbsp; <span class="kw1">if</span> f &amp;lt;&amp;gt; INVALID_HANDLE_VALUE <span class="kw1">then</span>
&nbsp; &nbsp;<span class="co1">//определяем дату создания и дату изменения файла s:=s+'$'+IntToStr(SearchF.ftCreationTime.dwLowDateTime)+'$'+IntToStr(SearchF.ftLastWriteTime.dwLowDateTime);</span>
&nbsp; <span class="kw3">writeln</span><span class="br0">&#40;</span>dbf<span class="sy0">,</span>s<span class="br0">&#41;</span>;
&nbsp; CloseFile<span class="br0">&#40;</span>dbf<span class="br0">&#41;</span>;
&nbsp; FS.<span class="me1">Free</span>;
<span class="kw1">end</span>;</div>
</div>
</pre>
<p>Далее надо объявить необходимые глобальные переменные:</p>
<pre><strong>Delphi</strong>
<div class="codesnip-container" >
<div class="pascal codesnip" style="font-family:monospace;"><span class="kw1">var</span>
&nbsp; SearchRec<span class="sy0">:</span> TSearchRec;
&nbsp; Count_file<span class="sy0">,</span>FindFlagB<span class="sy0">,</span>step<span class="sy0">:</span> <span class="kw4">integer</span>;
&nbsp; Path<span class="sy0">:</span> <span class="kw4">string</span>;
&nbsp; ListFiles<span class="sy0">:</span> TStrings;
&nbsp; FS<span class="sy0">:</span>TFileStream;
&nbsp; newBase<span class="sy0">:</span><span class="kw4">boolean</span>;</div>
</div>
</pre>
<p>Теперь необходимо для события onCreate написать следующее:</p>
<pre><strong>Delphi</strong>
<div class="codesnip-container" >
<div class="pascal codesnip" style="font-family:monospace;"><span class="kw1">procedure</span> TForm1.<span class="me1">FormCreate</span><span class="br0">&#40;</span>Sender<span class="sy0">:</span> TObject<span class="br0">&#41;</span>;
<span class="kw1">var</span>
&nbsp; f<span class="sy0">:</span> THandle;
&nbsp; SearchF<span class="sy0">:</span>TWIN32FindData;
<span class="kw1">begin</span>
&nbsp; SendMessage<span class="br0">&#40;</span>ListBox1.<span class="me1">Handle</span><span class="sy0">,</span>LB_SetHorizontalExtent<span class="sy0">,</span>1000<span class="sy0">,</span>0<span class="br0">&#41;</span>;
&nbsp; newBase<span class="sy0">:=</span> <span class="kw2">false</span>;
&nbsp; ListFiles<span class="sy0">:=</span>TStringList.<span class="me1">Create</span>;
&nbsp; Path<span class="sy0">:=</span><span class="st_h">'*.*'</span>;
&nbsp; f<span class="sy0">:=</span>FindFirstFile<span class="br0">&#40;</span><span class="st_h">'IFdb.db'</span><span class="sy0">,</span>SearchF<span class="br0">&#41;</span>;
&nbsp; <span class="kw1">if</span> f <span class="sy0">=</span> INVALID_HANDLE_VALUE <span class="kw1">then</span>
&nbsp; <span class="kw1">begin</span>
&nbsp; &nbsp; f<span class="sy0">:=</span>CreateFile<span class="br0">&#40;</span><span class="st_h">'IFdb.db'</span><span class="sy0">,</span> GENERIC_READ <span class="kw1">or</span> GENERIC_WRITE<span class="sy0">,</span> FILE_SHARE_WRITE <span class="kw1">or</span> FILE_SHARE_READ<span class="sy0">,</span> <span class="kw2">nil</span><span class="sy0">,</span> CREATE_NEW<span class="sy0">,</span> FILE_ATTRIBUTE_NORMAL <span class="kw1">or</span> FILE_FLAG_OVERLAPPED<span class="sy0">,</span> 0<span class="br0">&#41;</span>;
&nbsp; &nbsp; <span class="kw1">if</span> f &amp;lt;&amp;gt; INVALID_HANDLE_VALUE <span class="kw1">then</span>
&nbsp; &nbsp; <span class="kw1">begin</span>
&nbsp; &nbsp; &nbsp; CloseHandle<span class="br0">&#40;</span>f<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; newBase<span class="sy0">:=</span> <span class="kw2">true</span>;
&nbsp; &nbsp; <span class="kw1">end</span>;
&nbsp; <span class="kw1">end</span>;
<span class="kw1">end</span>;</div>
</div>
</pre>
<p>На этом статью заканчиваю. Надеюсь статья и программный код описал максимально понятно. Но замечу, что код требует оптимизации, так как был написан таким образом, чтобы был понятен читателю. Пример может быть расширен, в него можно добавить кучу дополнительных возможностей. Все это зависит от вашей фантазии. Все вопросы и замечания высказываем на <a href="/forum/">форуме</a>.</p>
<p><strong>Необходимые файлы:</strong><br />
- модуль для вычисления CRC32. <a href="http://depositfiles.com/files/zy2y8ho7y">Скачать</a></p>
<p><strong>Рабочий пример</strong> скачать <a href="http://depositfiles.com/files/8kp2p3qbo">здесь</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://zetblog.ru/programming/200902/%d0%b1%d0%b5%d0%b7%d0%be%d0%bf%d0%b0%d1%81%d0%bd%d0%be%d1%81%d1%82%d1%8c-%d0%b8%d0%bd%d1%81%d0%bf%d0%b5%d0%ba%d1%82%d0%be%d1%80-%d1%84%d0%b0%d0%b9%d0%bb%d0%be%d0%b2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>WinAPI: Взаимный контроль приложений.</title>
		<link>http://zetblog.ru/programming/200901/winapi-%d0%b2%d0%b7%d0%b0%d0%b8%d0%bc%d0%bd%d1%8b%d0%b9-%d0%ba%d0%be%d0%bd%d1%82%d1%80%d0%be%d0%bb%d1%8c-%d0%bf%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b9/</link>
		<comments>http://zetblog.ru/programming/200901/winapi-%d0%b2%d0%b7%d0%b0%d0%b8%d0%bc%d0%bd%d1%8b%d0%b9-%d0%ba%d0%be%d0%bd%d1%82%d1%80%d0%be%d0%bb%d1%8c-%d0%bf%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b9/#comments</comments>
		<pubDate>Fri, 23 Jan 2009 17:01:51 +0000</pubDate>
		<dc:creator>C0ffe1n</dc:creator>
				<category><![CDATA[Программирование]]></category>
		<category><![CDATA[системное]]></category>
		<category><![CDATA[Delphi]]></category>
		<category><![CDATA[WinAPI]]></category>

		<guid isPermaLink="false">http://zetblog.ru/?p=381</guid>
		<description><![CDATA[Иногда в своих проектах необходимо реализовать возможность контроля запущенных экземпляров программ или возможность взаимного контроля зависимых друг от друга программ. Для решения этой задачи нам понадобится получить список запущенных процессов. Как это делается можно прочитать здесь. А далее, после того как мы получим список процессов, достаточно проверить список на наличие в нем интересующего процесса, соответствующего [...]]]></description>
			<content:encoded><![CDATA[<p>Иногда в своих проектах необходимо реализовать возможность контроля запущенных экземпляров программ или возможность взаимного контроля зависимых друг от друга программ. Для решения этой задачи нам понадобится получить список запущенных процессов.<br />
<span id="more-381"></span><br />
Как это делается можно прочитать <a href="/?p=378">здесь</a>.</p>
<p>А далее, после того как мы получим список процессов, достаточно проверить список на наличие в нем интересующего процесса, соответствующего нашей программе. Если такового не оказалось, то необходимо нашу программу запустить заново.</p>
<p>Теперь посмотрим, как будет выглядеть листинг:</p>
<p><strong>Delphi</strong></p>
<pre>
<div class="codesnip-container" >
<div class="pascal codesnip" style="font-family:monospace;"><span class="co1">//глобальные переменные</span>
<span class="kw1">var</span>
&nbsp; &nbsp; &nbsp;lstprc<span class="sy0">:</span> TStrings;
&nbsp; &nbsp; &nbsp;i<span class="sy0">:</span><span class="kw4">integer</span>;
&nbsp; &nbsp; &nbsp;find<span class="sy0">:</span><span class="kw4">boolean</span>;
<span class="co1">//Получаем список процессов</span>
<span class="kw1">function</span> GetProcessList<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">:</span> TStrings;
<span class="kw1">var</span>
&nbsp; eP<span class="sy0">:</span> TProcessEntry32;
&nbsp; hP<span class="sy0">,</span> snap<span class="sy0">:</span> THandle; <span class="co1">//дескрипторы процесса и снимка</span>
&nbsp; hM<span class="sy0">:</span> hmodule; <span class="co1">//дескриптор модуля</span>
&nbsp; prcs<span class="sy0">:</span> <span class="kw4">array</span><span class="br0">&#91;</span>0..$FFF<span class="br0">&#93;</span> <span class="kw1">of</span> dword; <span class="co1">//массив для хранения</span>
<span class="co1">// дескрипторов процессов</span>
&nbsp; cP<span class="sy0">,</span> cM<span class="sy0">:</span> cardinal; <span class="co1">//количество процессов</span>
&nbsp; i<span class="sy0">:</span> <span class="kw4">integer</span>;
&nbsp; NameProc<span class="sy0">:</span> <span class="kw4">array</span><span class="br0">&#91;</span>0..<span class="me1">max_path</span><span class="br0">&#93;</span> <span class="kw1">of</span> <span class="kw4">char</span>; <span class="co1">//имя модуля</span>
&nbsp; lP<span class="sy0">:</span> TStrings;
<span class="kw1">begin</span>
&nbsp; lP<span class="sy0">:=</span>TStringList.<span class="me1">Create</span>;
&nbsp; lP.<span class="me1">Clear</span>;
<span class="co1">//проверяем версию винды</span>
&nbsp; <span class="kw1">if</span> Win32Platform <span class="sy0">=</span> VER_PLATFORM_WIN32_WINDOWS <span class="kw1">then</span>
&nbsp; <span class="kw1">begin</span> <span class="co1">//если это Win9x</span>
<span class="co1">//инициализируем переменные</span>
&nbsp; &nbsp; snap <span class="sy0">:=</span> CreateToolhelp32Snapshot<span class="br0">&#40;</span>th32cs_snapprocess<span class="sy0">,</span> 0<span class="br0">&#41;</span>;
&nbsp; &nbsp; <span class="kw1">if</span> <span class="kw4">integer</span><span class="br0">&#40;</span>snap<span class="br0">&#41;</span> <span class="sy0">=</span> <span class="sy0">-</span>1 <span class="kw1">then</span>
&nbsp; &nbsp; <span class="kw1">begin</span>
&nbsp; &nbsp; &nbsp; exit;
&nbsp; &nbsp; <span class="kw1">end</span>
&nbsp; &nbsp; <span class="kw1">else</span>
&nbsp; &nbsp; <span class="kw1">begin</span>
&nbsp; &nbsp; &nbsp; eP.<span class="me1">dwSize</span> <span class="sy0">:=</span> sizeof<span class="br0">&#40;</span>eP<span class="br0">&#41;</span>;
<span class="co1">//для Win9x получение списка процессов выполняется по</span>
<span class="co1">//аналогии с поиском файлов</span>
<span class="co1">//вызываем функцию для получения первого процесса</span>
&nbsp; &nbsp; &nbsp; <span class="kw1">if</span> Process32First<span class="br0">&#40;</span>snap<span class="sy0">,</span> eP<span class="br0">&#41;</span> <span class="kw1">then</span>
<span class="co1">//а далее в &nbsp;цикле пока еще есть процессы получаем следующий</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">repeat</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; lP.<span class="me1">Add</span><span class="br0">&#40;</span><span class="kw4">string</span><span class="br0">&#40;</span>eP.<span class="me1">szExeFile</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;<span class="co1">//получаем имя процесса</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">until</span> <span class="kw1">not</span> Process32Next<span class="br0">&#40;</span>snap<span class="sy0">,</span> eP<span class="br0">&#41;</span>;
&nbsp; &nbsp; <span class="kw1">end</span>;
&nbsp; <span class="kw1">end</span>
&nbsp; <span class="kw1">else</span>
&nbsp; <span class="kw1">begin</span> <span class="co1">//Если WinNT/2000/XP</span>
<span class="co1">//то в этом случае мы пользуемся Api-функцией перечисления</span>
<span class="co1">// запущенных процессов</span>
<span class="co1">//которая заполняет нам наши переменные</span>
&nbsp; &nbsp; <span class="kw1">if</span> <span class="kw1">not</span> EnumProcesses<span class="br0">&#40;</span>@prcs<span class="sy0">,</span> sizeof<span class="br0">&#40;</span>prcs<span class="br0">&#41;</span><span class="sy0">,</span> cP<span class="br0">&#41;</span> <span class="kw1">then</span>
&nbsp; &nbsp; <span class="kw1">begin</span>
&nbsp; &nbsp; &nbsp; exit;
&nbsp; &nbsp; <span class="kw1">end</span>;
<span class="co1">//и далее для каждого дескриптора процесса получаем о нем</span>
<span class="co1">// информацию</span>
&nbsp; &nbsp; <span class="kw1">for</span> i <span class="sy0">:=</span> 0 <span class="kw1">to</span> cP <span class="kw1">div</span> 4 <span class="sy0">-</span> 1 <span class="kw1">do</span>
&nbsp; &nbsp; <span class="kw1">begin</span>
&nbsp; &nbsp; &nbsp; hP <span class="sy0">:=</span> OpenProcess<span class="br0">&#40;</span>PROCESS_QUERY_INFORMATION <span class="kw1">or</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PROCESS_VM_READ<span class="sy0">,</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="kw2">false</span><span class="sy0">,</span> prcs<span class="br0">&#91;</span>i<span class="br0">&#93;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; <span class="kw1">if</span> hP &amp;gt; 0 <span class="kw1">then</span>
&nbsp; &nbsp; &nbsp; <span class="kw1">begin</span>
&nbsp; &nbsp; &nbsp; &nbsp; EnumProcessModules<span class="br0">&#40;</span>hP<span class="sy0">,</span> @hM<span class="sy0">,</span> 4<span class="sy0">,</span> cM<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; GetModuleFileNameEx<span class="br0">&#40;</span>hP<span class="sy0">,</span> hM<span class="sy0">,</span> NameProc<span class="sy0">,</span> sizeof<span class="br0">&#40;</span>NameProc<span class="br0">&#41;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; lP.<span class="me1">Add</span><span class="br0">&#40;</span>ExtractFileName<span class="br0">&#40;</span><span class="kw4">string</span><span class="br0">&#40;</span>NameProc<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>; <span class="co1">//если вы хотите</span>
<span class="co1">// &nbsp; &nbsp;получить только имена процессов</span>
<span class="co1">// &nbsp; &nbsp; &nbsp; &nbsp;lP.Add(string(NameProc)); //если вы хотите получить</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="co1">// имена процессов вместе c путем</span>
&nbsp; &nbsp; &nbsp; &nbsp; CloseHandle<span class="br0">&#40;</span>hP<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; <span class="kw1">end</span>;
&nbsp; &nbsp; <span class="kw1">end</span>;
&nbsp; <span class="kw1">end</span>;
&nbsp; GetProcessList<span class="sy0">:=</span>lP; <span class="co1">//возвращаем полученный список</span>
<span class="kw1">end</span>;
<span class="co1">//Основная процедура</span>
<span class="kw1">begin</span>
&nbsp; &nbsp;<span class="co1">//Сразу после запуска получаем список процессов</span>
&nbsp; lstprc<span class="sy0">:=</span>TStringList.<span class="me1">Create</span>;
&nbsp; lstprc.<span class="me1">Clear</span>;
&nbsp; lstprc<span class="sy0">:=</span>GetProcessList;
&nbsp; <span class="co1">//Теперь проверяем список на наличие интересующего</span>
<span class="co1">// нас процесса</span>
&nbsp; i<span class="sy0">:=</span><span class="nu0">0</span>;
&nbsp; find<span class="sy0">:=</span><span class="kw2">false</span>;
&nbsp; <span class="kw1">while</span> <span class="br0">&#40;</span>i &amp;lt;<span class="sy0">=</span> lstprc.<span class="me1">count</span><span class="sy0">-</span>1<span class="br0">&#41;</span> <span class="kw1">do</span>
&nbsp; <span class="kw1">begin</span>
&nbsp; &nbsp; &nbsp;<span class="kw1">if</span> lstprc.<span class="me1">Strings</span><span class="br0">&#91;</span>i<span class="br0">&#93;</span> <span class="sy0">=</span> <span class="st_h">'test.exe'</span> <span class="kw1">then</span>
&nbsp; &nbsp; &nbsp;<span class="kw1">begin</span>
&nbsp; &nbsp; &nbsp; &nbsp; find<span class="sy0">:=</span><span class="kw2">true</span>;
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">break</span>;
&nbsp; &nbsp; &nbsp;<span class="kw1">end</span>
&nbsp; &nbsp; &nbsp;<span class="kw1">else</span>
&nbsp; &nbsp; &nbsp; &nbsp; i<span class="sy0">:=</span>i<span class="sy0">+</span><span class="nu0">1</span>;
&nbsp; <span class="kw1">end</span>;
<span class="co1">//Если в списке процессов нашей программы</span>
<span class="co1">// не обнаружено, то мы ее запускаем</span>
&nbsp; <span class="kw1">if</span> <span class="kw1">not</span> find <span class="kw1">then</span>
&nbsp; &nbsp; &nbsp;WinExec<span class="br0">&#40;</span>PChar<span class="br0">&#40;</span><span class="st_h">'test.exe'</span><span class="br0">&#41;</span><span class="sy0">,</span>SW_SHOW<span class="br0">&#41;</span>;
<span class="kw1">end</span>;</div>
</div>
</pre>
<p>Вот и все! =)</p>
]]></content:encoded>
			<wfw:commentRss>http://zetblog.ru/programming/200901/winapi-%d0%b2%d0%b7%d0%b0%d0%b8%d0%bc%d0%bd%d1%8b%d0%b9-%d0%ba%d0%be%d0%bd%d1%82%d1%80%d0%be%d0%bb%d1%8c-%d0%bf%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b9/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Delphi: Получить список запущенных процессов.</title>
		<link>http://zetblog.ru/programming/200812/winapi-%d0%bf%d0%be%d0%bb%d1%83%d1%87%d0%b8%d1%82%d1%8c-%d1%81%d0%bf%d0%b8%d1%81%d0%be%d0%ba-%d0%b7%d0%b0%d0%bf%d1%83%d1%89%d0%b5%d0%bd%d0%bd%d1%8b%d1%85-%d0%bf%d1%80%d0%be%d1%86%d0%b5%d1%81%d1%81/</link>
		<comments>http://zetblog.ru/programming/200812/winapi-%d0%bf%d0%be%d0%bb%d1%83%d1%87%d0%b8%d1%82%d1%8c-%d1%81%d0%bf%d0%b8%d1%81%d0%be%d0%ba-%d0%b7%d0%b0%d0%bf%d1%83%d1%89%d0%b5%d0%bd%d0%bd%d1%8b%d1%85-%d0%bf%d1%80%d0%be%d1%86%d0%b5%d1%81%d1%81/#comments</comments>
		<pubDate>Fri, 26 Dec 2008 06:04:30 +0000</pubDate>
		<dc:creator>C0ffe1n</dc:creator>
				<category><![CDATA[Программирование]]></category>
		<category><![CDATA[системное]]></category>
		<category><![CDATA[Delphi]]></category>
		<category><![CDATA[WinAPI]]></category>

		<guid isPermaLink="false">http://zetblog.ru/?p=378</guid>
		<description><![CDATA[Я считаю, что данная тема довольно актуальна и для своих программ иногда приходится придумывать механизмы, которые, к примеру, не позволяли запускать одновременно несколько копий программ. Для реализации такого механизма достаточно описать в своем проекте функцию получения списка запущенных процессов и в зависимости от своих нужд работать с полученным списком. Ниже приведен пример программы которая выводит [...]]]></description>
			<content:encoded><![CDATA[<p>Я считаю, что данная тема довольно актуальна и для своих программ иногда приходится придумывать механизмы, которые, к примеру, не позволяли запускать одновременно несколько копий программ. Для реализации такого механизма достаточно описать в своем проекте функцию получения списка запущенных процессов и в зависимости от своих нужд работать с полученным списком.<br />
<span id="more-378"></span><br />
Ниже приведен пример программы которая выводит список процессов. Все комментарии смотрите в исходнике.</p>
<p><strong>Delphi</strong></p>
<pre>
<div class="codesnip-container" >
<div class="pascal codesnip" style="font-family:monospace;"><span class="kw1">unit</span> Unit1;
<span class="kw1">interface</span>
<span class="kw1">uses</span>
&nbsp; Windows<span class="sy0">,</span> Messages<span class="sy0">,</span> SysUtils<span class="sy0">,</span> Variants<span class="sy0">,</span> Classes<span class="sy0">,</span> Graphics<span class="sy0">,</span>
&nbsp;Controls<span class="sy0">,</span> Forms<span class="sy0">,</span> Dialogs<span class="sy0">,</span> StdCtrls<span class="sy0">,</span>PSAPI<span class="sy0">,</span> TlHelp32;
<span class="kw1">type</span>
&nbsp; TForm1 <span class="sy0">=</span> class<span class="br0">&#40;</span>TForm<span class="br0">&#41;</span>
&nbsp; &nbsp; Button1<span class="sy0">:</span> TButton;
&nbsp; &nbsp; Memo1<span class="sy0">:</span> TMemo;
&nbsp; &nbsp; Button2<span class="sy0">:</span> TButton;
&nbsp; &nbsp; <span class="kw1">procedure</span> Button1Click<span class="br0">&#40;</span>Sender<span class="sy0">:</span> TObject<span class="br0">&#41;</span>;
&nbsp; <span class="kw1">private</span>
&nbsp; &nbsp; <span class="coMULTI">{ Private declarations }</span>
&nbsp; <span class="kw1">public</span>
&nbsp; &nbsp; <span class="coMULTI">{ Public declarations }</span>
&nbsp; <span class="kw1">end</span>;
<span class="kw1">var</span>
&nbsp; Form1<span class="sy0">:</span> TForm1;
<span class="kw1">implementation</span>
<span class="coMULTI">{$R *.dfm}</span>

<span class="kw1">function</span> GetProcessList<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">:</span> TStrings;
<span class="kw1">var</span>
&nbsp; eP<span class="sy0">:</span> TProcessEntry32;
&nbsp; hP<span class="sy0">,</span> snap<span class="sy0">:</span> THandle; <span class="co1">//дескрипторы процесса и снимка</span>
&nbsp; hM<span class="sy0">:</span> hmodule; <span class="co1">//дескриптор модуля</span>
&nbsp; prcs<span class="sy0">:</span> <span class="kw4">array</span><span class="br0">&#91;</span>0..$FFF<span class="br0">&#93;</span> <span class="kw1">of</span> dword; <span class="co1">//массив для хранения</span>
<span class="co1">// дескрипторов процессов</span>
&nbsp; cP<span class="sy0">,</span> cM<span class="sy0">:</span> cardinal; <span class="co1">//количество процессов</span>
&nbsp; i<span class="sy0">:</span> <span class="kw4">integer</span>;
&nbsp; NameProc<span class="sy0">:</span> <span class="kw4">array</span><span class="br0">&#91;</span>0..<span class="me1">max_path</span><span class="br0">&#93;</span> <span class="kw1">of</span> <span class="kw4">char</span>; <span class="co1">//имя модуля</span>
&nbsp; lP<span class="sy0">:</span> TStrings;
<span class="kw1">begin</span>
&nbsp; lP<span class="sy0">:=</span>TStringList.<span class="me1">Create</span>;
&nbsp; lP.<span class="me1">Clear</span>;
<span class="co1">//проверяем версию винды</span>
&nbsp; <span class="kw1">if</span> Win32Platform <span class="sy0">=</span> VER_PLATFORM_WIN32_WINDOWS <span class="kw1">then</span>
&nbsp; <span class="kw1">begin</span> <span class="co1">//если это Win9x</span>
<span class="co1">//инициализируем переменные</span>
&nbsp; &nbsp; snap <span class="sy0">:=</span> CreateToolhelp32Snapshot<span class="br0">&#40;</span>th32cs_snapprocess<span class="sy0">,</span> 0<span class="br0">&#41;</span>;
&nbsp; &nbsp; <span class="kw1">if</span> <span class="kw4">integer</span><span class="br0">&#40;</span>snap<span class="br0">&#41;</span> <span class="sy0">=</span> <span class="sy0">-</span>1 <span class="kw1">then</span>
&nbsp; &nbsp; <span class="kw1">begin</span>
&nbsp; &nbsp; &nbsp; exit;
&nbsp; &nbsp; <span class="kw1">end</span>
&nbsp; &nbsp; <span class="kw1">else</span>
&nbsp; &nbsp; <span class="kw1">begin</span>
&nbsp; &nbsp; &nbsp; eP.<span class="me1">dwSize</span> <span class="sy0">:=</span> sizeof<span class="br0">&#40;</span>eP<span class="br0">&#41;</span>;
<span class="co1">//для Win9x получение списка процессов выполняется по</span>
<span class="co1">//аналогии с поиском файлов</span>
<span class="co1">//вызываем функцию для получения первого процесса</span>
&nbsp; &nbsp; &nbsp; <span class="kw1">if</span> Process32First<span class="br0">&#40;</span>snap<span class="sy0">,</span> eP<span class="br0">&#41;</span> <span class="kw1">then</span>
<span class="co1">//а далее в &nbsp;цикле пока еще есть процессы получаем следующий</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">repeat</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; lP.<span class="me1">Add</span><span class="br0">&#40;</span><span class="kw4">string</span><span class="br0">&#40;</span>eP.<span class="me1">szExeFile</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;<span class="co1">//получаем имя процесса</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">until</span> <span class="kw1">not</span> Process32Next<span class="br0">&#40;</span>snap<span class="sy0">,</span> eP<span class="br0">&#41;</span>;
&nbsp; &nbsp; <span class="kw1">end</span>;
&nbsp; <span class="kw1">end</span>
&nbsp; <span class="kw1">else</span>
&nbsp; <span class="kw1">begin</span> <span class="co1">//Если WinNT/2000/XP</span>
<span class="co1">//то в этом случае мы пользуемся Api-функцией перечисления</span>
<span class="co1">// запущенных процессов</span>
<span class="co1">//которая заполняет нам наши переменные</span>
&nbsp; &nbsp; <span class="kw1">if</span> <span class="kw1">not</span> EnumProcesses<span class="br0">&#40;</span>@prcs<span class="sy0">,</span> sizeof<span class="br0">&#40;</span>prcs<span class="br0">&#41;</span><span class="sy0">,</span> cP<span class="br0">&#41;</span> <span class="kw1">then</span>
&nbsp; &nbsp; <span class="kw1">begin</span>
&nbsp; &nbsp; &nbsp; exit;
&nbsp; &nbsp; <span class="kw1">end</span>;
<span class="co1">//и далее для каждого дескриптора процесса получаем о нем</span>
<span class="co1">// информацию</span>
&nbsp; &nbsp; <span class="kw1">for</span> i <span class="sy0">:=</span> 0 <span class="kw1">to</span> cP <span class="kw1">div</span> 4 <span class="sy0">-</span> 1 <span class="kw1">do</span>
&nbsp; &nbsp; <span class="kw1">begin</span>
&nbsp; &nbsp; &nbsp; hP <span class="sy0">:=</span> OpenProcess<span class="br0">&#40;</span>PROCESS_QUERY_INFORMATION <span class="kw1">or</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PROCESS_VM_READ<span class="sy0">,</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="kw2">false</span><span class="sy0">,</span> prcs<span class="br0">&#91;</span>i<span class="br0">&#93;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; <span class="kw1">if</span> hP &amp;gt; 0 <span class="kw1">then</span>
&nbsp; &nbsp; &nbsp; <span class="kw1">begin</span>
&nbsp; &nbsp; &nbsp; &nbsp; EnumProcessModules<span class="br0">&#40;</span>hP<span class="sy0">,</span> @hM<span class="sy0">,</span> 4<span class="sy0">,</span> cM<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; GetModuleFileNameEx<span class="br0">&#40;</span>hP<span class="sy0">,</span> hM<span class="sy0">,</span> NameProc<span class="sy0">,</span> sizeof<span class="br0">&#40;</span>NameProc<span class="br0">&#41;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; lP.<span class="me1">Add</span><span class="br0">&#40;</span>ExtractFileName<span class="br0">&#40;</span><span class="kw4">string</span><span class="br0">&#40;</span>NameProc<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>; <span class="co1">//если вы хотите</span>
<span class="co1">// &nbsp; &nbsp;получить только имена процессов</span>
<span class="co1">// &nbsp; &nbsp; &nbsp; &nbsp;lP.Add(string(NameProc)); //если вы хотите получить</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="co1">// имена процессов вместе c путем</span>
&nbsp; &nbsp; &nbsp; &nbsp; CloseHandle<span class="br0">&#40;</span>hP<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; <span class="kw1">end</span>;
&nbsp; &nbsp; <span class="kw1">end</span>;
&nbsp; <span class="kw1">end</span>;
&nbsp; GetProcessList<span class="sy0">:=</span>lP; <span class="co1">//возвращаем полученный список</span>
<span class="kw1">end</span>;
<span class="kw1">procedure</span> TForm1.<span class="me1">Button1Click</span><span class="br0">&#40;</span>Sender<span class="sy0">:</span> TObject<span class="br0">&#41;</span>;
<span class="kw1">begin</span>
&nbsp; memo1.<span class="me1">Lines</span><span class="sy0">:=</span>GetProcessList;
<span class="kw1">end</span>;
<span class="kw1">end</span>.</div>
</div>
</pre>
]]></content:encoded>
			<wfw:commentRss>http://zetblog.ru/programming/200812/winapi-%d0%bf%d0%be%d0%bb%d1%83%d1%87%d0%b8%d1%82%d1%8c-%d1%81%d0%bf%d0%b8%d1%81%d0%be%d0%ba-%d0%b7%d0%b0%d0%bf%d1%83%d1%89%d0%b5%d0%bd%d0%bd%d1%8b%d1%85-%d0%bf%d1%80%d0%be%d1%86%d0%b5%d1%81%d1%81/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>WinAPI: Определение типа носителя и его серийного номера.</title>
		<link>http://zetblog.ru/programming/200812/%d0%be%d0%bf%d1%80%d0%b5%d0%b4%d0%b5%d0%bb%d0%b5%d0%bd%d0%b8%d0%b5-%d1%82%d0%b8%d0%bf%d0%b0-%d0%bd%d0%be%d1%81%d0%b8%d1%82%d0%b5%d0%bb%d1%8f-%d0%b8-%d0%b5%d0%b3%d0%be-%d1%81%d0%b5%d1%80%d0%b8%d0%b9/</link>
		<comments>http://zetblog.ru/programming/200812/%d0%be%d0%bf%d1%80%d0%b5%d0%b4%d0%b5%d0%bb%d0%b5%d0%bd%d0%b8%d0%b5-%d1%82%d0%b8%d0%bf%d0%b0-%d0%bd%d0%be%d1%81%d0%b8%d1%82%d0%b5%d0%bb%d1%8f-%d0%b8-%d0%b5%d0%b3%d0%be-%d1%81%d0%b5%d1%80%d0%b8%d0%b9/#comments</comments>
		<pubDate>Wed, 24 Dec 2008 21:36:01 +0000</pubDate>
		<dc:creator>C0ffe1n</dc:creator>
				<category><![CDATA[Программирование]]></category>
		<category><![CDATA[системное]]></category>
		<category><![CDATA[C/C++]]></category>
		<category><![CDATA[Delphi]]></category>
		<category><![CDATA[WinAPI]]></category>

		<guid isPermaLink="false">http://zetblog.ru/?p=347</guid>
		<description><![CDATA[Иногда в программах необходимо использовать возможность проверки типа носителя или его серийный номер. Причины могут быть разными &#8212; от банального контроля устройств в системе, до средств защит использующих привязку к железу. Сейчас я вам покажу как с помощью API реализовать эту простую задачу. Нам понадобится всего 2 API &#8212; функции: GetDriveType &#8212; определяет и возвращает [...]]]></description>
			<content:encoded><![CDATA[<p>Иногда в программах необходимо использовать возможность проверки типа носителя или его серийный номер. Причины могут быть разными &#8212; от банального контроля устройств в системе, до средств защит использующих привязку к железу. Сейчас я вам покажу как с помощью API реализовать эту простую задачу.<br />
<span id="more-347"></span></p>
<p>Нам понадобится всего 2 API &#8212; функции:</p>
<ul>
<li>GetDriveType &#8212; определяет и возвращает тип носителя;</li>
<li>GetVolumeInformation &#8212; определяет информацию о носителе,  среди которой содержится серийный номер.</li>
</ul>
<p>Рассмотрим описание этих функций для С++ и Delphi. Первой будет функция GetDriveType, она очень простая и использует всего один параметр &#8212; указатель на том. Например &#171;c:\&#187;,&#187;a:\&#187; и т.д. Функция возвращает одно из следующих значений:</p>
<p><strong>DRIVE_UNKNOWN &#8212; 0</strong> : диск неопределен/не существует</p>
<p><strong>DRIVE_NO_ROOT_DIR &#8212; 1</strong> : неверный путь/ путь не указывает на том</p>
<p><strong>DRIVE_REMOVABLE</strong> &#8212; <strong>2</strong> : тип устройства определяется как съемный (дискета, флешка и т.д.)</p>
<p><strong>DRIVE_FIXED</strong> &#8212; <strong>3</strong> : тип устройства &#8212; фиксированный диск (жесткий диск)</p>
<p><strong>DRIVE_REMOTE </strong> &#8212; <strong>4 </strong>: тип устройства &#8212; удаленный(сетевой) диск</p>
<p><strong>DRIVE_CDROM</strong> &#8212; <strong>5</strong> : это устройство CD-ROM</p>
<p><strong>DRIVE_RAMDISK</strong> &#8212; <strong>6 </strong>:<strong> </strong> виртуальный диск, созданный в оперативной памяти</p>
<pre><strong>C/C++</strong>
<div class="codesnip-container" >
<div class="cpp codesnip" style="font-family:monospace;">UINT WINAPI GetDriveType<span class="br0">&#40;</span>
&nbsp; &nbsp; &nbsp; LPCTSTR lpRootPathName <span class="co1">//путь к диску</span>
<span class="br0">&#41;</span><span class="sy4">;</span></div>
</div>
</pre>
<pre><strong>Delphi</strong>
<div class="codesnip-container" >
<div class="pascal codesnip" style="font-family:monospace;"><span class="kw1">function</span> GetDriveType<span class="br0">&#40;</span>
&nbsp; &nbsp; &nbsp; lpRootPathName<span class="sy0">:</span> PChar <span class="co1">//путь к диску</span>
<span class="br0">&#41;</span><span class="sy0">:</span> UINT; <span class="kw1">stdcall</span>;</div>
</div>
</pre>
<p><strong>Замечание:</strong> Если в качестве параметра указать для С/С++  <strong>NULL</strong>, а для Delphi &#8212; <strong>nil,</strong> то тип устройства будет определяться для текущего диска (с которого была запущена программа).</p>
<p>А теперь взглянем на функцию GetVolumeInformation. Тоже достаточно простая функция, однако использует параметров значительно больше.</p>
<pre><strong>C/C++</strong>
<div class="codesnip-container" >
<div class="cpp codesnip" style="font-family:monospace;">BOOL WINAPI GetVolumeInformation<span class="br0">&#40;</span>
&nbsp; &nbsp; &nbsp; LPCTSTR lpRootPathName, &nbsp; &nbsp;<span class="co1">//путь к сетевому или локальному</span>
&nbsp; &nbsp; &nbsp; <span class="co1">// тому (пример: &quot;\\MyServer\MyShare\&quot; или &quot;C:\&quot;.</span>
&nbsp; &nbsp; &nbsp; LPTSTR lpVolumeNameBuffer, <span class="co1">//буфер - в котором будет храниться</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// имя тома</span>
&nbsp; &nbsp; &nbsp; DWORD nVolumeNameSize, &nbsp; &nbsp; <span class="co1">//размер буфера</span>
&nbsp; &nbsp; &nbsp; LPDWORD lpVolumeSerialNumber, <span class="co1">//серийный номер тома</span>
&nbsp; &nbsp; &nbsp; LPDWORD lpMaximumComponentLength, <span class="co1">//размер тома</span>
&nbsp; &nbsp; &nbsp; LPDWORD lpFileSystemFlags, <span class="co1">//тип файловой системы</span>
&nbsp; &nbsp; &nbsp; LPTSTR lpFileSystemNameBuffer, <span class="co1">//название файловой системы</span>
&nbsp; &nbsp; &nbsp; DWORD nFileSystemNameSize <span class="co1">//размер буфера под название ФС</span>
<span class="br0">&#41;</span><span class="sy4">;</span></div>
</div>
</pre>
<pre><strong>Delphi</strong>
<div class="codesnip-container" >
<div class="pascal codesnip" style="font-family:monospace;"><span class="kw1">function</span> GetVolumeInformation<span class="br0">&#40;</span>
&nbsp; &nbsp; &nbsp; lpRootPathName<span class="sy0">:</span> PChar; &nbsp; &nbsp;<span class="co1">//путь к сетевому или локальному</span>
&nbsp; &nbsp; &nbsp;  <span class="co1">//тому (пример: &quot;\\MyServer\MyShare\&quot; или &quot;C:\&quot;.</span>
&nbsp; &nbsp; &nbsp; lpVolumeNameBuffer<span class="sy0">:</span> PChar; <span class="co1">//буфер - в котором будет храниться</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="co1">// &nbsp; имя тома</span>
&nbsp; &nbsp; &nbsp; nVolumeNameSize<span class="sy0">:</span> DWORD; &nbsp; &nbsp; <span class="co1">//размер буфера</span>
&nbsp; &nbsp; &nbsp; lpVolumeSerialNumber<span class="sy0">:</span> PDWORD; <span class="co1">//серийный номер тома</span>
&nbsp; &nbsp; &nbsp; <span class="kw1">var</span> lpMaximumComponentLength<span class="sy0">,</span> lpFileSystemFlags<span class="sy0">:</span> DWORD; <span class="co1">//размер</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// тома и тип файловой системы</span>
&nbsp; &nbsp; &nbsp; lpFileSystemNameBuffer<span class="sy0">:</span> PChar; <span class="co1">//название файловой системы</span>
&nbsp; &nbsp; &nbsp; nFileSystemNameSize<span class="sy0">:</span> DWORD <span class="co1">//размер буфера под название ФС</span>
<span class="br0">&#41;</span><span class="sy0">:</span> BOOL; <span class="kw1">stdcall</span>;</div>
</div>
</pre>
<p><strong>Замечание:</strong> Если в качестве первого параметра указать для С/С++  <strong>NULL</strong>, а для Delphi &#8212; <strong>nil</strong>, то функция будет выполняется для текущего диска (с которого была запущена программа).<br />
Ну а теперь, собственно, для пущего интересу приведу пример как привязать программу к устройству. В данном примере будем привязывать программу к флешке. Смотрим пример:</p>
<pre><strong>C/C++</strong>
<div class="codesnip-container" >
<div class="cpp codesnip" style="font-family:monospace;"><span class="co2">#include</span>
<span class="co2">#include</span>
<span class="co2">#include</span>
<span class="co2">#include</span>
<span class="kw2">using</span> <span class="kw2">namespace</span> std<span class="sy4">;</span>

<span class="kw4">int</span> main<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// Получаем тип носителя с которого запущена программа</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">unsigned</span> <span class="kw4">int</span> drive_type <span class="sy1">=</span> GetDriveType<span class="br0">&#40;</span> <span class="kw2">NULL</span> <span class="br0">&#41;</span><span class="sy4">;</span>

&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">char</span> VolumeNameBuffer<span class="br0">&#91;</span>100<span class="br0">&#93;</span><span class="sy4">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">char</span> FileSystemNameBuffer<span class="br0">&#91;</span>100<span class="br0">&#93;</span><span class="sy4">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; DWORD sz,fs<span class="sy4">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">unsigned</span> <span class="kw4">long</span> drive_sn<span class="sy4">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; GetVolumeInformationA<span class="br0">&#40;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">NULL</span>,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; VolumeNameBuffer,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 100,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sy3">&amp;</span>amp<span class="sy4">;</span>drive_sn,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sz,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fs,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; FileSystemNameBuffer,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 100
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#41;</span><span class="sy4">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">cout</span> <span class="sy3">&amp;</span>lt<span class="sy4">;</span><span class="sy3">&amp;</span>lt<span class="sy4">;</span> <span class="st0">&quot;Volume serial number:<span class="es1">\t</span>&quot;</span><span class="sy4">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span>drive_sn <span class="sy1">==</span> <span class="nu0">1018821877</span><span class="br0">&#41;</span> &nbsp; &nbsp; <span class="co1">//сравниваем серийный номер</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">cout</span> <span class="sy3">&amp;</span>lt<span class="sy4">;</span><span class="sy3">&amp;</span>lt<span class="sy4">;</span> <span class="st0">&quot;correct&quot;</span> <span class="sy3">&amp;</span>lt<span class="sy4">;</span><span class="sy3">&amp;</span>lt<span class="sy4">;</span> endl<span class="sy4">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">else</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">cout</span> <span class="sy3">&amp;</span>lt<span class="sy4">;</span><span class="sy3">&amp;</span>lt<span class="sy4">;</span> <span class="st0">&quot;invalid&quot;</span> <span class="sy3">&amp;</span>lt<span class="sy4">;</span><span class="sy3">&amp;</span>lt<span class="sy4">;</span> endl<span class="sy4">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">cout</span> <span class="sy3">&amp;</span>lt<span class="sy4">;</span><span class="sy3">&amp;</span>lt<span class="sy4">;</span> <span class="st0">&quot;Drive type:<span class="es1">\t</span>&quot;</span><span class="sy4">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span>drive_type <span class="sy1">==</span> DRIVE_REMOVABLE<span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">cout</span> <span class="sy3">&amp;</span>lt<span class="sy4">;</span><span class="sy3">&amp;</span>lt<span class="sy4">;</span> <span class="st0">&quot;correct&quot;</span> <span class="sy3">&amp;</span>lt<span class="sy4">;</span><span class="sy3">&amp;</span>lt<span class="sy4">;</span> endl<span class="sy4">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">else</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">cout</span> <span class="sy3">&amp;</span>lt<span class="sy4">;</span><span class="sy3">&amp;</span>lt<span class="sy4">;</span> <span class="st0">&quot;invalid&quot;</span> <span class="sy3">&amp;</span>lt<span class="sy4">;</span><span class="sy3">&amp;</span>lt<span class="sy4">;</span> endl<span class="sy4">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; getch<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy4">;</span>
<span class="br0">&#125;</span></div>
</div>
</pre>
<pre><strong>Delphi</strong>
<div class="codesnip-container" >
<div class="pascal codesnip" style="font-family:monospace;"><span class="kw1">program</span> Project1;

<span class="coMULTI">{$APPTYPE CONSOLE}</span>

<span class="kw1">uses</span>
&nbsp; SysUtils<span class="sy0">,</span>windows;

<span class="kw1">var</span>
&nbsp;SerialNum<span class="sy0">,</span>dtyp<span class="sy0">:</span>DWORD;
&nbsp;a<span class="sy0">,</span>b<span class="sy0">:</span>DWORD;
&nbsp;Buffer<span class="sy0">,</span>disk <span class="sy0">:</span><span class="kw4">Array</span><span class="br0">&#91;</span>0..255<span class="br0">&#93;</span><span class="kw1">of</span> <span class="kw4">char</span>;
<span class="kw1">begin</span>
&nbsp; dtyp<span class="sy0">:=</span>GetDriveType<span class="br0">&#40;</span><span class="kw2">nil</span><span class="br0">&#41;</span>;
&nbsp; <span class="kw1">if</span> dtyp <span class="sy0">=</span> DRIVE_REMOVABLE <span class="kw1">then</span>
&nbsp; &nbsp; <span class="kw3">writeln</span><span class="br0">&#40;</span><span class="st_h">'Disk(type): Yes'</span><span class="br0">&#41;</span>
&nbsp; <span class="kw1">else</span>
&nbsp; &nbsp; <span class="kw3">writeln</span><span class="br0">&#40;</span><span class="st_h">'Disk(type): No'</span><span class="br0">&#41;</span>;
&nbsp; GetVolumeInformation<span class="br0">&#40;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">nil</span><span class="sy0">,</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Buffer<span class="sy0">,</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sizeof<span class="br0">&#40;</span>Buffer<span class="br0">&#41;</span><span class="sy0">,</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; @SerialNum<span class="sy0">,</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; a<span class="sy0">,</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; b<span class="sy0">,</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">nil</span><span class="sy0">,</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0<span class="br0">&#41;</span>;
&nbsp; <span class="kw1">if</span> SerialNum <span class="sy0">=</span> 1018821877 <span class="kw1">then</span> <span class="co1">//сравниваем серийный номер</span>
&nbsp; &nbsp; <span class="kw3">writeln</span><span class="br0">&#40;</span><span class="st_h">'S\N: Yes'</span><span class="br0">&#41;</span>
&nbsp; <span class="kw1">else</span>
&nbsp; &nbsp; <span class="kw3">writeln</span><span class="br0">&#40;</span><span class="st_h">'S\N: No'</span><span class="br0">&#41;</span>;
&nbsp; <span class="kw3">readln</span>;
<span class="kw1">end</span>.</div>
</div>
</pre>
<p><strong>Замечание:</strong> Может возникнуть вопрос, а как узнать серийник диска, чтобы знать, с чем сравнивать? Очень просто, для этого пишем тестовую прогу, в которой пишем следующий код:</p>
<pre><strong>C/C++</strong>
<div class="codesnip-container" >
<div class="cpp codesnip" style="font-family:monospace;">...
&nbsp; &nbsp; <span class="me1">GetVolumeInformationA</span><span class="br0">&#40;</span><span class="kw2">NULL</span>, VolumeNameBuffer,100,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="sy3">&amp;</span>amp<span class="sy4">;</span>drive_sn,sz,fs,FileSystemNameBuffer,100<span class="br0">&#41;</span><span class="sy4">;</span>
...</div>
</div>
</pre>
<p><strong>Delphi</strong></p>
<pre>
<div class="codesnip-container" >
<div class="pascal codesnip" style="font-family:monospace;">...
&nbsp; &nbsp; &nbsp;<span class="me1">GetVolumeInformation</span><span class="br0">&#40;</span><span class="kw2">nil</span><span class="sy0">,</span>Buffer<span class="sy0">,</span>sizeof<span class="br0">&#40;</span>Buffer<span class="br0">&#41;</span><span class="sy0">,</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;@SerialNum<span class="sy0">,</span> a<span class="sy0">,</span>b<span class="sy0">,</span> <span class="kw2">nil</span><span class="sy0">,</span> 0<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp;<span class="kw3">writeln</span><span class="br0">&#40;</span><span class="st_h">'S/N drive: '</span><span class="sy0">,</span>SerialNum<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp;<span class="kw3">readln</span>;
...</div>
</div>
</pre>
<p><strong>Рекомендуемые статьи для прочтения:</strong><br />
<a href="/?p=534">WinAPI: Смена серийного номера тома.</a></p>
]]></content:encoded>
			<wfw:commentRss>http://zetblog.ru/programming/200812/%d0%be%d0%bf%d1%80%d0%b5%d0%b4%d0%b5%d0%bb%d0%b5%d0%bd%d0%b8%d0%b5-%d1%82%d0%b8%d0%bf%d0%b0-%d0%bd%d0%be%d1%81%d0%b8%d1%82%d0%b5%d0%bb%d1%8f-%d0%b8-%d0%b5%d0%b3%d0%be-%d1%81%d0%b5%d1%80%d0%b8%d0%b9/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Криптография: Шифр Вернама и его программная реализация.</title>
		<link>http://zetblog.ru/programming/200812/%d0%ba%d1%80%d0%b8%d0%bf%d1%82%d0%be%d0%b3%d1%80%d0%b0%d1%84%d0%b8%d1%8f-%d1%88%d0%b8%d1%84%d1%80-%d0%b2%d0%b5%d1%80%d0%bd%d0%b0%d0%bc%d0%b0/</link>
		<comments>http://zetblog.ru/programming/200812/%d0%ba%d1%80%d0%b8%d0%bf%d1%82%d0%be%d0%b3%d1%80%d0%b0%d1%84%d0%b8%d1%8f-%d1%88%d0%b8%d1%84%d1%80-%d0%b2%d0%b5%d1%80%d0%bd%d0%b0%d0%bc%d0%b0/#comments</comments>
		<pubDate>Wed, 03 Dec 2008 18:23:16 +0000</pubDate>
		<dc:creator>C0ffe1n</dc:creator>
				<category><![CDATA[криптография]]></category>
		<category><![CDATA[Программирование]]></category>
		<category><![CDATA[C/C++]]></category>
		<category><![CDATA[Delphi]]></category>
		<category><![CDATA[шифры]]></category>

		<guid isPermaLink="false">http://zetblog.ru/?p=148</guid>
		<description><![CDATA[В криптографии шифр Вернама известен также как «схема одноразовых блокнотов». Решение является системой симметричного шифрования, которая была изобретена в 1917 году сотрудниками AT&#38;T Мейджором Джозефом Моборном и Гильбертом Вернамом. В 1949 годах была опубликована работа Клода Шеннона, где Шеннон доказал абсолютную стойкость шифра Вернама. В этой работе Шеннон показал, что не существует других шифров с [...]]]></description>
			<content:encoded><![CDATA[<p>В криптографии <strong>шифр Вернама</strong> известен также как <strong>«схема одноразовых блокнотов»</strong>. Решение является системой симметричного шифрования, которая была изобретена в 1917 году сотрудниками AT&amp;T Мейджором Джозефом Моборном и Гильбертом Вернамом.</p>
<p>В 1949 годах была опубликована работа Клода Шеннона, где Шеннон доказал абсолютную стойкость шифра Вернама. В этой работе Шеннон показал, что не существует других шифров с подобными свойствами и его  выводом стало следующее утверждение: <strong>шифр Вернама – самая безопасная криптосистема из всех имеющихся</strong>.<br />
<span id="more-148"></span></p>
<p>Однако, следует заметить, что для того, чтобы шифр действительно был стойким, необходимо выполнение следующих трех правил:</p>
<ol>
<li>Ключ для шифрования выбирается случайным образом.</li>
<li>Длина ключа должна быть равна длине открытого текста.</li>
<li>Ключ должен использоваться <strong>ТОЛЬКО</strong> один раз.</li>
</ol>
<p>А теперь поподробней о самом шифре и процессе шифрования. Так как этот шифр был придуман для компьютерных систем, то следует заметить, что базируется он на двоичной арифметике. Надеюсь что вы знакомы с ней ;).  Основным объектом рассмотрения в данном методе шифрования является логическая операция <strong>XOR</strong> (взаимоисключающее ИЛИ). Таким образом, так как у нас двоичная арифметика, то все операции будут осуществляется над нулем (0) и единицей (1). Логическая операция <strong>XOR</strong>, в отличие от операции <strong>OR</strong>, при логическом сравнении 0 и 1 дает 1,  при сравнении 1 с 1 дает 0, а при 0 с 0 дает 0. Следовательно, если мы выполним операцию <strong>XOR</strong> над числами 10110 и 11010, то получим: 10110 <strong>xor </strong>11010 = 01100. Надеюсь что принцип работы операции <strong>XOR</strong> понятен.</p>
<p>Далее,  так как шифр работает с двоичной системой исчисления, необходимо понимать, что буквы &#8212; это всего лишь некоторая интерпретация числа, то есть число является кодом символа некоторой таблицы кодировок. К примеру, наиболее популярные таблицы кодировок это: ANSI, ASCII и UTF(unicode). Естественно, что в каждой таблице один и тот же символ может иметь разный код, поэтому, во избежании путаницы, имейте это ввиду и используйте одну и ту же кодировку при шифровании и дешифровании.  Замечу, что использовать можно и свою (придуманную) кодировку. Кроме того, данный шифр может использоваться не только на компьютерах. Его можно применить и к тексту написанному на бумаге. Только перед применением надо сделать некие преобразования.</p>
<p>Таким образом, перед тем, как осуществить шифрование, необходимо перевести все символы в их однозначную числовую интерпретацию. Если Вы решили применить шифр в компьютерных системах, то для вас уже существуют соответствующие кодировки и язык программирования, выбранный Вами, скорее всего поддерживает явное или неявное преобразование. И вам остается только произвести над каждой парой операцию <strong>XOR</strong>. В различных языках это операция определяется по разному, приведу пример: для pasсal/Delphi/Assembler &#8212; <strong>xor</strong>, C/C++ &#8212; <strong>^</strong>.  Однако, если же Вы  решили применить шифр Вернама к письменному тексту, то, к примеру, дайте каждой букве используемого вами алфавита, соответствующий ей порядковый номер в двоичной системе исчисления. Например, если вы используете русский алфавит (без учета буквы Ё) то это будет выглядеть так: а -&gt; 00000, б -&gt; 00001, в -&gt; 00010, г -&gt; 00011, &#8230; я -&gt; 111111. Тем самым мы определили свою таблицу кодировки. После этого, написав сообщение и придумав ключ, преобразуйте каждый символ в их числовое значение, соответствующее вашей таблице кодировки, и после этого осуществляйте операцию <strong>XOR</strong> над каждой соответствующей парой. Так как данный метод шифрования является симметричным, следовательно, применив операцию <strong>XOR </strong> к каждой паре символов шифр-текста (шифрограммы) и ключа, мы получим открытый текст.</p>
<p><strong>Программная реализация шифра Вернама.</strong></p>
<p>На основе изученного материала я покажу как реализовать шифр Вернам на С/С++ и pascal/Delphi. Программу целиком писать нет надобности, поэтому будем рассматривать блочную структуру, для того, чтобы каждый мог без особого труда заточить ее под свои надобности. А теперь от слов к делу ;).</p>
<p>Допустим, что у нас есть строка или массив символов &#8212; oStr. Это будет открытый текст, который надо зашифровать. Теперь нам надо определить случайный ключ длиной равной длине открытого текста. Для простоты понимания, мы воспользуемся стандартной функцией генерации случайных чисел: random для pascal/Delphi и rand для C/C++. Но замечу сразу что это не лучший вариант в случае, если вы хотите реализовать действительно стойкий шифр. Данный пример выбран из соображения простоты. Теперь покажем как это будет выглядеть в исходном коде:</p>
<pre><strong>pascal/Delphi</strong>
<div class="codesnip-container" >
<div class="pascal codesnip" style="font-family:monospace;"><span class="kw1">var</span>
&nbsp; oStr<span class="sy0">,</span> key<span class="sy0">:</span><span class="kw4">string</span>;
&nbsp; i<span class="sy0">:</span><span class="kw4">integer</span>;
<span class="kw1">begin</span>
&nbsp; oStr<span class="sy0">:=</span><span class="st_h">'Holo word!'</span>; &nbsp;<span class="co1">//определяем открытый текст</span>
&nbsp; randomize; <span class="co1">//Необходимая функция для функции random, чтобы последняя каждый раз выдавала случайные значения</span>
<span class="co1">//генерируем случайный ключ длиной равной длине открытого текста</span>
&nbsp; <span class="kw1">for</span> i<span class="sy0">:=</span>1 <span class="kw1">to</span> length<span class="br0">&#40;</span>oStr<span class="br0">&#41;</span> <span class="kw1">do</span>
&nbsp; &nbsp; key<span class="br0">&#91;</span>i<span class="br0">&#93;</span><span class="sy0">:=</span><span class="kw3">Chr</span><span class="br0">&#40;</span>random<span class="br0">&#40;</span>255<span class="br0">&#41;</span><span class="br0">&#41;</span>; <span class="co1">//генерируем случайное число из диапозона от 0 до 255 и полученое число переводим в символ;</span>
<span class="kw1">end</span>;</div>
</div>

<strong>C/C++</strong>
<div class="codesnip-container" >
<div class="cpp codesnip" style="font-family:monospace;"><span class="kw4">int</span> i,len<span class="sy4">;</span> <span class="co1">//Определяем необходимые переменные</span>
&nbsp; len <span class="sy1">=</span> <span class="kw3">strlen</span><span class="br0">&#40;</span><span class="st0">&quot;Holo word!&quot;</span><span class="br0">&#41;</span><span class="sy4">;</span><span class="co1">// определяем длину строки открытого текста</span>
&nbsp; <span class="kw4">char</span> <span class="sy2">*</span>oStr <span class="sy1">=</span> <span class="kw3">new</span> <span class="kw4">char</span><span class="br0">&#91;</span>len<span class="br0">&#93;</span><span class="sy4">;</span> <span class="co1">//объявляем динамический массив указанной длины для открытого текста</span>
&nbsp; <span class="kw4">char</span> <span class="sy2">*</span>key <span class="sy1">=</span> <span class="kw3">new</span> <span class="kw4">char</span><span class="br0">&#91;</span>len<span class="br0">&#93;</span><span class="sy4">;</span> &nbsp;<span class="co1">//точно такой же массив объявляем для ключа</span>
&nbsp; oStr<span class="sy1">=</span><span class="st0">&quot;Holo word!&quot;</span><span class="sy4">;</span> &nbsp; <span class="co1">//помещаем в массив открытый текст</span>
<span class="co1">// определяем ключ случайным образом</span>
&nbsp; <span class="kw1">for</span><span class="br0">&#40;</span>i <span class="sy1">=</span> <span class="nu0">0</span><span class="sy4">;</span> i <span class="sy3">&amp;</span>lt<span class="sy4">;</span> len<span class="sy4">;</span> i<span class="sy2">++</span><span class="br0">&#41;</span>
&nbsp; &nbsp; key<span class="br0">&#91;</span>i<span class="br0">&#93;</span><span class="sy1">=</span><span class="br0">&#40;</span><span class="kw4">char</span><span class="br0">&#41;</span><span class="kw3">rand</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy2">%</span><span class="nu19">255</span><span class="sy4">;</span></div>
</div>
</pre>
<p>Так, самое основное мы сделали. Теперь нам осталось лишь реализовать шифрование, для этого мы опишем цикл, в котором мы будем посимвольно осуществлять операцию XOR. Но для этого нам понадобится еще объявить массив приемник, в который мы поместим зашифрованный текст. Смотрим:</p>
<pre><strong>pascal/Delphi</strong>
<div class="codesnip-container" >
<div class="pascal codesnip" style="font-family:monospace;"><span class="kw1">procedure</span> shifr_Vernam;
<span class="kw1">var</span>
&nbsp; oStr<span class="sy0">,</span> key<span class="sy0">,</span> shStr <span class="sy0">:</span><span class="kw4">string</span>;
&nbsp; i<span class="sy0">:</span><span class="kw4">integer</span>;
<span class="kw1">begin</span>
&nbsp; oStr<span class="sy0">:=</span><span class="st_h">'Holo word!'</span>; &nbsp;<span class="co1">//определяем открытый текст</span>
&nbsp; randomize; <span class="co1">//Необходимая функция для функции random, чтобы последняя каждый раз выдавала случайные значения</span>
<span class="co1">//генерируем случайный ключ длиной равной длине открытого текста</span>
&nbsp; <span class="kw1">for</span> i<span class="sy0">:=</span>1 <span class="kw1">to</span> length<span class="br0">&#40;</span>oStr<span class="br0">&#41;</span> <span class="kw1">do</span>
&nbsp; &nbsp; key<span class="br0">&#91;</span>i<span class="br0">&#93;</span><span class="sy0">:=</span><span class="kw3">Chr</span><span class="br0">&#40;</span>random<span class="br0">&#40;</span>255<span class="br0">&#41;</span><span class="br0">&#41;</span>; <span class="co1">//генерируем случайное число из диапозона от 0 до 255 и полученное число переводим в символ;</span>
<span class="co1">//собственно само шифрование</span>
&nbsp; <span class="kw1">for</span> i<span class="sy0">:=</span>1 <span class="kw1">to</span> length<span class="br0">&#40;</span>oStr<span class="br0">&#41;</span> <span class="kw1">do</span>
&nbsp; &nbsp; shStr<span class="br0">&#91;</span>i<span class="br0">&#93;</span><span class="sy0">:=</span>oStr<span class="br0">&#91;</span>i<span class="br0">&#93;</span> <span class="kw1">xor</span> key<span class="br0">&#91;</span>i<span class="br0">&#93;</span>;
<span class="co1">//для наглядности выведем на экран результат работы</span>
&nbsp; <span class="kw3">writeLn</span><span class="br0">&#40;</span><span class="st_h">'Otkrytyi text: '</span><span class="sy0">,</span>oStr<span class="br0">&#41;</span>;
&nbsp; <span class="kw3">writeLn</span><span class="br0">&#40;</span><span class="st_h">'Zashifrovanyi text: '</span><span class="sy0">,</span>shStr<span class="br0">&#41;</span>;
<span class="kw1">end</span>;</div>
</div>

<strong>C/C++</strong>
<div class="codesnip-container" >
<div class="cpp codesnip" style="font-family:monospace;"><span class="kw4">void</span> shifr_Vernam
<span class="br0">&#123;</span>
&nbsp; &nbsp;<span class="kw4">int</span> i,len<span class="sy4">;</span> <span class="co1">//Определяем необходимые переменные</span>
&nbsp; &nbsp;len <span class="sy1">=</span> <span class="kw3">strlen</span><span class="br0">&#40;</span><span class="st0">&quot;Holo word!&quot;</span><span class="br0">&#41;</span><span class="sy4">;</span><span class="co1">// определяем длину строки открытого текста</span>
&nbsp; &nbsp;<span class="kw4">char</span> <span class="sy2">*</span>oStr <span class="sy1">=</span> <span class="kw3">new</span> <span class="kw4">char</span><span class="br0">&#91;</span>len<span class="br0">&#93;</span><span class="sy4">;</span> <span class="co1">//объявляем динамический массив указанной длины для открытого текста</span>
&nbsp; &nbsp;<span class="kw4">char</span> <span class="sy2">*</span>key <span class="sy1">=</span> <span class="kw3">new</span> <span class="kw4">char</span><span class="br0">&#91;</span>len<span class="br0">&#93;</span><span class="sy4">;</span> &nbsp;<span class="co1">//точно такой же массив объявляем для ключа</span>
&nbsp; &nbsp;<span class="kw4">char</span> <span class="sy2">*</span>shStr <span class="sy1">=</span> <span class="kw3">new</span> <span class="kw4">char</span><span class="br0">&#91;</span>len<span class="br0">&#93;</span><span class="sy4">;</span> &nbsp;<span class="co1">//массив-приемник для зашифрованного текста</span>
&nbsp; &nbsp;oStr<span class="sy1">=</span><span class="st0">&quot;Holo word!&quot;</span><span class="sy4">;</span> &nbsp; <span class="co1">//помещаем в массив открытый текст</span>
<span class="co1">// определяем ключ случайным образом</span>
&nbsp; &nbsp;<span class="kw1">for</span><span class="br0">&#40;</span>i <span class="sy1">=</span> <span class="nu0">0</span><span class="sy4">;</span> i <span class="sy3">&amp;</span>lt<span class="sy4">;</span> len<span class="sy4">;</span> i<span class="sy2">++</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; key<span class="br0">&#91;</span>i<span class="br0">&#93;</span><span class="sy1">=</span><span class="br0">&#40;</span><span class="kw4">char</span><span class="br0">&#41;</span><span class="kw3">rand</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy2">%</span><span class="nu19">255</span><span class="sy4">;</span>
<span class="co1">//собственно само шифрование</span>
&nbsp; &nbsp;<span class="kw1">for</span><span class="br0">&#40;</span>i <span class="sy1">=</span> <span class="nu0">0</span><span class="sy4">;</span> i <span class="sy3">&amp;</span>lt<span class="sy4">;</span> len<span class="sy4">;</span> i<span class="sy2">++</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; shStr<span class="br0">&#91;</span>i<span class="br0">&#93;</span><span class="sy1">=</span>oStr<span class="br0">&#91;</span>i<span class="br0">&#93;</span><span class="sy3">^</span>key<span class="br0">&#91;</span>i<span class="br0">&#93;</span><span class="sy4">;</span>
<span class="co1">//для наглядности выведем на экран результат работы</span>
&nbsp; &nbsp;<span class="kw3">printf</span><span class="br0">&#40;</span><span class="st0">&quot;<span class="es1">\n</span>Otkrytyi text: %s&quot;</span>, oStr<span class="br0">&#41;</span><span class="sy4">;</span>
&nbsp; &nbsp;<span class="kw3">printf</span><span class="br0">&#40;</span><span class="st0">&quot;<span class="es1">\n</span>Zashifrovanyi text: %s&quot;</span>, shStr<span class="br0">&#41;</span><span class="sy4">;</span>
<span class="br0">&#125;</span></div>
</div>
</pre>
<p>На этом  все, реализация шифрования закончена. Надеюсь, что вы догадаетесь как реализовать дешифровку(Подсказка: те же действия нужно провести для шифрованного текста ;) ). Спасибо за внимание.</p>
]]></content:encoded>
			<wfw:commentRss>http://zetblog.ru/programming/200812/%d0%ba%d1%80%d0%b8%d0%bf%d1%82%d0%be%d0%b3%d1%80%d0%b0%d1%84%d0%b8%d1%8f-%d1%88%d0%b8%d1%84%d1%80-%d0%b2%d0%b5%d1%80%d0%bd%d0%b0%d0%bc%d0%b0/feed/</wfw:commentRss>
		<slash:comments>18</slash:comments>
		</item>
		<item>
		<title>Криптография: Шифр Виженера и его программная реализация.</title>
		<link>http://zetblog.ru/programming/200812/%d0%ba%d1%80%d0%b8%d0%bf%d1%82%d0%be%d0%b3%d1%80%d0%b0%d1%84%d0%b8%d1%8f-%d1%88%d0%b8%d1%84%d1%80-%d0%b2%d0%b8%d0%b6%d0%b5%d0%bd%d0%b5%d1%80%d0%b0-%d0%bf%d1%80%d0%be%d0%b3%d1%80%d0%b0%d0%bc%d0%bc/</link>
		<comments>http://zetblog.ru/programming/200812/%d0%ba%d1%80%d0%b8%d0%bf%d1%82%d0%be%d0%b3%d1%80%d0%b0%d1%84%d0%b8%d1%8f-%d1%88%d0%b8%d1%84%d1%80-%d0%b2%d0%b8%d0%b6%d0%b5%d0%bd%d0%b5%d1%80%d0%b0-%d0%bf%d1%80%d0%be%d0%b3%d1%80%d0%b0%d0%bc%d0%bc/#comments</comments>
		<pubDate>Wed, 03 Dec 2008 14:41:50 +0000</pubDate>
		<dc:creator>C0ffe1n</dc:creator>
				<category><![CDATA[криптография]]></category>
		<category><![CDATA[Программирование]]></category>
		<category><![CDATA[Delphi]]></category>
		<category><![CDATA[шифры]]></category>

		<guid isPermaLink="false">http://zetblog.ru/?p=111</guid>
		<description><![CDATA[Немного теории. Шифр Виженера представляет собой усовершенствованную многоалфавитную систему шифрования. Идея шифра состоит в использовании в качестве ключа (кодовое слово) текста самого сообщения (открытого &#8212; не зашифрованного) или же шифрованного текста (закрытого). Кроме того, для усиления стойкости шифра, в качестве первого символа ключа берется случайным образом буква из алфавита. Авторами этой идеи являются Джероламо Кардано [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Немного теории. Шифр Виженера</strong> представляет собой усовершенствованную многоалфавитную систему шифрования. Идея шифра  состоит     в использовании в качестве ключа (кодовое слово) текста самого сообщения (открытого &#8212; не зашифрованного) или же     шифрованного текста (закрытого). Кроме того, для усиления стойкости шифра, в качестве первого символа ключа берется случайным образом буква из алфавита. Авторами этой идеи являются Джероламо Кардано и собственно сам Блез де Виженер.  Данный шифр также имеет другое название <strong>&#171;шифр самоключ&#187;</strong>. Этот шифр Виженер описал в своей книге &#171;Трактат о шифрах&#187;. В своем трактате Блез описал этот шифр следующим образом: В простейшем случае за основу бралась таблица Тритемия, в последствии которая получила название таблица Виженера.<br />
<span id="more-111"></span></p>
<table style="height: 346px;" border="1" cellspacing="1" cellpadding="3" width="198" align="center">
<tbody>
<tr>
<td width="10%" valign="top"><span style="font-family: Courier New;"> * </span></td>
<td colspan="2" valign="top"><span style="font-family: Courier New;"> АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЬЫЪЭЮЯ</span></td>
</tr>
<tr>
<td width="10%" valign="top"><span style="font-family: Courier New;"> А Б В Г Д Е Ж З И Й К Л М Н О П Р С Т У Ф Х Ц Ч Ш Щ Ь Ы Ъ Э Ю Я</span></td>
<td style="text-align: left;" width="90%" valign="top"><span style="font-family: Courier New;"> абвгдежзийклмнопрстуфхцчшщьыъэюя бвгдежзийклмнопрстуфхцчшщьыъэюяА вгдежзийклмнопрстуфхцчшщьыъэюяАБ гдежзийклмнопрстуфхцчшщьыъэюяАБВ дежзийклмнопрстуфхцчшщьыъэюяАБВГ ежзийклмнопрстуфхцчшщьыъэюяАБВГД жзийклмнопрстуфхцчшщьыъэюяАБВГДЕ зийклмнопрстуфхцчшщьыъэюяАБВГДЕЖ ийклмнопрстуфхцчшщьыъэюяАБВГДЕЖЗ йклмнопрстуфхцчшщьыъэюяАБВГДЕЖЗИ клмнопрстуфхцчшщьыъэюяАБВГДЕЖЗИЙ лмнопрстуфхцчшщьыъэюяАБВГДЕЖЗИЙК мнопрстуфхцчшщьыъэюяАБВГДЕЖЗИЙКЛ нопрстуфхцчшщьыъэюяАБВГДЕЖЗИЙКЛМ опрстуфхцчшщьыъэюяАБВГДЕЖЗИЙКЛМН прстуфхцчшщьыъэюяАБВГДЕЖЗИЙКЛМНО рстуфхцчшщьыъэюяАБВГДЕЖЗИЙКЛМНОП стуфхцчшщьыъэюяАБВГДЕЖЗИЙКЛМНОПР туфхцчшщьыъэюяАБВГДЕЖЗИЙКЛМНОПРС уфхцчшщьыъэюяАБВГДЕЖЗИЙКЛМНОПРСТ фхцчшщьыъэюяАБВГДЕЖЗИЙКЛМНОПРСТУ хцчшщьыъэюяАБВГДЕЖЗИЙКЛМНОПРСТУФ цчшщьыъэюяАБВГДЕЖЗИЙКЛМНОПРСТУФХ чшщьыъэюяАБВГДЕЖЗИЙКЛМНОПРСТУФХЦ шщьыъэюяАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧ щьыъэюяАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШ ьыъэюяАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩ ыъэюяАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЬ ъэюяАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЬЫ эюяАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЬЫЪ юяАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЬЫЪЭ яАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЬЫЪЭЮ<br />
</span></td>
</tr>
</tbody>
</table>
<div><strong>Таблица Виженера</strong></div>
<p>Замечу, в общем случае таблица Виженера состоит из алфавита, циклически сдвинутого на один символ влево, однако, возможны и другие перестановки &#8212; это на Ваше усмотрение. Кроме того, первая строка может представлять собой  алфавит, случайным образом  перемешанный.</p>
<p>Процесс шифрования выглядит следующим образом: открытый текст (который надо зашифровать) записывается в строчку без пробелов. Далее необходимо определить ключ. Виженер предлагал в качестве ключа использовать сам открытый текст, с добавлением к началу ключа символ, выбранный случайным образом. Но замечу, что не обязательно следовать установленному правилу создателя шифра. В качестве ключа вполне возможно использовать и любую другую последовательность символов длиною равной длине открытого текста.</p>
<p>После всего проделанного, для получения шифр-текста (криптограмма) берем первый символ открытого текста в качестве указателя строки в <strong>Таблице Виженера</strong>, а стоящую под ним букву &#8212; в качестве столбца. На пересечении этой пары из таблицы выписываем символ шифр-текста. Далее повторяем  эти действия для всех оставшихся символов. Для примера рассмотрим шифрование открытого текста &#8212; &#171;яблочный джем&#187;. В качестве ключа будем использовать сам открытый текст с добавлением в начала случайного символа &#8212; у меня это вышло &#171;щ&#187;. Повторюсь, что ключ может быть образован иным способом, к примеру просто перемешанный случайным образом открытый текст &#8212; &#171;ляйычнбо жемд&#187;. Но ключ должен быть известен получателю шифра, то есть известна схема перемешивания открытого текста для того, чтобы он мог расшифровать криптограмму. Так, теперь записываем открытый текст в строку без пробелов, а под ней также записываем ключ.</p>
<p>Получаем:</p>
<pre>открытый текст:  я б л о ч н ы й д ж е м
ключ:            щ я б л о ч н ы й д ж е
               ---------------------------
шифр-текст:      ш а м щ е д й д н к л с</pre>
<p>Для того, чтобы восстановить (расшифровать) открытый текст, необходимо знать шифр-текст и ключ. Далее берем первую букву ключа определяем соответствующий ей столбец в <strong>Таблице Виженера</strong> и пробегаемся по нему сверху вниз пока не встретим первый символ шифр-текста. Как только встретили нужный символ, выписываем букву указывающую на эту строку &#8212; таким образом мы получаем первый символ открытого текста. Проделываем те же действия для оставшихся символов ключа и шифр-текста.</p>
<p>Шифр Виженера был незаслуженно забыт на долгое время. И многие по сей день под этим шифром понимают самый простой вариант с коротким ключевым словом и с таблицей, состоящей из обычных алфавитов.</p>
<p><strong>А теперь рассмотрим программную реализацию шифра Виженера на Delphi.</strong></p>
<p>Для начала нам необходимо сгенерировать саму таблицу Виженера. Для этого</p>
<p>необходимо объявить следующие глобальные переменные:</p>
<pre class="brush: delphi">
mas_alf: array[1..32] of char =

('А','Б','В','Г','Д','Е','Ж','З','И','Й','К','Л','М','Н','О','П','Р','С

','Т','У','Ф','Х','Ц','Ч','Ш','Щ','Ь','Ы','Ъ','Э','Ю','Я');
tab_Vig: array[1..32,1..32] of Char;
</pre>
<p>Ну а теперь напишем код генерации таблицы:</p>
<pre class="brush: delphi">
var
  i,j,k,n:integer;
begin
 k:=0;
 n:=k;

 for i:=Ord('А')-191 to Ord('Я')-191 do
 begin
   k:=n+1;
   for j:=Ord('А')-191 to Ord('Я')-191 do
    begin
     if k = 33 then
        k:=1;
     tab_vig[i][j]:=mas_alf[k];
     k:=k+1;
    end;
    n:=n+1;
 end;
end;
</pre>
<p>Таблица есть и можно смело приступать к реализации процедуры шифрования. Смотрим:</p>
<pre class="brush: delphi">
var
  key : array [0..255] of Char;
  s:char;
  k:Boolean;
  length_key,length_text,i,j,c,stroka,stolbec: integer;
begin
  Label5.Caption:='';//
  Memo2.Clear;//
  length_key:=Edit1.GetTextLen;
  Edit1.GetTextBuf(key,sizeof(key));
  length_text:=Memo1.GetTextLen;
//выводим таблицу Виженера
 for i:=Ord('А')-191 to Ord('Я')-191 do
 begin
    for j:=Ord('А')-191 to Ord('Я')-191 do
    begin
      Label5.Caption:= Label5.Caption +'  '+ tab_Vig[i][j];
    end;
    Label5.Caption := Label5.Caption + #13+#10;
 end;
//приступаем к процессу шифрования
 j:=1;
 c:=0;
 k:=false;
 Memo2.Lines.Add('Зашифрованный текст:');
 Memo2.Lines.Add('------------------------');
  for i:= 0 to Memo1.Lines.Count-1 do
  begin
     s:=Memo1.Lines[i][j];
     if ((s &lt;&gt; #0) or (s &lt;&gt; #13)) then
     while k = false do
     begin
       if Ord(key[c])&gt;223 then
         stolbec:=Ord(key[c])-32-191
       else
         stolbec:=Ord(s)-191;
       if Ord(s)&gt;223 then
         stroka:=Ord(s)-32-191
       else
         stroka:=Ord(s)-191;
       Memo2.Text:=Memo2.Text+tab_Vig[stroka][stolbec];
       if(c &lt; length_key-1)then
         c:=c+1
       else
         c:=0;
       j:=j+1;
       s:=Memo1.Lines[i][j];
       if(s = #0) then
         k:=true;
     end;
     k:=false;
     j:=1;
  end;
 Memo2.Lines.Add('------------------------');
end;
</pre>
<p>Так как шифрование реализовано, значит пора рассмотреть процедуру расшифровки. Смотрим:</p>
<pre class="brush: delphi">
var
  key : array [0..255] of Char;
  s:char;
  k:Boolean;
  length_key,length_text,i,j,c,stroka,stolbec,q: integer;
begin
  Label5.Caption:='';//
  Memo2.Clear;//
  length_key:=Edit1.GetTextLen;
  Edit1.GetTextBuf(key,sizeof(key));
  length_text:=Memo1.GetTextLen;
  j:=1;
  c:=0;
  k:=false;
  Memo2.Lines.Add('Расшифрованный текст:');
  Memo2.Lines.Add('------------------------');
  for i:= 0 to Memo1.Lines.Count-1 do
  begin
     if Ord(Memo1.Lines[i][j])&gt;223 then
         s:=Ord(Memo1.Lines[i][j])-32-191
     else
         s:=Ord(Memo1.Lines[i][j])-191;
     s:=Memo1.Lines[i][j];
     if ((s &lt;&gt; #0) or (s &lt;&gt; #13)) then
     while k = false do
     begin
       if Ord(key[c])&gt;223 then
         stolbec:=Ord(key[c])-32-191
       else
         stolbec:=Ord(s)-191;
       for q:=1 to 32 do
       begin
         if tab_Vig[q][stolbec] = s then
         begin
           Memo2.Text:=Memo2.Text+Chr(q+191);
            break;
         end;
       end;

       if(c &lt; length_key-1)then
         c:=c+1
       else
         c:=0;
       j:=j+1;
       s:=Memo1.Lines[i][j];
       if(s = #0) then
         k:=true;
     end;
     k:=false;
     j:=1;
  end;
 Memo2.Lines.Add('------------------------');
end;
</pre>
<p>Что ж, на этом все, если Вы обнаружили какие то неточности, или что то не понятно прошу отписывать их на <a href="/forum/">форуме</a> ;). Спасибо за внимание.</p>
<p><strong>Рабочий пример</strong> <a href="http://depositfiles.com/files/5nv357jnz">скачать</a>.</p>
<p><strong>Рекомендую для прочтения:</strong><br />
Книга Чарльз Уэзерелл, &#171;Этюды для программистов&#187;. <a href="http://depositfiles.com/files/87fn0bihs">Скачать</a><br />
Статья о книге. <a href="http://easy-coding.blogspot.com/2009/02/blog-post_26.html">Читать</a></p>
]]></content:encoded>
			<wfw:commentRss>http://zetblog.ru/programming/200812/%d0%ba%d1%80%d0%b8%d0%bf%d1%82%d0%be%d0%b3%d1%80%d0%b0%d1%84%d0%b8%d1%8f-%d1%88%d0%b8%d1%84%d1%80-%d0%b2%d0%b8%d0%b6%d0%b5%d0%bd%d0%b5%d1%80%d0%b0-%d0%bf%d1%80%d0%be%d0%b3%d1%80%d0%b0%d0%bc%d0%bc/feed/</wfw:commentRss>
		<slash:comments>32</slash:comments>
		</item>
		<item>
		<title>Delphi: Контроль соединений c Internet.</title>
		<link>http://zetblog.ru/programming/200811/delphi-%d0%ba%d0%be%d0%bd%d1%82%d1%80%d0%be%d0%bb%d1%8c-%d1%81%d0%be%d0%b5%d0%b4%d0%b8%d0%bd%d0%b5%d0%bd%d0%b8%d0%b9-%d1%81-internet/</link>
		<comments>http://zetblog.ru/programming/200811/delphi-%d0%ba%d0%be%d0%bd%d1%82%d1%80%d0%be%d0%bb%d1%8c-%d1%81%d0%be%d0%b5%d0%b4%d0%b8%d0%bd%d0%b5%d0%bd%d0%b8%d0%b9-%d1%81-internet/#comments</comments>
		<pubDate>Wed, 19 Nov 2008 19:10:50 +0000</pubDate>
		<dc:creator>C0ffe1n</dc:creator>
				<category><![CDATA[Программирование]]></category>
		<category><![CDATA[системное]]></category>
		<category><![CDATA[Delphi]]></category>
		<category><![CDATA[Internet]]></category>
		<category><![CDATA[WinAPI]]></category>

		<guid isPermaLink="false">http://zetblog.ru/?p=36</guid>
		<description><![CDATA[Причиной побудившей меня написать эту статью была нестабильность работы соединения с Интернетом, которое довольно часто разрывалось. А стандартная функция ОС Windows ХР не справлялась с возложенной на нее обязанностью по восстановлению разорванного соединения. Плюс к этому, не так уж удобно «листать» системный журнал в поиске причины разрыва, или времени разрыва, или других каких логов.(Стоит только вспомнить эти ужасные времена, когда у «стрима» было аж по 4 обрыва. Сколько нерв попортили они людям) … прошу прощения, отвлекся ;)]]></description>
			<content:encoded><![CDATA[<p>Причиной, побудившей меня написать эту статью, была нестабильность работы соединения с Интернетом, которое довольно часто разрывалось. А стандартная функция ОС Windows ХР не справлялась с возложенной на нее обязанностью по восстановлению разорванного соединения. Плюс к этому, не так уж удобно «листать» системный журнал в поиске причины разрыва, или времени разрыва, или других каких логов.(Стоит только вспомнить эти ужасные времена, когда у «стрима» было аж по 4 обрыва. Сколько нервов попортили они людям) … прошу прощения, отвлекся ;) Приступим к решению этого вопроса. В качестве язык программирования будем использовать Delphi 7 версии.<br />
<span id="more-36"></span></p>
<p>Первое что нам надо рассмотреть &#8212; это средства для работы с системой установки удаленного доступа (RAS). Данное средство представляет собой набор API-функций, которые хранятся в системной библиотеке rasapi.dll, используемой ОС.</p>
<p>Это достаточно мощная библиотека и для решения нашей проблемы нам понадобятся не все функции. Поэтому мы рассмотрим только необходимые нам. Перечислю их:<br />
<strong>RasEnumConnections </strong>– функция для проверки наличия установленных соединений;<br />
<strong>RasEnumEntries</strong> – функция получения списка соединений(зарегистрированных) в системе;<br />
<strong>RasDial</strong> – функция установки соединения.</p>
<p>Что ж, теперь необходимо сформулировать тех. задание решения поставленной задачи. Итак:<br />
1) Необходимо определить/получить список соединений (зарегистрированных в системе)<br />
2) Реализовать процедуру дозвона<br />
3) Реализовать обработчик-таймер, который будет проверять, через определенный интервал времени, статус установленного соединения<br />
4) Написать процедуру ведения лога – пользовательский журнал.</p>
<p>Кроме того, чтобы программы была более гибкой, то мы реализуем дружественный интерфейс, в котором позволим пользователю выбирать из списка соединений (которых может быть более одного ;) ). Поэтому начнем мы с последнего.</p>
<p>Для этого запустим Delphi, создадим новый проект и сохраним его под названием, к примеру ControlConn. Скинем на форму:<br />
<strong>- 2 ListBox’a<br />
- 3 кнопки<br />
- 1 поле ввода</strong> (для указания интервала проверки статуса соединения).</p>
<p>Теперь проведем некоторое приготовление. Один ListBox назовем ActivCon – в него будут занесены сведения о существующих соединениях, а второй назовем ControlCon – в нем будут находится соединения которые необходимо контролировать. Одна из кнопок будет отвечать за запуск процесса контроля – и будет иметь недвусмысленное имя start ;), оставшиеся 2-е кнопки необходимы для манипулирования содержимым ListBox’ов, добавить в список контролируемых соединений и удалить из списка. Поле ввода назовем interval.</p>
<p>Создадим для формы событие<strong> OnActivate</strong>, на вкладке <strong>Event</strong> в инспекторе объектов. В нем мы опишем код, который будет получать список соединений. Кстати, замечу для тех, кто только начинает и тех, кто этого не знал, но программирует уже давно, что хорошим стилем программирования является описание всех своих функций и процедур, используемых в проекте, в отдельном модуле. В данном случае у нас нет необходимости выносить код в отдельную функцию. Но стоит иметь в виду, что в этом есть два основных плюса:<br />
- сам проект не перегружен большим количеством программного кода<br />
- в случае необходимости редактирования некоторых функция проекта, гораздо удобнее загрузив в редактор отдельный модуль.</p>
<p>При этом не возникнет никаких проблем с согласованием с промежуточным кодом в самом проекте.</p>
<p>А теперь код:</p>
<pre  class="brush: delphi">
procedure TForm1.FormActivate(Sender: TObject);
var
bSize    : integer; //размер массива, который будут помещаться сведения об «удаленных соединениях»
cCount           : integer; //количество удаленных соединений
cList             : array[1..MaxEntries] of TRasEntryName; //массив, в который будут помещены сведения об удаленных соединениях
// где MaxEntries – константа, представляющая максимально возможное количество соединений, объявлена в модуле RasUnit.pas
x,rslt         : integer;
begin
cList[1].dwSize:=SizeOf(TRasEntryName);
bSize:=SizeOf(TRasEntryName)*MaxEntries;
//получаем список соединений
rslt:=RasEnumEntries(nil, nil, @cList[1], bSize, cCount);
//если функция выполнилась успешно и есть соединения
if (rslt=0) and (cCount&gt;0) then
begin
// то заполняем список соединений ActivCon
for x:=1 to cCount do
ActivCon.Add(cList[x].szEntryName);
end;
end;
</pre>
<p>Теперь при запуске программы у нас в списке ActivCon будут перечислены все зарегистрированные в системе ras-соединения. Далее нужно добавить возможность манипулирования списком соединений. Следующий код для кнопки <strong>«Добавить»</strong>:</p>
<pre  class="brush: delphi">
procedure TForm1.Button1Click(Sender: TObject);
var
i,j:integer;
begin
if ActivCon.SelCount=0 then
exit;
for j:=0 to ActivCon.SelCount-1 do
if search(ActivCon.Items.Strings[ActivCon.ItemIndex], ControlCon) = -1 then
begin
ControlCon.Items.Add(ActivCon.Items.Strings[ActivCon.ItemIndex]);
ActivCon.Items.Delete(ActivCon.ItemIndex);
end
else
begin
Application.MessageBox('Такое соединение в списке уже есть!','Внимание');
end;
end;
</pre>
<p>Для кнопки <strong>«Удалить»</strong>:</p>
<pre  class="brush: delphi">
procedure TForm1.Button2Click(Sender: TObject);
var
i,j:integer;
begin
if ControlCon.SelCount=0 then
exit;
for j:=0 to ControlCon.SelCount-1 do
if search(ControlCon.Items.Strings[ControlCon.ItemIndex], ActiveCon) = -1 then
begin
ActiveCon.Items.Add(ControlCon.Items.Strings[ControlCon.ItemIndex]);
ControlCon.Items.Delete(ControlCon.ItemIndex);
end
else
begin
Application.MessageBox('Такое соединение в списке уже есть!','Внимание');
end;
end;
</pre>
<p>В обоих листингах используется функция <strong>search</strong>, которой в качестве параметра передается строка, наличие которой необходимо проверить в списке соединений:</p>
<pre  class="brush: delphi">
function search(str:string; lsb:TListBox):integer;
var
i,j:integer;
begin
for i:=0 to lsb.Count-1 do
begin
j:=i;
if lsb.Items[i] = str then
begin
search:=j;
exit;
end;
end;
search:=-1;
end;
</pre>
<p>Да, кстати, самое главное то мы забыли. Нам еще нужен таймер, добавим его. Кроме того, нам необходимо объявить глобальные переменные и структуру состояния соединения, объявим их:</p>
<pre  class="brush: delphi">type
TMyDialParam = Record
AMsg:Integer;
AState:TRasConnState;
AError:Integer;
End;

var
MyDialParam:TMyDialParam;
hRas: ThRASConn;
</pre>
<p>Кроме глобальных переменных, нам нужно определить <strong>CallBack</strong>-процедуру, которая  необходима для вызова функции <strong>RasDial()</strong>.</p>
<pre  class="brush: delphi">
procedure RasCallback(msg: Integer; state: TRasConnState; error: Integer); stdcall;
begin
MyDialParam.AMsg:=msg;
MyDialParam.AState:=state;
MyDialParam.AError:=error;
{
Здесь можно описать обработчик полученных сообщений о статусе установки соединения.
}
end;
</pre>
<p>Теперь создадим для Таймера событие <strong>onTimer</strong> и напишем в нем следующий код:</p>
<pre  class="brush: delphi">
procedure TForm1. Timer1Timer(Sender: TObject);
var
rcArray: array[1..100]of TRASCONN;
rStatus: TRASCONNSTATUS;
dwRet: integer;
rcsize: integer;
dw2: integer;
i,j,tr:integer;
s:string;

begin
tr:=0;
//отключаем таймер
Timer1.Enabled:=false;
if  Edit1.Text = ‘’ then      // Если интервал не указан
Timer1.Interval:=5000;  // то устанавливаем значение по умолчанию 5 секунд
else
Timer1.Interval:=StrToint(Edit1.Text)*1000;
//производим подготовку для получения списка работающих соединений(уже установленных)
rcsize:= sizeof(rcArray);
ZeroMemory(@rcArray, rcsize);
rcArray[1].dwSize := sizeof(TRASCONN);
dwRet := RasEnumConnections(@rcArray, rcsize, dw2);
ZeroMemory(@rStatus, sizeof(TRASCONNSTATUS));
rStatus.dwSize := sizeof(TRASCONNSTATUS);
// если количество работающих соединений равно 0, тогда
if dw2 = 0 then     //запускаем их поочередно
begin
if ControlCon.Count &lt;&gt; 0 then // проверяем не пуст ли список контролируемых соединений
for i:=1 to ControlCon.Count-1 do
begin
MemError.Lines.Add(TimeToStr(Time)+' соединение не установлено '+ ControlCon.items[i]+'. Запускаю.'); //заносим в журнал сообщение о разрыве
//и вызываем функцию установки соединения
ConnectEntry(ControlCon.Items[i],i);
end;
end
else
begin
//если же было определено что соединение хоть одно но запущено
if ControlCon.Count &lt;&gt; 0 then // то мы опять же проверяем список
begin
for i:=0 to ControlCon.Count-1 do  // после чего пробегаем по всему списку и сверяемся с полученным списком рабочих соединений, если в полученном списке какие-то соединения отсутствуют, то мы их немедленно устанавливаем
begin
for j:=1 to dw2 do
begin
if ControlCon.Items[i] = rcArray[j].szEntryName then
begin
tr:=1;
MemError.Lines.Add(TimeToStr(Time)+' соединение не установлено '+ ControlCon.items[i]+'. Запускаю.'); //заносим в журнал сообщение о разрыве
end;
end;
if tr = 1 then
// устанавливаем соединение
ConnectEntry(ControlCon.Items[i],i);
end;
end;
end;
//запускаем таймер
Timer1.Enabled:=true;
end;
</pre>
<p>Теперь опишем процедуру установки соединения:</p>
<pre  class="brush: delphi">procedure ConnectEntry(nameEntry: string);
var
fl : LongBool;
r  : Integer;
DialParams  : TRasDialParams;
hR: ThRASConn;
begin
//забиваем DialParams нулями
FillChar(DialParams, SizeOf(TRasDialParams), 0);
//Инициализируем переменную DialParams, заполнив поля dwSize и szEntryName
with DialParams do
begin
dwSize:=Sizeof(TRasDialParams);
StrPCopy(szEntryName, nameEntry);
end;
//Теперь вызовем функцию для заполнения оставшихся полей структуры DialParams
r:=RasGetEntryDialParams(nil, DialParams, fl);
//если все прошло успешно
if r=0 then
begin
//вызываем функцию «дозвона»
r:=RasDial(nil, nil, DialParams, 0, @RasCallback, hRas);
end;
end;
</pre>
<p>На этом все. Статью заканчивал в спешке, поэтому в случае обнаружения каких либо неточностей, непоняток или ошибок &#8212; просьба сильно не ругаться, а отписываться по всем замечаниям и не только ;). Всем спасибо!</p>
<p><strong>Необходимые модули:</strong><br />
rasunit &#8212; <a href="http://depositfiles.com/files/ngwqz5p3r">Скачать</a></p>
]]></content:encoded>
			<wfw:commentRss>http://zetblog.ru/programming/200811/delphi-%d0%ba%d0%be%d0%bd%d1%82%d1%80%d0%be%d0%bb%d1%8c-%d1%81%d0%be%d0%b5%d0%b4%d0%b8%d0%bd%d0%b5%d0%bd%d0%b8%d0%b9-%d1%81-internet/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
	</channel>
</rss>

