Версия для печати


Использование Internet-функций Win32® API
http://www.delphikingdom.com/asp/viewitem.asp?catalogID=401

Александр Лозовюк
дата публикации 27-04-2001 00:00

Использование Internet-функций Win32® API

Internet так сильно вошел в нашу жизнь, что программа, так или иначе не использующая его возможности, обречена на “вымирание” почти как динозавры. Поэтому всех программистов, вне зависимости от квалификации и специализации так и тянет дописать до порой уже готовой программы какой-то модуль для работы с Internet. Но тут и встает вопрос – как это сделать? Давайте рассмотрим, что нам предлагает среда Borland Delphi и Win32 API.

Во-первых, можно использовать компоненты с вкладки FastNet. Все они написаны фирмой NetMasters и поставляются без исходного кода. По многочисленным откликам различных разработчиков можно сказать, что большинство из них не выдерживает никакой критики, особенно “отличились” компоненты для работы с почтой. Большинство проблем можно было бы исправить, но так как исходные тексты закрыты, то это вряд ли удастся. Даже если вы будете использовать такие вроде бы надежные компоненты как TNMHTTP, TNMFTP, то в случае распространения готовой программы перед вами встает проблема: для полноценной работы программа с этими компонентами требует наличия ряда динамических библиотек. Значит, их надо отыскать, потом поставлять вместе с приложением, копировать в системные папки… Короче говоря, все слишком запутано.

Если вам не требуется всей функциональности этих компонент, например, надо только реализовать функции GET или POST протокола HTTP, то можно поискать на сайтах с компонентами, вроде torry.ru – там обязательно сыщется много различных библиотек, по большей части бесплатных, и с исходным кодом.

Но зачем нам что-то использовать, когда есть доступ к Win32 API ? Если приглядеться, то все эти компоненты всего лишь оболочка для вызова функций более низкого порядка. А раз так, то можно сразу их использовать. Кроме полного контроля над реализацией сетевых функций вы будете иметь и более компактный и быстрый код, так как устраняется прослойка между программой и API. Так что же такое Internet- функции Win32 API?

Все Internet- функции разбиты на категории:
  • General Win32 Internet Functions - общие функции.
  • Automatic Dialing Functions – функции для автодозвона.
  • Uniform Resource Locator (URL) Functions – функции для работы с URL.
  • FTP Functions – FTP- функции.
  • Gopher Functions - Gopher- функции.
  • HTTP Functions - HTTP- функции.
  • Cookie Functions – Работа и управление файлами cookie.
  • Persistent URL Cache Functions - работа с офф-лайном и кешем.

Всего функций довольно много, около 80, но для средних приложений большинство из них не понадобится. Рассмотрим, что можно использовать из первой категории.

Из всех функций наибольший практический интерес представляют следующие:

InternetCheckConnection
позволяет узнать, есть ли уже соединение с Internet.

Синтаксис:

function InternetCheckConnection(lpszUrl: PAnsiChar; 
                                 dwFlags: DWORD; 
                                 dwReserved: DWORD): BOOL; stdcall; 
Если нужно проверить, есть ли соединение по конкретному URL, то параметр lpszUrl должен содержать нужный URL; если интересует, есть ли соединение вообще, установите его в nil. Последнее значение , dwReserved, зарезервировано, и должно быть установлено в 0.

К сожалению, я не проверял эту функцию, когда писал статью... а жаль... вот что получаеться: константа FLAG_ICC_FORCE_CONNECTION вообще не описана в Дельфи. более того - ее нет ни в Microsoft Visual C++ 5 (!!!!), VBasic 5 тоже! едва нашел в C++ Builder 5.
Вот описание -
const FLAG_ICC_FORCE_CONNECTION       $00000001
Но! Даже с описанной константой ничего не работает так, как надо! Вот пример:
procedure TForm1.Button1Click(Sender: TObject);
var
 h:boolean;
begin
 h:= wininet.InternetCheckConnection(nil,$00000001,0);
 if
  h = True then
   Label1.Caption:='Соеденение с сервером 127.0.0.1 установлено.'
 else
  if h = false
   then
     Label1.Caption:='Соеденения с сервером 127.0.0.1 нет.';

