Juri Shutenko Personal Homepage. Visual FoxPro.

VFP и Интернет. Часть 3. Готовы работать? Притормозите...

Итак, список функций WinAPI, необходимых для работы нам известен. Декларации приведены в предыдущей статье, описания - в соотвествующих статьях. Но кроме этого необходимо знать и соблюдать некоторые правила. Прежде всего, это касается последовательности вызовов функций. Что говорит по этому поводу MSDN?

До использования функций WinINet, приложение должно попытаться установить соединение с Internet с помощью функции InternetAttemptConnect. Эта функция либо вызовет диалоговое окно для инициализации соелинения с Internet, либо проверит наличие уже существующего соединения. Если вызов этой функции потерпит неудачу, приложение может перейти в отключенный режим (offline), что позволит ему обращаться к информации, которая была сохранена в кэше по время предыдущего соединения с Internet.

Далее для проверки соединения с Internet можно использовать функцию InternetCheckConnection. Функция попытается определить доступность сервера, определяемого из URL, который послан функции в качестве параметра, с помощью пинга. Если в вызове функции был установлен флаг FLAG_ICC_FORCE_CONNECTION, а в качестве URL был послан NULL, функция проверит не имеется ли входа в серверную базу данных ближайшего сервера. Если такой сервер существует, то функция выполнит пинг этого сервера.

Затем нужно использовать функцию InternetOpen для установки характеристик соединения с Internet, которые будет использовать клиентское приложение. InternetOpen создает корневой дескриптор HINTERNET, который используется для установки сессий по протоколам http, ftp и gopher. InternetOpen не тестирует соединение с интернет для проверки - корректны ли характеристики посланные ей в качестве параметров.

Для создания индивидуальных сессий используйте функцию InternetConnect. InternetConnect инициализирует сессию для конкретного сайта, используя посланные ей параметры, и создает новый дескриптор HINTERNET, который является сегментом корневого дескриптора, созданного вызовом функции InternetOpen. Функция InternetConnect не пытается обратиться или установить соединение к конкретному сайту, за исключением случаев сессий FTP. Функции FtpFindFirstFile, FtpOpenFile, GopherFindFirstFile, GopherOpenFile и HttpOpenRequest используют дескриптор, созданный вызовом InternetConnect для установки соединения с конкретным сайтом.

Посмотрим, что будет происходить на реальном компьютере. Для начала выполним первую рекомендацию - будем использовать функцию InternetCheckConnection для попытки установки соединения с Internet.

Вызов функции предельно прост, так как функция не принимает никаких параметров:

DECLARE integer InternetAttemptConnect IN WinInet
? InternetAttemptConnect()

Будем использовать компьютер, подключенный к Интернет через локальную сеть, на что указывает индикатор в system tray.

computer connected to Internet over LAN

Выполним приведенную выше программу.В результате исполнения этого кода - мы получим 0 (что эквивалентно ERROR_SUCCESS). Попытка соединения удалась.

InternetAttemptConnect show that computer has connection to Internet

Но так-ли это? Отсоединяем комьютер от сети

computer not connected to LAN

и повторно исполняем приведенную программку. В результате имеем тот же 0, при гарантированной невозможности подключения к всемирной сети.

Don't believe your eyes! Your computer succesfully made attempt to connect!

То есть, получается, что данная функция сообщает лишь о наличии настройки подключения к Интернет.

Тогда переходим ко второй рекомендуемой проверке, которая осуществляется с помощью функции InternetCheckConnection. Дополним приведенную выше программу:

CLEAR
#Define FLAG_ICC_FORCE_CONNECTION  0x00000001

Declare Integer GetLastError In kernel32
Declare Integer InternetAttemptConnect IN WinInet
Declare Integer InternetCheckConnection In wininet;
   STRING  lpszUrl,;
   INTEGER dwFlags,;
   INTEGER dwReserved

? "Result of calling InternetAttemptConnect... "
?? InternetAttemptConnect()

Local llCanConnect2Host, lnError, lcHost2Check

? "Checking http://kodu.neti.ee/~juri4... "

lcHost2Check="http://kodu.neti.ee/~juri4"+CHR(0)
llCanConnect2Host=;
   InternetCheckConnection(;
      lcHost2Check,;
      FLAG_ICC_FORCE_CONNECTION,;
      0;
   )
?? Iif(;
     llCanConnect2Host=0,;
     "Can't connect to host!",;
     "Connection may be successfully established!";
  )
lnError=GetLastError()
If lnError !=0
   ? "An error occurs on function call! Error number is:"
   ?? lnError
Endif
? 
? "Checking nearest server... "

llCanConnect2Host=;
   InternetCheckConnection(;
      .Null.,;
      FLAG_ICC_FORCE_CONNECTION,;
      0;
   )