end;
Запускаю вместе с сервером - вроде должно пинговать его. Но первый раз функция показывает что соеденение есть несмотря на то, стоит ли сервер, или нет. Потом все время выдает false.
Если кто из читателей может пролить некоторый свет на проблему этой функции, очень прошу написать мне.
Благодарю Суркиза Максима, который впервые обратил мое внимание на проблему.

InternetOpen

Функция возвращает значение TRUE, если компьютер соединен с Internet, и FALSE - в противном случае. Для получения более подробной информации о причинах неудачного выполнения функции вызовите GetLastError, которая возвратит код ошибки. Например, значение ERROR_NOT_CONNECTED информирует нас, что соединение не может быть установлено или компьютер работает в off-line.

Далее рассмотрим одну из самых важных функций. Ее вы будете использовать всякий раз, когда нужно получить доступ к любому из серверов – будь то HTTP, FTP или Gopher. Речь идет о InternetOpen .

Синтаксис:

function InternetOpen(lpszAgent: PChar; 
                      dwAccessType: DWORD; 
                      lpszProxy, lpszProxyBypass: PChar; 
                      dwFlags: DWORD): HINTERNET; stdcall;

Параметры:

lpszAgent
– строка символов, которая передается серверу и идентифицирует программное обеспечение, пославшее запрос.
dwAccessType
- задает необходимые параметры доступа. Принимает следующие значения:
  • INTERNET_OPEN_TYPE_DIRECT – обрабатывает все имена хостов локально.
  • INTERNET_OPEN_TYPE_PRECONFIG – берет установки из реестра.
  • INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY - берет установки из реестра и предотвращает запуск Jscript или Internet Setup (INS) файлов.
  • INTERNET_OPEN_TYPE_PROXY – использование прокси-сервера. В случае неудачи использует INTERNET_OPEN_TYPE_DIRECT. LpszProxy – адрес прокси-сервера. Игнорируется только если параметр dwAccessType отличается от INTERNET_OPEN_TYPE_PROXY. LpszProxyBypass - список имен или IP- адресов, соединяться с которыми нужно в обход прокси-сервера. В списке допускаются шаблоны. Так же, как и предыдущий параметр, не может содержать пустой строки. Если dwAccessType отличен от INTERNET_OPEN_TYPE_PROXY, то значения игнорируются, и параметр можно установить в nil. DwFlags – задает параметры, влияющие на поведение Internet- функций . Возможно применение комбинации из следующих разрешенных значений: INTERNET_FLAG_ASYNC, INTERNET_FLAG_FROM_CACHE, INTERNET_FLAG_OFFLINE.
Функция инициализирует использование Internet- функций Win32 API. В принципе, ваше приложение может неоднократно вызывать эту функцию, например, для доступа к различным сервисам, но обычно ее достаточно вызвать один раз. При последующих вызовах других функций возвращаемый указатель HINTERNET должен передаваться им первым. Таким образом, можно дважды вызвать InternetOpen, и, имея два разных указателя HINTERNET, работать с HTTP и FTP параллельно. В случае неудачи, она возвращает nil, и для более детального анализа следует вызвать GetLastError.

Непосредственно с этой функцией связанна и еще одна, не менее важная: InternetCloseHandle.

InternetCloseHandle

Синтаксис:

function InternetCloseHandle(hInet: HINTERNET): BOOL; stdcall; 
Как единственный параметр, она принимает указатель, полученный функцией InternetOpen, и закрывает указанное соединение. В случае успешного закрытия сессии возвращается TRUE, иначе - FALSE. Если поток блокирует возможность вызова Wininet.dll, то другой поток приложения может вызвать функцию с тем же указателем, чтобы отменить последнюю команду и разблокировать поток.

Мы уже установили соединение и знаем, как его закрыть. Теперь нам нужно соединиться с конкретным сервером, используя нужный протокол. В этом нам помогут следующие функции:
InternetConnect
function InternetConnect (hInet: HINTERNET; 
                          lpszServerName: PChar; 
                          nServerPort: INTERNET_PORT; 
                          lpszUsername: PChar; 
                          lpszPassword: PChar; 
                          dwService: DWORD; 
                          dwFlags: DWORD; 
                          dwContext: DWORD): HINTERNET; stdcall;