?? Iif(;
     llCanConnect2Host=0,;
     "Can't connect to host!",;
     "Connection may be successfully established!";
  )
lnError=GetLastError()
If lnError !=0
   ? "An error occurs on function call! Error number is:"
   ?? lnError
Endif

? 
? "Checking unavailable host... "

lcHost2Check="http://192.168.0.2/"+CHR(0)
llCanConnect2Host=;
   InternetCheckConnection(;
      lcHost2Check,;
      FLAG_ICC_FORCE_CONNECTION,;
      0;
   )
?? Iif(;
     llCanConnect2Host=0,;
     "Can't connect to host!",;
     "Connection may be successfully established!";
  )
lnError=GetLastError()
If lnError !=0
   ? "An error occurs on function call! Error number is:"
   ?? lnError
Endif

Результат исполнения этой программы приведен на рисунке:

Result of the program execution.

Вызов функции с URL несуществующего сервера возвратил код ошибки 12002, которая указывает, что запрос прерван по истечении лимита времени (The request has timed out.)

Что имеем в итоге? Вызов первой функции уверил нас в том, что настройки для соединения с Интернет имеются, вызов второй - что интересующий нас сервер доступен. Осталось соединиться с Интернет. Для этого будем использовать функцию InternetOpen, которая вернет нам дескриптор соединения с Интернет. Взглянем на ее декларацию:

Declare Integer InternetOpen In WinInet ;
   String @lpcAgent, ;
   Integer nAccessType, ;
   String @lpcProxyName, ;
   String @lpcProxyBypass, ;
   Integer nFlags

Функция принимает пять параметров:

lpсAgent
Указатель на строку с нуль-терминатором (CHR(0)), которая указывает на имя приложения или сущности, вызывающего функции WinINet. Это имя используется как пользовательский агент в протоколе HTTP. Мы можем использовать здесь все, что угодно, например "Visual FoxPro Application".

nAccessType
Тип требующегося доступа. Этот параметр может принимать одно из перечисленных в таблице значений:

Символьная константа Hex-значение Dec-значение Описание
INTERNET_OPEN_TYPE_DIRECT 1 1 Разрешает имена всех хостов локально.
INTERNET_OPEN_TYPE_PRECONFIG 0 0 Запрашивает прокси или прямую конфигурацию из регистра.
INTERNET_OPEN_TYPE_PRECONFIG_WITH_NO_AUTOPROXY 4 4 Запрашивает проки или прямую конфигурацию из регистра и предотвращает использование стартовых Microsoft JScript или Internet Setup (INS) файлов.
INTERNET_OPEN_TYPE_PROXY 3 3 Направляет запрос прокси-серверу, в случае если не предоставлен лист обходов прокси-серверов и имени прокси-сервера нет списке прокси-серверов, которые можно обойти. В этом случае функция использует INTERNET_OPEN_TYPE_DIRECT.

@lpcProxyName
Указатель на строку с нуль-терминатором (CHR(0)), указывает имя прокси-сервера(серверов) для использования с соединением, когда доступ через прокси-сервер определен установкой параметра nAccessType в значение INTERNET_OPEN_TYPE_PROXY. Не используйте пустую строку, так как функция InternetOpen в таком случае будет использовать ее как имя прокси-сервера. Фукнции WinINet распознают только зафиксированные CERN типы прокси (только HTTP) и TIS FTP шлюзы (только FTP). Если в системе инсталлирован Microsoft Internet Explorer, эти функции, кроме того, поддерживают SOCKS - прокси. Запросы к FTP и Gopher могут быть выполнены через определенные CERN типы либо путем изменения их в запрос HTTP или путем использования функции InternetOpenUrl. Если параметр dwAccessType не установлен в значение INTERNET_OPEN_TYPE_PROXY, то этот параметр игнорируется и должен быть установлен в NULL.

@lpcProxyBypass
Указатель на строку с нуль-терминатором CHR(0), который определяет необязательный список имен хостов или IP адресов, или тех и других, запросы к которым не должны отправляться через прокси для случая, когда значение параметра nAccessType установлено в INTERNET_OPEN_TYPE_PROXY. Список может содержать модификаторы в виде звездочки. Не используйте пустую строку в качестве параметра, так как InternetOpen будет использовать ее как список обхода прокси-серверов. Если этот параметр указан как макро "<local>" в виде единственного члена списка, функция будет обходить любые имена хостов, которые не имеют в своем имени точки. Если же значение параметра nAccessType не установлено в INTERNET_OPEN_TYPE_PROXY, то этот параметр будет игнорирован и и его значение должно быть установлено в NULL.

nFlags
Опции. Этот параметр может представлять собой комбинацию значений, приведенных ниже в таблице.