Функция открывает сессию с указанным сервером, используя протокол FTP, HTTP, Gopher. Параметры: Функция возвращает указатель на установленную сессию или nil в случае невозможности ее установки.

Итак, мы имеем связь с сервером, нужный нам порт открыт. Теперь следует открыть соответствующй файл. Для этого определена функция InternetOpenUrl. Она принимает полный URL файла и возвращает указатель на него. Кстати, перед ее использованием не нужно вызывать InternetConnect.

InternetOpenUrl

Синтаксис:

function InternetOpenUrl(hInet: HINTERNET; 
                         lpszUrl: PChar; 
                         lpszHeaders: PChar; 
                         dwHeadersLength: DWORD; 
                         dwFlags: DWORD; 
                         dwContext: DWORD): HINTERNET; stdcall; 

Параметры:

Возвращается значение TRUE, если соединение успешно, или FELSE - в противном случае.

Теперь можно спокойно считывать нужный файл функцией InternetReadFile.

InternetReadFile

Синтаксис:

function InternetReadFile(hFile: HINTERNET; 
                          lpBuffer: Pointer; 
                          dwNumberOfBytesToRead: DWORD; 
                          var lpdwNumberOfBytesRead: DWORD): BOOL; stdcall;

Параметры:

Функция позволяет считывать данные, используя указатель, полученный в результате вызова InternetOpenUrl, FtpOpenFile, GopherOpenFile, или HttpOpenRequest. Так же, как и все остальные функции, возвращает TRUE или FALSE.

После завершения работы функции нужно освободить указатель Hfile, вызвав InternetCloseHandle(hUrlFile) .

Вот, в принципе, и все об самых основных функциях. Для простейшего приложения можно определить примерно такой упрощенный алгоритм использования Internet- функций Win32 API взамен стандартным компонентов.
HSession:= InternetOpen - открывает сессию. 

HConnect:= InternetConnect - устанавливает соединение. 

hHttpFile:=httpOpenRequest
HttpSendRequest - HttpOpenRequest и HttpSendRequest используются вместе для получения доступа к файлу по HTTP- протоколу. Вызов HttpOpenRequest создает указатель и определяет необходимые параметры, а HttpOpenRequest отсылает запрос HTTP серверу, используя эти параметры.
function HttpOpenRequest(hConnect: HINTERNET; 
                         lpszVerb: PChar; 
                         lpszObjectName: PChar; 
                         lpszVersion: PChar; 
                         lpszReferrer: PChar; 
                         lplpszAcceptTypes: PLPSTR; 
                         dwFlags: DWORD; 
                         dwContext: DWORD): HINTERNET; stdcall;

function HttpSendRequest(hRequest: HINTERNET; 
                         lpszHeaders: PChar; 
                         dwHeadersLength: DWORD; 
                         lpOptional: Pointer; 
                         dwOptionalLength: DWORD): BOOL; stdcall;
HttpQueryInfo – используется для получения информации о файле. Вызывается после вызова HttpOpenRequest.
function HttpQueryInfo(hRequest: HINTERNET; 
                       dwInfoLevel: DWORD; 
                       lpvBuffer: Pointer; 
                       var lpdwBufferLength: DWORD; 
                       var lpdwReserved: DWORD): BOOL; stdcall;

InternetReadFile - считывает нужный файл. 

InternetCloseHandle(hHttpFile) – освобождает указатель на файл. 

InternetCloseHandle(hConnect) - освобождает указатель на соединение. 

InternetCloseHandle(hSession) - освобождает указатель на сессию. 
Объем статьи не позволяет подробно рассмотреть все множество функций, предоставляемых Win32 API. Это введение показало вам только вершину айсберга, а дальше дело за вами – внутренний мир WinAPI очень богат и большинство из того, что обеспечивают сторонние компоненты, можно отыскать в его недрах.

Удачи вам!

Лозовюк Александр
Специально для Королевства Delphi
апрель 2001 г.
Новое поколение выбирает... MatrixWB - http://www.matrix-wb.h1.ru