Символьная константа Dec-значение Описание
INTERNET_FLAG_ASYNC 1 Выполняет только асинхронные запросы на дескрипторах по убывающей от дескриптора возвращенного этой функцией.
INTERNET_FLAG_FROM_CACHE 2 Не выполняет сетевых запросов. Все сущности возвращаются из кэша. Если запрашиваемый элемент не находится в кэше, то возвращается соответствующая подходящая ошибка, такая как ERROR_FILE_NOT_FOUND.
INTERNET_FLAG_OFFLINE 2 Идентично INTERNET_FLAG_FROM_CACHE. Не выполняет сетевых запросов. Все сущности возвращаются из кэша. Если запрашиваемый элемент не находится в кэше, то возвращается соответствующая подходящая ошибка, такая как ERROR_FILE_NOT_FOUND.

Смысл вызова этой функции - получить дескриптор соединения с Интернет и затем использовать его для вызова других функций, которым он требуется в качестве одного из параметров. Но прежде чем изменить нашу простенькую программку, посмотрим еще на одну функцию, которая также необходима в приложении. Это функция InternetCloseHandle. Назначение этой функции - закрыть дескриптор соединения с Интернет или дескприптор сессии, установленной ддя конкретного сайта. Ее декларация проста:

Declare Integer InternetCloseHandle In WinInet Integer nHandle

и требует передачи ей при вызове всего одного параметра - дескриптора соединия, который должен быть закрыт.

Изменим нашу простенькую программку так, как показано ниже. При этом мы не будем ипсользовать ни прокси-серверы, ни их обходов, ни флагов. Но укажем функции, что она должна использовать предустановки из регистра Windows, которые определены вами в диалоговом окне Internet Options панели управления.

Clear

#Define FLAG_ICC_FORCE_CONNECTION  0x00000001
#Define INTERNET_OPEN_TYPE_PRECONFIG 0

Declare Integer GetLastError In kernel32
Declare Integer InternetAttemptConnect In WinInet
Declare Integer InternetCheckConnection In wininet;
   STRING  lpcUrl,;
   INTEGER nFlags,;
   INTEGER nReserved
Declare Integer InternetOpen In WinInet ;
   String @lpcAgent, ;
   Integer nAccessType, ;
   String @lpcProxyName, ;
   String @lpcProxyBypass, ;
   Integer nFlags
Declare Integer InternetCloseHandle In WinInet Integer nHandle

If  InternetAttemptConnect() !=0
   =Messagebox(;
      "На данном компьютере не определены настройки для соединения с Интернет",;
      16,;
      "Warning!Connection to Internet cannot be established!";
      )
   Return
Endif

Local llCanConnect2Host, lnError, lcHost2Check,;
lpcAgent, lpcProxyName, lpcProxyBypass, lnFlags, lhInternet

lcHost2Check="http://kodu.neti.ee/~juri4"+Chr(0)
lpcAgent="Visual FoxPro Application"+Chr(0)
lpcProxyName=Chr(0)
lpcProxyBypass=Chr(0)
lnFlags=0

? "Checking http://kodu.neti.ee/~juri4... "

lcHost2Check="http://kodu.neti.ee/~juri4"+Chr(0)
llCanConnect2Host=;
   InternetCheckConnection(;
   lcHost2Check,;
   FLAG_ICC_FORCE_CONNECTION,;
   0;
   )

?? Iif(;
   llCanConnect2Host=0,;
   "Can't connect to host!",;
   "Connection may be successfully established!";
   )

lnError=GetLastError()
If lnError !=0
   ? "An error occurs on function call! Error number is:"
   ?? lnError
Endif

lhInternet=InternetOpen(;
   @lpcAgent, ;
   INTERNET_OPEN_TYPE_PRECONFIG,;
   @lpcProxyName,;
   @lpcProxyBypass,;
   lnFlags;
   )

If lhInternet<>0
   ? "We have handle of the Internet connection, that is "
   ?? lhInternet
   =InternetCloseHandle(lhInternet)
Else
   lnError=GetLastError()
   If lnError !=0
      ? "An error occurs on function call! Error number is:"
      ?? lnError
   Endif
Endif

В результате исполнения этой программы на своем компьютере я получил приведенный на рисунке результат.

Result of the program execution

Итак чему мы научились в этой статье? Трем вещам:

  • как подготовиться к открытию соединения с Интернет,
  • как открыть соединение и получить его дескриптор и
  • как закрыть соединение с Интерент.

Для чего все это нужно? Об этом в следующей статье, в которой мы начнем создавать базовый класс-обертку для работы с Интернет.

Cелектор для быстрого перехода на сайты, связанные с Visual FoxPro.