Интерфейс WinInet
Программный интерфейс WinInet предназначен для разработки 32-разрядных приложений. К сожалению, вы не сможете воспользоваться WinInet при создании 16-разрядных приложений для операционных систем Windows 3.хх.
В принципе вы можете применять приложения WinInet в среде операционных систем Windows 3.хх, если дополнительно установите Win32s. Однако в этом случае вы не должны пользоваться библиотекой классов MFC, потому что классы для работы с программным интерфейсом WinInet добавлены в MFC версии 4.2, а начиная с этой версии, приложения, подготовленные в Microsoft Visual C++ и MFC, не будут работать в среде Windows 3.хх с установленной поддержкой 32-разрядных приложений Win32s.
Функции WinInet являются реентерабельными. Поэтому вы свободно можете использовать их в многозадачных приложениях и не заботиться о синхронизации отдельных задач между собой.
В настоящее время функции WinInet располагаются в библиотеке динамической компоновки WININET.DLL. Эта библиотека поставляется вместе с новыми версиями операционных системам Windows.
Полную документацию по функциям программного интерфейса WinInet вы можете получить на сервере WWW фирмы Microsoft по адресу: http://www.microsoft.com/win32dev.
В нешей книге мы не станем рассмотривать функции программного интерфеса WinInet. Вместо этого мы изучим классы MFC, которые интегрируют в себе все возможности этого программного интерфейса.
Взаимодействие с сервером FTP
Серверы FTP предоставляют однин из самых распространенных типов сервиса Internet. Сервера FTP обычно хранят на своих дисках большое количество различных файлов, доступных пользователям сервера. Администратор сервера FTP может разграничить доступ к серверу FTP различным категориям пользователей. Так например, для всех желающих, которые подключаются к серверу FTP под именем anonymus, могут быть доступны только некоторые каталоги, содержащие файлы общего доступа. Чтобы получить доступ к другим файлам, администратор сервера должен зарегистрировать вас и дать вам имя и пароль для подключения к серверу.
В зависимости от того, какими правами вы обладаете, вы можете иметь право не только загружать файлы с сервера, но также и записывать файлы со своего компьютера на сервер FTP, а также изменять структуру каталогов самого сервера - создавать, удалять и переименовывать каталоги.
Надо отметить, что все операции, связанные с реорганизацией структуры каталогов сервера и даже с загрузкой данных на сервер как правило, недоступны обычным пользователям. Их выполняют только администратор сервера и его помощники. Поэтому, если у вас нет собственного FTP сервера, могут возникнуть трудности с отладкой приложений загружающих файлы на сервер. Если в вашем распоряжении есть локальная сеть, мы рекомендуем установить на ней свой сервер FTP и отлаживать свои программы в рамках локальной сети.
Как и любое другое приложение, использующее для работы с Internet классы WinInet, вы должны первым делом создать сеанс связи представленный объектом класса CInternetSession.
Затем вы должны выполнить соединение с сервером FTP. Для этого надо вызвать метод GetFtpConnection класса CInternetSession. Методу GetFtpConnection надо указать адрес сервера FTP. Если указанный сервер не будет обнаружен в сети, то данный метод вызовет исключение и завершится с ошибкой. Это может быть следствием того, что вы неправильно указали имя сервера или сервер не активен в данный момент времени.
В случае успешного завершения, метод GetFtpConnection создает объект класса CFtpConnection. Этот объект будет представлять в вашем приложении указанный сервер FTP.
Вызывая методы класса CFtpConnection ваше приложение может определить и изменить текущий каталог сервера, выполнять поиск файлов и каталогов с определенными именами, обмениваться с сервером файлами, удалять и переименовывать файлы, изменять структуру каталогов - создавать, переименовывать и удалять каталоги и т. д.
Так, чтобы определить и изменить путь текущего каталога на сервере FTP надо воспользоваться методами GetCurrentDirector и SetCurrentDirectory класса CFtpConnection. Создать каталог вы можете при помощи метода CreateDirectory, удалить с помощью метода RemoveDirectory. Другие методы класса CFtpConnection, предназначенные для работы с системой каталогов сервера, вы можете просмотреть в разделе “Методы для управления каталогами”.
Чтобы загрузить файл с сервера FTP вы можете обратится к методу GetFile, а чтобы загрузить файл на сервер - к методу PutFile класса CFtpConnection. Эти методы работают как команда COPY операционной системы MS-DOS. Вы указываете им только имя файла на диске локального компьютера и имя файла на сервере. Все остальное они делают самостоятельно.
Вы также можете открыть файл на сервере FTP с помощью метода OpenFile класса CFtpConnection. Если указанный файл удалось открыть, этот метод возвращает объект класса CInternetFile. Далее вы можете использовать методы Read и Write данного класса чтобы прочитать или записать открытый файл.
Если у вас есть соответствующие права на данном сервере FTP, вы можете переименовать файлы на сервере или удалить их. Для этого надо использовать методы Rename и Remove класса CFtpConnection.
Как только приложение установило соединение с сервером FTP, вы можете просмотреть содержимое указанного каталога или попытаться найти на сервере файлы с определенным именем. Для этого надо создать объект класса CFtpFileFind, указав конструктору класса объект класса CFtpConnection, представляющий соединение с сервером. Затем с помощью методов FindFile и FindNextFile вы можете осуществить поиск файлов и каталогов с указанными именами. С помощью методов класса CFileFind, являющегося базовым классом для CFtpFileFind, вы можете определить различные характеристики обнаруженных файлов и каталогов.
В следующем разделе мы предложим вашему вниманию приложение ConsoleFtp, которое выполняет соединение с указанным сервером FTP. Вы можете использовать исходный текст этого приложения как шаблон для изучения основных приемов работы с серверами FTP.
Взаимодействие с сервером WWW
Сервера WWW предоставляют пользователям возможность просмотра гипертекстовой информации. Вся информация, расположенная на сервере, разделена на небольшие страницы.
Когда вы соединяетесь с сервером WWW с помощью какой-нибудь программы навигатора, например Microsoft Internet Explorer или Netscape Navigator, то вы увидите, что страницы могут содержать не только форматированный текст и гипертекстовые ссылки, но также рисунки, аудио и видео информацию. Некоторые страницы даже могут содержать органы управления диалоговых панелей - поля ввода, кнопки, переключатели.
Как же удается сочетать столь разнообразную информацию в одном документе? Оказывается сами страницы, адрес которых вы указываете навигатору, содержат описание на языке разметки гипертекста HTML (Hyper Text Markup Language) и хранятся в файлах с расширениями htm или html. Навигатор загружает файл страницы, а затем интерпретирует его и отображает на экране. При этом он, возможно, будет загружать и другие файлы с сервера, например файлы изображений или анимации.
В листинге 3.1 представлен пример страницы WWW, содержащей в себе текст, изображение и ссылки на другие страницы WWW (это главная рускоязычная страница нашего сервера WWW).
Листинг 3.1. Файл main.htm
<HTML>
<BODY BGCOLOR="#FFFFFF">
<BGSOUND SRC="../midi/bach.mid"></BGSOUND>
<!-- <embed src="../midi/bach.mid" width=2 height=2 hidden="yes"
autostart="true" loop=1> -->
<H2>Добро пожаловать на наш сервер WEB!</H2>
<P>На этом сервере вы можете найти подробную информацию
о наших книгах из серий "Персональный компьютер.
Шаг за шагом" и "Библиотека системного программиста":
<UL>
<LI>аннотации и оглавления;
<LI>исходные тексты программ, опубликованных в книгах;
<LI>наши планы на будущее;
<LI>список ошибок, замеченных в наших книгах;
<LI>информацию о наших друзьях;
<LI>бесплатные книги, доступные в режиме online
</UL>
Эти серии книг предназначенны для самого широкого
круга людей, чья работа связана с компьютерами.
<P>Мы подготовили для вас и кое-что еще!
<CENTER><HR>
Эту страницу лучше всего просматривать навигаторами MS Internet Explorer v3.0 или Netscape Navigator
<TABLE><TR><TD>
<A HREF="http://www.microsoft.com/ie"><IMG SRC="ieanim.gif"
ALT="MS Internet Explorer v3.0" BORDER=0></A>
</TD><TD>
<A HREF="http://home.netscape.com"><IMG SRC="netnow3.gif
" ALT="Netscape Navigator" BORDER=0></A>
</TD></TR></TABLE>
<P><IMG SRC="http://www.dials.ccas.ru/scripts/w3count.exe?frolov1"
ALIGN=bottom><BR>
<FONT SIZE=2>Посылайте ваши комментарии по адресу
<A HREF="mailto:frolov@glas.apc.org" >frolov@glas.apc.org</A></FONT>
<BR><FONT SIZE=1>© Александр Фролов, Григорий Фролов, 1997</FONT>
</CENTER>
</BODY>
</HTML>
Как видите, исходный текст страницы WWW, хранящийся на сервере, имеет мало общего с изображением этой странице в окне навигатора. Чтобы вывести страницу на экран, навигатор проделывает большую работу. Он загружает все необходимые файлы изображений, аудио и видео, которые включены в данную страницу, а затем отображает страницу на экране, руководствуясь операторами языка HTML.
¨ Описание языка HTML и процедуры создания страниц WWW вы можете найти в 29 томе серии “Библиотека системного программиста”, который называется “Сервер WEB своими руками”.
Самостоятельная обработка исходных файлов HTML достаточно проста, хотя и требует очень большой и кропотливой работы, так как по сути, вам будет нужно создать интерпретатор языка HTML. Чтобы не загромождать исходные тексты наших приложений, мы не будем обрабатывать полученные страницы WWW, а основное внимание уделим процедуре взаимодействия с сервером.
Если ваше приложение должно загружать с сервера страницы WWW и отображать их на экране, не выполняя дополнительной обработки, вы можете воспользоваться органом управления Microsoft Web Browser Control. Мы расскажем про этот орган управления в главе “Ваш собственный Internet Explorer”.
Сначала необходимо инициализировать сеанс связи с Internet. Для этого надо создать объект класса CInternetSession, или класса наследованного от CInternetSession.
Затем вы должны открыть соединение с сервером WWW. Для этого надо вызвать метод GetHttpConnection класса CInternetSession. Методу GetHttpConnection указывается адрес сервера WWW. Он создает объект класса CHttpConnection. Этот объект будет представлять в вашем приложении указанный сервер WWW.
В отличие от метода GetFtpConnection класса CInternetSession, рассмотренного нами ранее, GetHttpConnection на самом деле не выполняет настоящего соединения с сервером. Поэтому даже если указать ему имя несуществующего сервера, он создаст объект класса CHttpConnection без сообщения об ошибке. Настоящее соединение с сервером будет установлено значительно позже, во время передачи серверу WWW запроса.
Теперь надо создать (открыть) и подготовить запрос для передачи серверу. Для этого вызвите метод OpenRequest класса CHttpConnection. Он создаст объект класса CHttpFile. Вы можете добавить к созданному запросу дополнительные заголовки. Для этого надо воспользоваться методом AddRequestHeaders класса CHttpFile.
Когда запрос полностью сформирован, его следует передать серверу с помощью метода SendRequest класса CHttpFile. Этот метод передает запрос указанному серверу. Именно в это время устанавливается сетевое соединение. Если запрос передан успешно, тогда метод SendRequest возвращает значение TRUE. Если указанный сервер не существует или на нем отсутствует запрашиваемый файл - возвращается значение FALSE и может быть вызвано исключение CInternetException.
Далее следует получить ответ на запрос от сервера. Для этого вызовите метод QueryInfo класса CHttpFile. В некоторых случаях, когда надо только проверить существует ли страница с указанным адресом этого уже достаточно.
Если же вам необходимо загрузить страницу с сервера на локальный компьютер, вы можете воспользоваться методом Read. Этот метод определен в классе CInternetFile, который является базовым для класса CHttpFile.
Если во время чтения файла прервется связь с сервером или произойдут другие непредвиденные события, то метод Read может вызвать исключение CInternetException. Чтобы приложение правильно обрабатывало ошибки WinInet, вы должны поместить все методы, которые могут вызвать исключение в блок try и определить для него соответствующий блок catch.
В следующем разделе мы предложим вашему вниманию приложение ConsoleHTTP, которое выполняет соединение с указанным сервером WWW. Используйте исходный текст этого приложения как шаблон для изучения основных приемов работы с серверами WWW.
Ваш собственный Internet Explorer
Для просмотра серверов Internet используются специальные программы - навигаторы. Сегодня вы можете встретить много различных навигаторов, однако наиболее часто используются Microsoft Internet Explorer и Netscape Navigator.
Навигаторы представляют собой весьма сложные программы. Достаточно сказать, что они должны уметь работать с протоколами передачи данных TCP/IP, протоколом передачи гипертекста HTTP, протоком передачи файлов FTP. Навигатор также должен уметь правильно отображать принятые данные на экране. Он должен понимать данные в формате HTML, уметь отображать на экране графические файлы, использовать органы управления ActiveX, исполнять аплеты на языке Java и т. д. (рис. 4.1).
Рис. 4.1. Microsoft Internet Explorer
Основу навигатора Microsoft Internet Explorer составляют несколько библиотек dll, в которых определены объекты ActiveX. Именно они несут на себе основную нагрузку - взаимодействуют с серверами, отображают страницы WWW на экране и т. д. Окно навигатора вместе с меню панелями управления и состояния - не более чем простая оболочка и не несет на себе никакой функциональной нагрузки.
Самое замечательное в этом то, что вы можете воспользоваться ядром Microsoft Internet Explorer и в своих собственных приложениях. Для этого достаточно подключить соответствующий орган управления Microsoft Web Browser Control к проекту и вы сможете использовать его как другие органы управления, например кнопки, поля редактирования, списки и т. д.
В следующем разделе мы представим вашему вниманию приложение Look. В нем мы будем использовать орган управления Microsoft Web Browser Control, чтобы создать свой маленький, но работающий навигатор Internet.
Ссылки на ресурсы Internet
Во многих случаях нет необходимости встраивать навигатор непосредственно в приложение. Как правило достаточно ограничиться возможностью запуска навигатора из программы с переходом к нужному ресурсу.
Примером такого приложения может служить Microsoft Visual C++. Выверите из меню Help строку Web Favorites. На экране появится диалоговая панель Web Favorites (рис. 5.1). В списке Name перечислены ссылки на различные ресурсы Internet, которые могут быть интересны для программистов. Вы можете выбрать название любого ресурса из списка и нажать на кнопку Go To чтобы получить к нему доступ. Загрузится Internet Explorer, или другой навигатор, установленный в компьютере, и вы сможете просмотреть выбранный ресурс.
Рис. 5.1. Диалоговая панель Web Favorites
Кнопки New, Edit и Delete служат для редактирования списка ресурсов Internet. Они позволяют добавить новую ссылку, отредактировать уже существующую ссылку и удалить ссылку из списка.
Для загрузки ресурса Internet можно воспользоваться функциями ShellExecute или WinExec. В качестве примера мы привели приложение WebHelp. Справочная информация для приложения WebHelp доступна через Internet по адресу http://www.dials.ccas.ru/frolov/rwin/webhelp.htm.
Адреса URL
Ресурсы, доступные через сеть Internet, определяются посредством универсальных адресов ресурсов или просто адресов (URL - Universal Resource Locators или Uniform Resource Locators). Адрес URL определяет имя сервера на котором расположен ресурс, имя объекта и каталог где этот ресурс находится, протокол для взаимодействия с сервером и номер порта TCP/IP на котором происходит соединение.
Общий формат адресов URL представлен ниже:
service://server:port/dir/dir/object.ext
Поле service определяет протокол для работы с сервером. Сразу после названия протокола следует символ двоеточия и два обратных слеша.
Затем идет поле server. Оно содержит название сервера, соответствующего данному адресу.
После имени сервера может располагаться номер порта TCP/IP. Это числовое значение перед которым надо указать символ двоеточия. Данное поле необязательное. Если вы не укажете номер порта TCP/IP, то будет использоваться порт принятый по умолчанию для данного протокола.
Непосредственно за номером порта TCP/IP или сразу после имени сервера (если номер порта TCP/IP не задан) следует путь каталога и имя объекта на который ссылается адрес. В качестве имени объекта может фигурировать имя файла, имя расширения CGI или ISAPI.
Аннотация
Книга посвящена программированию в среде Microsoft Visual C++ с использованием библиотеки классов MFC. В ней рассказывается о разработке приложений для работы в глобальной сети Internet и корпоративных сетях Intranet на основе программного интерфейса WinInet и соответствующих классов MFC.
Рассматриваются возможности создания программ навигаторов с использованием органа управления Microsoft Web Browser. На представленном примере вы узнаете, как использовать органы управления ActiveX в своих приложениях.
Затрагиваются вопросы использования стандартных органов управления Windows 95. Приводятся начальные сведения об использовании мультизадачности в приложениях MFC.
Асинхронный режим WinInet
К сожалению, классы WinInet имеют один недостаток. Большинство операций по взаимодействию с сетью Internet занимают много времени. Даже процедура соединения с сервером может занять несколько десятков секунд. Мы уже не говорим о загрузки с серверов FTP файлов большого размера. Даже если вы имеете соединение с Internet через высокоскоростной модем, получение файла с размерами в несколько мегабайт займет несколько десятков минут.
В самом простом случае классы WinInet используются в синхронном режиме, вызывая соответствующие методы классов непосредственно из основной задачи приложения. Естественно, пользовательский интерфейс приложения в этом случае блокируется. Мало того, что пользователь не сможет работать с таким приложением во время загрузки файла, если вы переключитесь в это время на другое приложение, открыв его окно поверх окна приложения работающего с Internet, а затем попытаетесь переключится обратно, то окно приложения не будет восстановлено.
Иллюстрацией вышесказанного может быть приложение FtpView, описанное нами в разделе “Загрузка файлов с сервера FTP”. Соединитесь с его помощью с каким-либо сервером FTP и попытайтесь загрузить файл большого размера. Вы увидите что в этом случае пользовательский интерфейс приложения блокируется и окно приложения не перерисовывается.
Существует две возможности выхода из этой ситуации.
Во-первых, можно организовать в рамках приложения еще одину задачу, и все вызовы методов WinInet, которые могут занять много времени выполнять именно из нее. При этом основная задача приложения останется свободеной и пользовательский интерфейс блокироваться не будет.
Во-вторых, можно использовать WinInet в асинхронном режиме. При этом методы классов WinInet будут сразу возвращать управление еще до того как соответствующая операция завершится. Возникает вопрос, как же приложение узнает о том что длительная асинхронная операция наконец-то завершилась и можно продолжить работу приложения далее?
Программный интерфейс WinInet извещает приложение о завершении асинхронной операции через специальную функцию обратного вызова. Если вы используете классы MFC, управляющие WinInet, вы можете воспользоваться виртуальным методом OnStatusCallback класса CInternetSession, который вызывается функцией обратного вызова WinInet.
¨ Метод OnStatusCallback также может использоваться и в том случае, если вы вызываете методы WinInet в синхронном режиме. В этом случае OnStatusCallback позволит вашему приложению сообщать пользователю более подробную информацию о исполнении текущей операции
Чтобы воспользоваться методом OnStatusCallback, вы должны наследовать от класса CInternetSession собственный класс, переопределив в нем этот метод.
Конструктор класса CInternetSession имеет параметр, через который ему передаются флаги, управляющие режимами работы данного сеанса связи. Если вы желаете чтобы операции данного сеанса связи исполнялись в асинхронном режиме, вы должны указать конструктору флаг INTERNET_FLAG_ASYNC.
После того как вы создадите объект этого класса, представляющий сеанс связи, вы должны вызвать метод EnableStatusCallback чтобы разрешить использование метода OnStatusCallback.
Теперь дальнейшие вызовы методов классов WinInet могут завершиться с ошибкой ERROR_IO_PENDING, означающей что операция выполняется в асинхронном режиме. Когда асинхронная операция завершится, будет вызван метод OnStatusCallback с кодом завершения INTERNET_STATUS_REQUEST_COMPLETE. Сразу заметим, что метод OnStatusCallback вызывается не только по завершении асинхронной операции. Этот метод также может вызываться раньше и сигнализирует о выполнении какой либо конкретной фазы асинхронной операции.
Метод OnStatusCallback имеет несколько параметров, которые определяют текущее состояние исполняемой операции WinInet. Один и тот же метод OnStatusCallback вызывается для всех асинхронных операций, исполняемых в рамках данного сеанса связи. Чтобы иметь возможность различать, какая операция вызвала метод OnStatusCallback, ему передается идентификатор контекста. Идентификатор контекста является числом типа DWORD и указывается при вызове многих методов классов WinInet. По умолчанию, идентификатор контекста принимается равным единице.
Теперь, когда вы получили общее представление об устройстве приложений WinInet, мы опишем соответствующие классы MFC. Мы будем подробно рассматривать только наиболее важные методы этих классов, которые впоследствии будут использоваться в наших приложениях. Описание остальных методов вы найдете в справочной системе Microsoft Visual C++.
Мы также рекомендуем вам ознакомиться с исходными текстами интересующих вас методов. В них вы сможете найти ответы на многие свои вопросы. Некоторые программисты даже считают исходные тексты MFC самой лучшей документацией к этой библиотеке. Вам также потребуется описание программного интерфейса WinInet, которое вы можете найти на сервере WWW Microsoft по адресу http://www.microsoft.com/workshoop/prog/sdk/docs/wininet/.
Благодарности
Большую помощь нам оказал сотрудник Microsoft АО Юрий Тумашко, предоставивший для работы над этой книгой дистрибутив Microsoft Visual C++ версии 4.2.
Авторы выражают благодарность Фроловой Ольге Викторовне, Кустову Виктору. Мы также благодарим всех сотрудников издательского отдела АО "ДИАЛОГ-МИФИ": Голубева Олега Александровича, Дмитриеву Наталью, Виноградову Елену, Кузьминову Оксану.
Поддержку в работе над книгами нам оказали генеральный директор АО “ДиалогНаука” Антимонов Сергей Григорьевич и руководитель антивирусного отдела АО “ДиалогНаука” Лященко Юрий Павлович, предоставившие доступ к сети Internet и позволившие нам разместить у них свой сервер WWW.
Блокировка кнопок
Теперь нам надо добавить программный код, выполняющий блокировку кнопок. Для этого мы будем использовать метод EnableWindow базового класса CWnd (Класс CButton наследуется от базового класса CWnd).
BOOL EnableWindow(BOOL bEnable = TRUE);
Этот метод имеет единственный необязательный параметр, который задает новое состояние кнопки. Если параметр bEnable не указан или равен TRUE, тогда кнопка становится доступна, а если FALSE - кнопка блокируется.
Значение второго параметра метода OnCommandStateChangeExplorer, принадлежащего классу CBrowserDlg, можно непосредственно передавать параметру bEnable метода EnableWindow данной кнопки.
Переопределите метод OnCommandStateChangeExplorer класса CBrowserDlg, опять же используя для этого средства MFC ClassWizard. Загрузите полученный шаблон метода OnCommandStateChangeExplorer в редактор и дополните его в соответствии со следующим листингом:
void CBrowserDlg::OnCommandStateChangeExplorer(
long Command,
BOOL Enable
)
{
switch(Command)
{
case CSC_NAVIGATEFORWARD:
// Меняем состояние кнопки Forward
m_Forward.EnableWindow(Enable);
break;
case CSC_NAVIGATEBACK:
// Меняем состояние кнопки Back
m_Back.EnableWindow(Enable);
break;
}
}
В представленном выше программном коде мы не проверяем значение параметра Command на равенство значению CSC_UPDATECOMMANDS. Метод OnCommandStateChangeExplorer вызывается с этим значением, если изменилось состояние кнопок панели управления.
Постройте полученное приложение и запустите его на выполнение. Теперь вы заметите, что кнопки Back и Forward будут автоматически блокироваться по мере необходимости и предупреждающее сообщение, представленное на рисунке 3.3 больше не появится.
После прочтения главы об органе управления Microsoft Web Browser Control у вас может появиться вполне резонный вопрос - а зачем вообще нужно создавать свою программу просмотра, если можно просто использовать готовое приложение Internet Explorer без всякого дополнительного программирования.
Безусловно, создавать свой Internet Explorer не имеет особого смысла. Эта задача успешно решена Microsoft. Однако, если вы разрабатываете приложения для компьютерной сети в рамках своего предприятия, преимущества налицо. Вы, например, можете легко интегрировать средства WWW в свое приложение и позволить пользователю просматривать только определенные ресурсы сети.
Чтение файла с серверов сети Internet
В этом случае вы можете сразу вызвать метод OpenURL класса CInternetSession. Он выполнит соединение с указанным ему сервером и создаст объект класса CInternetFile, соответствующий необходимому вам файлу.
Далее вы можете воспользоваться методами класса CInternetFile, чтобы прочитать данный файл с сервера на локальный компьютер. Для этой цели вы можете вызвать метод Read, который читает файл и записывает считанные данные в буфер, или метод ReadString, который считывает из файла текстовую строку, ограниченную символом перевода строки.
Описанный метод получения файла не позволяет выполнить обратную задачу - записать файл на сервер FTP. Серверы WWW и Gopher такую операцию не допускают в любом случае. От них вы можете только получать информацию.
Деструктор класса CFtpViewDlg
Когда пользователь нажимает кнопку OK и закрывает диалоговую панель, вызывается деструктор класса CFtpViewDlg. Он последовательно закрывает соединение с сервером FTP и завершает сеанс связи с Internet.
Деструктор проверяет установлено ли соединение с сервером FTP - при этом указатель m_FtpConnection должен быть не равен значению NULL. Если это так, сначала вызывается метод Close, закрывающий соединение, а затем удаляется сам объект m_FtpConnection:
if (m_FtpConnection != NULL)
{
m_FtpConnection -> Close();
delete m_FtpConnection;
}
После того, как соединение с сервером FTP закрыто, завершаем сеанс связи с Internet. Для этого вызываем метод Close, а затем удаляем объект m_InternetSession:
if (m_InternetSession != NULL)
{
m_InternetSession -> Close();
delete m_InternetSession;
}
В завершение деструктор класса CFtpViewDlg удаляет список изображений m_ImageList:
delete m_ImageList;
Для самостоятельного изучения
Естественно, что самую полную и свежую информацию о программировании для Internet можно найти на серверах этой сети. Приложив немного усилий, вы легко получите из Internet сведения о самых последних разработках ведущих фирм, занимающихся программным обеспечением.
В сети вы найдете описания различных стандартов протоколов, программных интерфейсов, технические статьи и даже примеры программ с исходными текстами. Для поиска информации в сети мы рекомендуем вам воспользоваться специальными поисковыми серверами. Адреса наиболее популярных поисковых серверов вы найдете в следующей таблице:
Поисковый сервер | Адрес | ||
Lycos | http://www.lycos.com | ||
Magellan | http://www.magellan.com | ||
Yahoo | http://www.yahoo.com | ||
Microsoft | http://www.microsoft.com/search/ | ||
AltaVista | http://www.altavista.com | ||
Excite | http://www.excite.com | ||
NetGuide | http://www.netguide.com |
Сервер WWW фирмы Microsoft содержит специальную страницу, позволяющую провести поиск данных с использованием нескольких (на выбор) поисковых серверов. Адрес этой страницы http://home.microsoft.com/access/allinone.asp. Если у вас установлен навигатор Microsoft Internet Explorer, то вы можете перейти на эту страницу, выбрав из меню Go строку Search the Web, или просто нажав кнопку Search в главной панели инструментов.
Навигатор Microsoft Internet Explorer, орган управления Microsoft Web Browser Control, программный интерфейс WinInet и набор классов MFC для управления WinInet, ActiveX SDK - это далеко не полный перечень разработок Microsoft, связанных с технологиями Internet. Вы можете получить информацию или даже сами эти продукты непосредственно с серверов WWW и FTP фирмы Microsoft. Ниже мы приводим несколько адресов, которые будут вам полезны:
Адрес | Содержание | ||
http://www.microsoft.com/visualc/ | Страница Microsoft Visual C++ | ||
http://www.microsoft.com/intdev/sdk/ | Описание органа управления Microsoft Web Browser Control | ||
http://www.microsoft.com/ie/ | Навигатор Microsoft Internet Explorer | ||
http://www.microsoft.com/intdev/sdk/ | ActiveX SDK | ||
http://www.microsoft.com/intdev/sdk/ | Документация по программному интерфейсу WinInet |
Большое количество полезных документов расположено на сервере ds.internic.net. Здесь вы найдете описание протокола HTTP, универсальных ресурсов URL, URI и URN, формата MIME, системы доменных имен и множество другой полезной информации. Документам присвоены номера RFC, указанные в названии соответствующих файлов. Список этих документов расположен в файле http://ds.internic.net/rfc/rfc.txt.
Следующая табица содержит адреса и краткие описания ряда документов RFC:
Адрес |
Содержание |
http://ds.internic.net/rfc/rfc1630.txt |
Описание формата URI |
http://ds.internic.net/rfc/rfc1738.txt |
Описание формата URL |
http://ds.internic.net/rfc/rfc1945.txt |
Описание протокола HTTP 1.0 |
http://ds.internic.net/rfc/rfc1341.txt |
Формат MIME |
http://ds.internic.net/rfc/rfc1034.txt |
Доменная система имен |
¨ Путешествуя в сети Internet по указанным нами адресам, вы должны иметь в виду, что серверы могут быть закрыты, могут сменить адрес или тематику
В Internet существует множество серверов, посвященных программистам, использующим Microsoft Visual C++ и библиотеку классов MFC. На них вы найдете ответы на вопросы, статьи и другую полезную информацию. В следующей таблице представлены некоторые адреса таких серверов:
Адрес |
Содержание |
http://www.iftech.com |
Обучение |
http://www.mcp.com |
Издательство |
http://www.visionx.com |
Сервер The MFC Professional |
http://www.vcdj.com/default.htm |
Журнал Visual C++ Developers Journal |
Добавление программного кода
После того как вы подготовили главную диалоговую панель приложения Look и привязали к органам управления этой панели соответствующие переменные, надо добавить к классу CLookDlg ряд методов, которые будут обрабатывать сообщения от диалоговой панели. Вы должны добавить методы, обрабатывающие сообщения от кнопок Navigate (IDC_NAVIGATE), Stop (IDC_BUTTON_STOP), Refresh (IDC_BUTTON_REFRESH), Exit (IDOK), от списка с адресами серверов Internet (IDC_COMBO_ADDRESS) и от объекта навигатора (IDC_EXPLORER).
Чтобы добавить все эти методы мы рекомендуем вам воспользоваться средствами MFC ClassWizard. Для этого надо запустить MFC ClassWizard, в диалоговой панели MFC ClassWizard выбрать страницу Message Map. Затем из списка Class name выберите имя класса CLookDlg. К этому классу мы будем добавлять все наши методы.
Из списка Object IDs выбирайте идентификаторы кнопок, списка и навигатора, сообщения от которых надо обрабатывать. При этом в списке Messages будет отображаться список сообщений, которые этот орган управления вырабатывает и методов которые вызываются при определенных условиях. Чтобы добавить новый метод, выберите из списка Messages идентификатор сообщения или название метода которые надо обработать или переопределить и нажмите кнопку Add Function. Вам будет предложено определить название метода. Вы можете оставить его по умолчанию или изменить по своему усмотрению.
Так, вы должны добавить к классу CLookDlg методы для обработки командных сообщений BN_CLICKED от кнопок Navigate (IDC_NAVIGATE), Stop (IDC_BUTTON_STOP), Refresh (IDC_BUTTON_REFRESH). Примите предложение MFC ClassWizard и назовите соответствующие методы именами OnButtonNavigate, OnButtonStop и OnButtonRefresh.
Для списка IDC_COMBO_ADDRESS вы должны назначить обработчик сообщения с кодом идентификации CBN_SELCHANGE. Это сообщение передается диалоговой панели, когда пользователь выбирает из списка новый элемент. Назовите этот метод OnSelchangeComboAddress.
Рис. 4.11. Орган управления Microsoft Web Browser и MFC ClassWizard
Теперь вам надо переназначить ряд методов, которые вызываются навигатором IDC_EXPLORER. Выберите из списка Object IDs идентификатор IDC_EXPLORER. В списке Messages появятся названия методов, которые вы можете переназначить (рис. 4.11). Обратите внимание, когда вы выбираете строки из списка Messages, то ниже списка Member function в поле Description отображается краткое описание данного метода.
Вы должны переопределить следующие методы - DownloadBegin, DownloadComplete, ProgressChange, BeforeNavigate, FrameBeforeNavigate, TitleChange, Quit, StatusTextChange и NavigateComplete. Для каждого из них MFC ClassWizard предложит собственное название. Согласитесь со всеми предложенными названиями. В следующей таблице мы привели соответствие названий событий в списке Messages и названий методов, которые их обрабатывают:
Строка Messages |
Метод-обработчик |
DownloadBegin |
OnDownloadBeginExplorer |
DownloadComplete |
OnDownloadCompleteExplorer |
ProgressChange |
OnProgressChangeExplorer |
TitleChange |
OnTitleChangeExplorer |
StatusTextChange |
OnStatusTextChangeExplorer |
NavigateComplete |
OnNavigateCompleteExplorer |
Определение класса CLookDlg содержится во включаемом файле LookDlg.h. Мы привели исходный текст файла LookDlg.h в листинге 4.7.
Листинг 4.7. Файл LookDlg.h
//////////////////////////////////////////////////////////////
// CLookDlg dialog
//{{AFX_INCLUDES()
#include "webbrowser.h"
//}}AFX_INCLUDES
class CLookDlg : public CDialog
{
// Construction
public:
CLookDlg(CWnd* pParent = NULL); // standard constructor
// Dialog Data
//{{AFX_DATA(CLookDlg)
enum { IDD = IDD_LOOK_DIALOG };
CProgressCtrl m_Progress;
CWebBrowser m_explorer;
CString m_address;
CString m_StatusText;
CString m_TitleBar;
//}}AFX_DATA
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CLookDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX);
//}}AFX_VIRTUAL
// Implementation
protected:
HICON m_hIcon;
// Generated message map functions
//{{AFX_MSG(CLookDlg)
virtual BOOL OnInitDialog();
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
afx_msg void OnSelchangeComboAddress();
afx_msg void OnButtonRefresh();
afx_msg void OnButtonStop();
afx_msg void OnButtonBack();
afx_msg void OnButtonNext();
afx_msg void OnDownloadBeginExplorer();
afx_msg void OnDownloadCompleteExplorer();
afx_msg void OnProgressChangeExplorer(long Progress,
long ProgressMax);
afx_msg void OnTitleChangeExplorer(LPCTSTR Text);
afx_msg void OnStatusTextChangeExplorer(LPCTSTR Text);
afx_msg void OnNavigate();
afx_msg void OnNavigateCompleteExplorer(LPCTSTR URL);
DECLARE_EVENTSINK_MAP()
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
Вы должны самостоятельно доработать все новые методы, только что добавленные MFC ClassWizard к классу CLookDlg, в соответствии с листингом 3.3.
Определение методов класса CLookDlg и таблица сообщений этого класса содержатся в файле LookDlg.cpp. Кроме того файл LookDlg.cpp содержит конструкцию, которая ранее не встречалась в наших приложениях.
Исходный текст файла LookDlg.cpp приведен нами в листинге 4.8.
Листинг 4.8. Файл LookDlg.cpp
#include "stdafx.h"
#include "Look.h"
#include "LookDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
//////////////////////////////////////////////////////////////
// Конструктор класса CLookDlg
CLookDlg::CLookDlg(CWnd* pParent /*=NULL*/)
: CDialog(CLookDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CLookDlg)
m_address = _T("");
m_StatusText = _T("");
m_TitleBar = _T("");
//}}AFX_DATA_INIT
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
//////////////////////////////////////////////////////////////
// Метод DoDataExchange класса CLookDlg.
// Организует взаимодействие между органами управления
// диалоговой панели и привязанными к ним элементами класса
void CLookDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CLookDlg)
DDX_Control(pDX, IDC_PROGRESS, m_Progress);
DDX_Control(pDX, IDC_EXPLORER, m_explorer);
DDX_CBString(pDX, IDC_COMBO_ADDRESS, m_address);
DDX_Text(pDX, IDC_STATUS_TEXT, m_StatusText);
DDX_Text(pDX, IDC_TITLE_BAR, m_TitleBar);
//}}AFX_DATA_MAP
}
//////////////////////////////////////////////////////////////
// Таблица сообщений класса CLookDlg
BEGIN_MESSAGE_MAP(CLookDlg, CDialog)
//{{AFX_MSG_MAP(CLookDlg)
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_CBN_SELCHANGE(IDC_COMBO_ADDRESS,
OnSelchangeComboAddress)
ON_BN_CLICKED(IDC_BUTTON_REFRESH, OnButtonRefresh)
ON_BN_CLICKED(IDC_BUTTON_STOP, OnButtonStop)
ON_BN_CLICKED(IDC_BUTTON_BACK, OnButtonBack)
ON_BN_CLICKED(IDC_BUTTON_NEXT, OnButtonNext)
ON_BN_CLICKED(IDC_NAVIGATE, OnNavigate)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
//////////////////////////////////////////////////////////////
// Метод OnInitDialog класса CLookDlg
BOOL CLookDlg::OnInitDialog()
{
CDialog::OnInitDialog();
SetIcon(m_hIcon, TRUE);
SetIcon(m_hIcon, FALSE);
return TRUE;
}
//////////////////////////////////////////////////////////////
// Метод OnPaint класса CLookDlg
void CLookDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND,
(WPARAM) dc.GetSafeHdc(), 0);
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
}
//////////////////////////////////////////////////////////////
// Метод OnQueryDragIcon класса CLookDlg
HCURSOR CLookDlg::OnQueryDragIcon()
{
return (HCURSOR) m_hIcon;
}
//////////////////////////////////////////////////////////////
// Метод OnSelchangeComboAddress класса CLookDlg.
// Вызывается при выборе нового адреса из списка
void CLookDlg::OnSelchangeComboAddress()
{
// Определяем адрес, выбранный из списка
UpdateData(TRUE);
// Переходим к просмотру соответствующего ресурса
m_explorer.Navigate(
m_address, // Адрес URL для просмотра
NULL, // Дополнительные флаги
NULL, // Имя (frame name) ресурса
NULL, // Данные для запроса POST
NULL // Заголовок запроса HTTP
);
}
//////////////////////////////////////////////////////////////
// Метод OnButtonRefresh класса CLookDlg. Обновить
// текущую страницу WWW, которая отображается навигатором
void CLookDlg::OnButtonRefresh()
{
m_explorer.Refresh();
}
//////////////////////////////////////////////////////////////
// Метод OnButtonStop класса CLookDlg.
// Прервать загрузку страницы WWW
void CLookDlg::OnButtonStop()
{
m_explorer.Stop();
}
//////////////////////////////////////////////////////////////
// Метод OnButtonBack класса CLookDlg.
// Вернуться к просмотру предыдущей страницы
void CLookDlg::OnButtonBack()
{
m_explorer.GoBack();
}
//////////////////////////////////////////////////////////////
// Метод OnButtonStop класса CLookDlg.
// Передти к просмотру следующей страницы
void CLookDlg::OnButtonNext()
{
m_explorer.GoForward();
}
//////////////////////////////////////////////////////////////
// Таблица сообщений класса CLookDlg.
//
BEGIN_EVENTSINK_MAP(CLookDlg, CDialog)
//{{AFX_EVENTSINK_MAP(CLookDlg)
ON_EVENT(CLookDlg, IDC_EXPLORER, 106 /* DownloadBegin */,
OnDownloadBeginExplorer, VTS_NONE)
ON_EVENT(CLookDlg,IDC_EXPLORER, 104 /* DownloadComplete */,
OnDownloadCompleteExplorer, VTS_NONE)
ON_EVENT(CLookDlg, IDC_EXPLORER, 108 /* ProgressChange */,
OnProgressChangeExplorer, VTS_I4 VTS_I4)
ON_EVENT(CLookDlg, IDC_EXPLORER, 100 /* BeforeNavigate */,
OnBeforeNavigateExplorer, VTS_BSTR VTS_I4 VTS_BSTR
VTS_PVARIANT VTS_BSTR VTS_PBOOL)
ON_EVENT(CLookDlg,IDC_EXPLORER,200 /*FrameBeforeNavigate*/,
OnFrameBeforeNavigateExplorer, VTS_BSTR VTS_I4 VTS_BSTR
VTS_PVARIANT VTS_BSTR VTS_PBOOL)
ON_EVENT(CLookDlg, IDC_EXPLORER, 113 /* TitleChange */,
OnTitleChangeExplorer, VTS_BSTR)
ON_EVENT(CLookDlg, IDC_EXPLORER, 103 /* Quit */,
OnQuitExplorer, VTS_PBOOL)
ON_EVENT(CLookDlg,IDC_EXPLORER, 102 /* StatusTextChange */,
OnStatusTextChangeExplorer, VTS_BSTR)
ON_EVENT(CLookDlg, IDC_EXPLORER, 101 /*NavigateComplete */,
OnNavigateCompleteExplorer, VTS_BSTR)
//}}AFX_EVENTSINK_MAP
END_EVENTSINK_MAP()
//////////////////////////////////////////////////////////////
// Метод OnDownloadBeginExplorer класса CLookDlg.
// Начало загрузки файла
void CLookDlg::OnDownloadBeginExplorer()
{
// Инициализируем линейный индикатор
m_Progress.SetRange(0, 100);
m_Progress.SetStep(0);
m_Progress.SetPos(0);
}
//////////////////////////////////////////////////////////////
// Метод OnDownloadCompleteExplorer класса CLookDlg.
// Загрузка завершена, сбрасываем линейный индикатор
void CLookDlg::OnDownloadCompleteExplorer()
{
// TODO: Add your control notification handler code here
m_Progress.SetPos(0);
}
//////////////////////////////////////////////////////////////
// Метод OnProgressChangeExplorer класса CLookDlg.
// Идет загрузка, обновляем положение линейного индикатора
void CLookDlg::OnProgressChangeExplorer(long Progress, long ProgressMax)
{
// На всякий случай проверяем параметры метода
if(Progress <= 0 | ProgressMax <= 0)
return;
// Изменяем положение линейного индикатора
m_Progress.SetPos( (int) (Progress * 100) / ProgressMax);
}
//////////////////////////////////////////////////////////////
// Метод OnTitleChangeExplorer класса CLookDlg.
// Получен текст для заголовка окна навигатора
void CLookDlg::OnTitleChangeExplorer(LPCTSTR Text)
{
// Отображаем заголовок в поле редактирования IDC_TITLE_BAR
SetDlgItemText(IDC_TITLE_BAR, Text);
}
//////////////////////////////////////////////////////////////
// Метод OnTitleChangeExplorer класса CLookDlg.
// Получен текст для панели состояния окна навигатора
void CLookDlg::OnStatusTextChangeExplorer(LPCTSTR Text)
{
// Отображаем текст в поле редактирования IDC_STATUS_TEXT
SetDlgItemText(IDC_STATUS_TEXT, Text);
}
//////////////////////////////////////////////////////////////
// Метод OnNavigate класса CLookDlg.
// Передти к просмотру заданного адреса URL
void CLookDlg::OnNavigate()
{
// Определяем адрес URL, выбранный пользователем
UpdateData(TRUE);
// Переходим к просмотру ресурса по заданному адресу
m_explorer.Navigate(
m_address, // Адрес URL
NULL,
NULL,
NULL,
NULL
);
}
//////////////////////////////////////////////////////////////
// Метод OnNavigateCompleteExplorer класса CLookDlg.
// Загрузка всех ресурсов страницы завершена
void CLookDlg::OnNavigateCompleteExplorer(LPCTSTR URL)
{
// Обновляем адрес URL ресурса, показанного навигатором
m_address = URL;
UpdateData(FALSE);
}
Функции WinInet
Кроме классов WinInet в состав библиотеки MFC входят три глобальные функции - AfxParseURL, AfxGetInternetHandleType и AfxThrowInternetException. Они не принадлежат классам MFC и могут вызываться из любого места приложения.
Наибольший интерес представляет функция AfxParseURL. Она позволяет выделить из строки URL составные части. Вы можете использовать эту функцию для обработки адресов URL.
Для обработки ошибок WinInet в состав библиотеки классов MFC включен класс CInternetException. Соответствующее исключение вызывается методами классов WinInet, чтобы сообщить приложению о возникших ошибках и нестандартных ситуациях. Приложение может самостоятельно вызвать исключение CInternetException, воспользовавшись глобальной функцией AfxThrowInternetException.
Функция AfxGetInternetHandleType позволяет определить тип идентификатора Internet. Для определения типа идентификатора Internet глобальная функция InternetQueryOption вызывает функцию InternetQueryOption библиотеки WinInet.
Также как и классы WinInet все глобальные функции описаны в файле AFXINET.H. Если вы желаете изучить их более подробно, то можете найти исходные тексты в файле INET.CPP.
Функция AfxParseURL
Функция AfxParseURL разбирает текстовую строку, содержащую универсальный указатель ресурсов URL и выделяет из него тип сервиса, объект и номер порта TCP/IP. Приведем прототип функции AfxParseURL:
BOOL AFXAPI
AfxParseURL(
LPCTSTR pstrURL,
DWORD& dwServiceType,
CString& strServer,
CString& strObject,
INTERNET_PORT& nPort
);
Указатель на строку, содержащую URL, передается функции AfxParseURL через параметр pstrURL. Функция AfxParseURL разбирает данную строку и возвращает результат через параметры dwServiceType, strServer, strObject и nPort.
Тип сервиса, соответствующий указанному URL, записывается в переменную по ссылке dwServiceType. В качестве типа сервиса может фигурировать одна из констант, перечисленных в следующей таблице (полный список смотрите в документации Microsoft Visual C++):
Константа | Тип сервиса | ||
AFX_INET_SERVICE_FILE | Имя файла на локальном диске компьютера | ||
AFX_INET_SERVICE_FTP | Протокол передачи файлов FTP | ||
AFX_INET_SERVICE_GOPHER | Протокол Gopher | ||
AFX_INET_SERVICE_HTTP | Протокол передачи гипертекста | ||
AFX_INET_SERVICE_MAILTO | Адрес электронной почты (e-Mail) | ||
AFX_INET_SERVICE_NEWS | Новости | ||
AFX_INET_SERVICE_NNTP | Новости с использованием протокола NNTP | ||
AFX_INET_SERVICE_TELNET | Протокол Telnet | ||
AFX_INET_SERVICE_WAIS | Протокол Wais |
В строку strServer записывается первое поле URL, определяющее тип сервиса (тип протокола). Объект на который ссылается URL записывается в строку strObject. И, наконец, номер порта TCP/IP записывается в переменную nPort.
Функция AfxParseURL возвращает ненулевое значение в случае успешного завершения и нуль в случае ошибки.
Функция ShellExecute
Функция ShellExecute выполняет различные действия над определенным файлом. Файл может быть либо исполнимым файлом, либо файлом документа, либо папкой. Функция может запустить файл на выполнение (для исполняемых файлов), открыть файл документа с помощью соответствующего ему приложения или раскрыть на экране окно с содержимым папки (каталога).
Рассмотрим прототип функции ShellExecute:
HINSTANCE ShellExecute(
HWND hwnd,
LPCTSTR lpOperation,
LPCTSTR lpFile,
LPCTSTR lpParameters,
LPCTSTR lpDirectory,
INT nShowCmd
);
Параметр hwnd указывает идентификатор окна. Это окно будет выступать в качестве родительского окна для запускаемого приложения.
Наибольший интерес представляет параметр lpOperation. Он определяет операцию, которая будет выполняться над файлом, заданным в параметре lpFile. Как ни странно, код операции задается не числовой константой, а строкой, закрытой нулем. В качестве lpOperation можно указать строки “open”, “print” и “explore”. Краткое описание соответствующих операций мы привели в следующей таблице:
Параметр lpOperation | Операция | ||
“open” или значение NULL | Открыть файл, указанный параметром lpFile. Файл может быть исполнимым файлом, документом или папкой | ||
“print” | Распечатать файл, определенный параметром lpFile. Указанный файл должен быть файлом документа | ||
“explore” | Функция позволяет просмотреть содержимое папки, заданной параметром lpFile с помощью приложения Microsoft Explorer |
В случае, если ShellExecute используется для запуска исполнимого файла, вы можете передать ему строку параметров через lpParameters. Во всех остальных случаях указывайте в качестве lpParameters значение NULL.
Параметр lpDirectory задает имя каталога, который используется по умолчанию. В качестве него вы можете указать значение NULL.
Параметр nShowCmd позволяет указать режим, в котором будет запущено приложение. Этот параметр используется только при запуске исполнимых файлов. Если функция ShellExecute используется для открытия или печати файла документа, этот параметр следует указать равным нулю.
Описание возможных значений для параметра nShowCmd вы найдете в документации Microsoft Visual C++ или SDK. Фактически в качестве этого параметра можно использовать значения параметра nCmdShow известной функции WinMain. Например, вы можете указать в качестве параметра nShowCmd значение SW_SHOWNORMAL, который означает, что главное окно приложения должно иметь нормальные размеры и положение на экране, или значение SW_MINIMIZE, которое минимизирует окно запускаемого приложения.
Функция ShellExecute возвращает идентификатор (instance handle) запущенного приложения или идентификатор сервера DDE. Если возникнет ошибка, то функция возвращает ее код, значение которого меньше 32. Например, если указанный вами файл не будет обнаружен, то функция вернет код ERROR_FILE_NOT_FOUND. Полный список ошибок функции ShellExecute вы можете найти в документации.
Главный класс приложения
Метод InitInstance главного класса приложения выполняет инициализацию и, собственно, отображает на экране главную диалоговую панель приложения, которая управляется классом CLookDlg.
В целом, метод InitInstance практически ни чем не отличается от аналогичных методов других приложений с пользовательским интерфейсом на основе диалоговой панели. Исключение составляет только вызов глобальной функции AfxEnableControlContainer:
AfxEnableControlContainer();
Эта функция вызывается сразу после того как метод InitInstance получает управление и позволяет работать приложению как контейнеру для органов управления ActiveX. Другими словами функция AfxEnableControlContainer позволяет вам использовать в приложении органы управления ActiveX (OLE).
HTML и справочная система Windows
В примере приложения WebHelp, справочная информация расположена в сети Internet на нашем WWW сервере по адресу http://www.glasnet.ru/~frolov. Однако вы можете пользоваться навигатором и для просмотра справочной информации в формате HTML на локальном диске компьютера, дискете или компакт диске.
Вы можете использовать технологии Internet для создания справочной системы приложения в формате HTML. В принципе, такая справочная система способна заменить традиционную справочную систему Windows. Надо сказать, что так поступают многие фирмы, например Microsoft и Intel. Достаточно посмотреть компакт-диск технической поддержки Intel и последнюю версию “Решений Microsoft”, также распространяемых на компакт-диске.
В пользу использования справочной системы на основе технологий Internet можно привести несколько соображений. Во-первых, разработка справочной системы в формате HTML позволяет легко перенести ее с локального варианта на WWW сервер Internet и наоборот. Поэтому вы убиваете сразу двух зайцев - создаете справочную систему для распространения вместе с приложением и подготавливаете материал для размещения на своем сервере в Internet. Во-вторых, вы можете использовать в разработке справочной системы новые технологии, открывающие новые возможности, например, органы управления ActiveX, аплеты на языке Java и т. д. Большое количество приложений для создания файлов HTML значительно облегчит вам эту задачу.
Если вы решили разрабатывать справочную систему приложения на основе файлов в формате HTML, надо позаботится, чтобы вместе с приложением поставлялась программа-навигатор. Для этого, вы можете использовать, например, навигатор Microsoft Internet Explorer. Подробную информацию о возможностях лицензионного распространения этого навигаторе вы можете получить на WWW сервере корпорации Microsoft по адресу http://www.microsoft.com/ie/ieak/.
INTERNET_OPTION_ASYNC_ID
Идентификатор последнего асинхронного запроса, который выполнен в данной задаче.
INTERNET_OPTION_CALLBACK
Адрес функции обратного вызова, установленной для данного сеанса.
INTERNET_OPTION_CONNECT_BACKOFF
Задержка в миллисекундах между повторными попытками соединения.
INTERNET_OPTION_CONNECT_RETRIES
Количество попыток соединения. В случае неудачной попытки соединения выполняется соответствующее количество повторных попыток. По умолчанию выполняется 5 попыток.
INTERNET_OPTION_CONNECT_TIMEOUT
Время, отведенное на установление соединения. Задается в миллисекундах. Если соединение не устанавливается в течении данного времени, оно отменяется. По умолчанию время на соединение никак не ограничено.
INTERNET_OPTION_CONTEXT_VALUE
Идентификатор контекста, связанный с данным идентификатором Internet.
INTERNET_OPTION_CONTROL_RECEIVE_TIMEOUT
Время, отведенное для приема запроса, не связанного с получением данных. Задается в миллисекундах. По умолчанию время на прием запроса не ограничено.
INTERNET_OPTION_CONTROL_SEND_TIMEOUT
Время, отведенное для передачи запроса, не связанного с передачей данных. Задается в миллисекундах. По умолчанию время на передачу запроса не ограничено
INTERNET_OPTION_DATA_RECEIVE_TIMEOUT
Время, отведенное для запроса на прием данных. Задается в миллисекундах. По умолчанию время на прием запроса не ограничено.
INTERNET_OPTION_DATA_SEND_TIMEOUT
Время, отведенное для передачи запроса с данными. Задается в миллисекундах. По умолчанию время на передачу запроса не ограничено.
INTERNET_OPTION_EXTENDED_ERROR
Код ошибки программного интерфейса Winsock, который вызвал ошибку ERROR_INTERNET_ в данной задаче приложения.
Если метод QueryOption завершился без ошибок, он возвращает значение TRUE. В противном случае возвращается значение FALSE. Причину ошибки можно определить, обратившись к функции GetLastError.
INTERNET_OPTION_HANDLE_TYPE
Тип идентификатора Internet, например INTERNET_HANDLE_TYPE_CONNECT_FTP или INTERNET_HANDLE_TYPE_HTTP_REQUEST.
INTERNET_OPTION_KEEP_CONNECTION
Определяет, используется ли данным идентификатором уже существующее соединение.
INTERNET_OPTION_PASSWORD
Пароль, связанный с идентификатором, который возвращает функция InternetConnect из программного интерфейса WinInet.
INTERNET_OPTION_READ_BUFFER_SIZE
Размер буфера, используемого для чтения данных с сервера FTP.
INTERNET_OPTION_REQUEST_FLAGS
Информация о текущем процессе загрузки. Если загрузка идет из кэш-памяти, то возвращается флаг INTERNET_REQFLAG_FROM_CACHE.
INTERNET_OPTION_USERNAME
Имя пользователя, связанное с идентификатором, который возвращает функция InternetConnect из программного интерфейса WinInet.
INTERNET_OPTION_WRITE_BUFFER_SIZE
Размер буфера, используемого для передачи данных на сервер FTP.
INTERNET_STATUS_CLOSING_CONNECTION
Соединение с сервером закрывается. Параметр lpvStatusInformation не используется.
INTERNET_STATUS_CONNECTED_TO_SERVER
Установлено соединение по адресу сокета, указанного в буфере lpvStatusInformation.
INTERNET_STATUS_CONNECTING_TO_SERVER
Выполняется соединение по адресу сокета, указанного в буфере lpvStatusInformation.
INTERNET_STATUS_CONNECTION_CLOSED
Соединение с сервером закрыто. Параметр lpvStatusInformation не используется.
INTERNET_STATUS_HANDLE_CREATED
Функция InternetConnect из программного интерфейса WinInet создала новый идентификатор.
INTERNET_STATUS_NAME_RESOLVED
В буфере lpvStatusInformation находится IP-адрес сервера, имя которого вы указали.
INTERNET_STATUS_RECEIVING_RESPONSE
Ожидает ответ на запрос, переданный серверу. Параметр lpvStatusInformation не используется.
INTERNET_STATUS_REQUEST_COMPLETE
Асинхронная операция завершена. Параметр lpvStatusInformation содержит значение NULL, но параметр dwStatusInformationLength используется. Он содержит код завершения асинхронной операции.
Если параметр dwStatusInformationLength содержит значение ERROR_INTERNET_EXTENDED_ERROR, вы можете получить дополнительную информацию об ошибке, обратившись к функции InternetGetLastResponseInfo.
Если параметр dwStatusInformationLength имеет значение INTERNET_STATUS_REQUEST_COMPLETE, тогда параметр lpvStatusInformation содержит указатель на структуру типа INTERNET_ASYNC_RESULT.
Данная структура определена в файле wininet.h следующим образом:
typedef struct {
DWORD dwResult; // код завершения операции
DWORD dwError; // код ошибки
} INTERNET_ASYNC_RESULT, * LPINTERNET_ASYNC_RESULT;
В поле dwResult находится код завершения операции. Если во время выполнения операции возникла ошибка, тогда в поле dwError будет записан код ошибки. Если операция завершилась успешно, в поле dwError записана константа ERROR_SUCCESS.
¨ В том случае если вы используете библиотеку MFC в виде библиотеки dll, необходимо добавить в самом начале переопределенного вами метода OnStatusCallback строку следующего вида:
AFX_MANAGE_STATE( AfxGetStaticModuleState() );
INTERNET_STATUS_REQUEST_SENT
Информационный запрос передан на сервер. Параметр lpvStatusInformation не используется.
INTERNET_STATUS_RESOLVING_NAME
Определяет IP-адрес имени, записанного в параметре lpvStatusInformation.
INTERNET_STATUS_RESPONSE_RECEIVED
Получен ответ на запрос, переданный серверу. Параметр lpvStatusInformation не используется.
INTERNET_STATUS_SENDING_REQUEST
Передается информационный запрос на сервер. Параметр lpvStatusInformation не используется.
Исходные тексты приложения FtpView
Когда вы закончите создание и доработку ресурсов приложения FtpView, надо приступить к доработке программных кодов приложения. Список файлов, составляющих проект FtpView, вы можете просмотреть в окне Project Workspace на странице FileView (рис. 2.7). Вы можете непосредственно внести все необходимые изменения в исходные файлы проекта, однако значительно лучше переложить часть работы на MFC ClassWizard. Средствами MFC ClassWizard вы сможете легко добавить к классам новые элементы данных и новые методы.
Рис. 2.7. Файлы проекта FtpView
Исходный текст приложения
Исходный текст приложения весьма прост и не содержит в себе каких-либо особенностей. Если вы желаете подробно изучить алгоритм работы приложения WebHelp, воспользуйтесь томом 24 серии “Библиотека системного программиста”. Единственное, что сейчас представляет для нас интерес, это то, как происходит запуск навигатора.
Когда вы выбираете из меню Help строку Web Help приложению поступает командное сообщение с идентификатором ID_HELP_WEBHELP. Это сообщение поступает в класс CWebHelpWindow и распределяется таблицей сообщений этого класса методу WebHelpCommand:
BEGIN_MESSAGE_MAP(CWebHelpWindow, CFrameWnd)
ON_COMMAND(ID_HELP_WEBHELP, WebHelpCommand)
...
END_MESSAGE_MAP()
Метод WebHelpCommand передает функции ShellExecute адрес страницы WWW, содержащей справочную информацию для приложения. Этот вызов запускает навигатор для просмотра информации по указанному адресу:
IRes = ShellExecute( NULL, // Индекс родительского окна
"open", // Код операции
"http://www.dials.ccas.ru/" // URL адрес страницы
"frolov/rwin/webhelp.htm",
NULL, // Строка параметров
NULL, // Путь текущего каталога
SW_SHOWNORMAL // Режим отображения
// окна навигатора
);
Мы не указываем функции ShellExecute индекс родительского окна и используем вместо него значение NULL. Нам надо открыть файл HTML, поэтому в качестве второго параметра передается строка "open". Строка URL адреса, в которой записан путь к справочному файлу, передается функции через третий параметр. Следующие два параметра - строка параметров и путь текущего каталога - не используются. В них указываются значения NULL.
В качестве кода операции используем строку "open". Она означает, что мы желаем открыть объект, адрес которого содержится в третьем параметре функции ShellExecute. В данном случае приложение WebHelp обращается на страницу WWW, расположенную по адресу http://www.dials.ccas.ru/frolov/rwin/webhelp.htm.
Третий и четвертый параметры функции ShellExecute содержат нулевые значения, так как мы не используем дополнительные параметры и текущий каталог. Последний, пятый параметр функции равен SW_SHOWNORMAL. Эта константа означает, что приложение для просмотра WWW страницы запускается в окне нормального размера (не свернутым до размера пиктограммы и не открытым на весь экран).
Код результата, возвращаемого функцией ShellExecute, проверяется. В случае если произошла ошибка, ее код отображается на экране при помощи функции MessageBox.
Конечно, можно было бы запустить на выполнение непосредственно исполнимый файл программы навигатора, но в этом случае необходимо знать имя этого файла и суметь передать ему адрес, который надо посетить. Следует сказать, что одно только первое требование уже составляет определенную трудность, так как файлы навигаторов разных фирм, естественно, имеют различные названия, более того для разных версий одного и того же навигатора название файлов также может отличаться.
Элементы данных класса CFtpViewDlg
Когда вы с помощью MFC ClassWizard привязывали переменные к органам управления диалоговой панели, в класс были добавлены несколько элементов данных. Все они были занесены с специальный блок, отмеченный комментариями вида //}}AFX_DATA:
//{{AFX_DATA(CFtpViewDlg)
CEdit m_Status; // Поле Directory
CButton m_Ok; // Кнопка OK
CButton m_OnTop; // Кнопка On top
CButton m_Connect; // Кнопка Connect
CListCtrl m_FtpList; // Таблица с содержимым каталога
CString m_FtpAddress; // Поле адреса сервера FTP
//}}AFX_DATA
Эти элементы данных представляют собой объекты классов MFC, управляющие соответствующими им органами управления диалоговой панели. Например, объект m_Connect класса CButton, привязан к кнопке Connect. Вызывая различные методы для этого объекта вы можете управлять кнопкой Connect (блокировать ее, снимать блокировку и т. д.).
Элементы данных, определенные внутри блока AFX_DATA тесно соотносятся с методом DoDataExchange, который, собственно, и осуществляет их связь с органами управления диалоговой панели.
Другая группа элементов данных класса CFtpViewDlg определена после ключевого слова protected содержит пять объектов. Доступ к этим объектам открыт только для методов самого класса CFtpViewDlg:
protected:
HICON m_hIcon; // Пиктограмма приложения
CString sCurentDirectory; // Текущий каталог
CImageList* m_ImageList; // Список изображений
CFtpConnection* m_FtpConnection; // FTP сервер
CInternetSession* m_InternetSession; // Сеанс связи
Элемент m_hIcon используется для хранения идентификатора пиктограммы приложения. Этот элемент создан MFC AppWizard и не представляет для нас особого интереса. Остальные элементы данных класса добавлены нами через окно Project Workspace и мы рассмотрим их более подробно.
Полный путь каталога, содержимое которого отображается в списке на диалоговой панели, хранится в строке sCurentDirectory. Этот путь устанавливается, когда приложение соединяется с сервером FTP, а потом изменяется, когда вы входите в каталог, отображаемый в списке или выходите в каталог верхнего уровня, нажимая кнопку On top.
В списке IDC_FTP_LIST отображаются названия каталогов и файлов. Для наглядности мы выделяем их различными пиктограммами. Список изображений формируется во время инициализации диалоговой панели методом OnInitDialog и указатель на него записывается в элемент данных m_ImageList класса CFtpViewDlg.
Два последних элемента данных, входящих в класс CFtpViewDlg, наиболее интересны, так как используются для доступа к сети Internet и серверу FTP.
Элемент m_InternetSession является указателем на объект класса CInternetSession. Этот объект создается во время инициализации диалоговой панели с помощью метода OnInitDialog и требуется для дальнейшей работы с классами WinInet.
Элемент m_FtpConnection представляет собой указатель на объект класса CFtpConnection. Этот объект создается при установлении соединения с сервером FTP, которое выполняется методом OnConnect, когда пользователь нажимает кнопку Connect.
Элементы данных класса CInternetException
Класс CInternetException содержит два элемента данных - m_dwError и m_dwContext. Они позволяют узнать код ошибки и идентификатор контекста операции, ставшей причиной вызова исключения.
Код ошибки содержится в элементе данных m_dwError. Причина вызова исключения может быть не связана с WinInet напрямую. В этом случае в качестве кода ошибки m_dwError будет фигурировать один из кодов ошибок Win32. Их список вы найдете в документации Visual C++.
Список кодов ошибок, связанных с WinInet, вы можете найти в документации по ActiveX SDK, а также в Internet по следующему адресу: http:\\www.microsoft.com/intdev. Ниже мы перечислили для примера несколько таких кодов и дали им краткие описания:
Код ошибки | Описание | ||
ERROR_INTERNET_TIMEOUT | Время, отведенное на выполнение запроса истекло | ||
ERROR_INTERNET_INTERNAL_ERROR | Внутренняя ошибка WinInet | ||
ERROR_INTERNET_LOGIN_FAILURE | Неудачная попытка соединения с сервером FTP | ||
ERROR_FTP_DROPPED | Операция с сервером FTP не завершена из за разрыва сеанса связи |
Как работает приложение Look
Приложение Look имеет пользовательский интерфейс на основе диалоговой панели. Мы не будем рассматривать основные принципы устройства этого приложения. Соответствующую информацию вы можете получить из 24 тома серии “Библиотека системного программиста”. Больше внимания мы уделим прикладной части приложения, имеющей отношение к управлению навигатором Microsoft Web Browser Control.
Как работает приложение ParseURL
Структура приложения ParseURL ничем не отличается от других приложений с пользовательским интерфейсом на основе диалоговой панели, сформированных средствами MFC AppWizard. Поэтому мы не будем останавливаться на описании устройства приложения, и рассмотрим только моменты, непосредственно связанные с разбором адресов URL и отображением полученной информации в диалоговой панели.
Сразу после запуска, приложение ParseURL создает диалоговую панель IDD_PARSEURL_DIALOG и отображает ее на экране. Управление этой диалоговой панелью осуществляет класс CParseURLDlg, определенный в нашем приложении.
Конструктор класса CParseURLDlg инициализирует строки m_ObjectName, m_PortNumber, m_ServiceType, m_UrlAddress. Несколько позже, когда будет вызван метод OnInitDialog, мы запишем в строку m_UrlAddress пример адреса URL. Чтобы вывести этот адрес на экран, метод OnInitDialog вызывает метод UpdateData с параметром FALSE:
UpdateData(FALSE);
Когда пользователь нажимает кнопку Convert, командное сообщение от нее попадает в таблицу сообщений класса CParseURLDlg и для его обработки вызывается метод OnButtonConvert:
ON_BN_CLICKED(IDC_BUTTON_CONVERT, OnButtonConvert)
Метод OnButtonConvert опять вызывает метод UpdateData, но на этот раз в качестве параметра ему передается значение TRUE. Этот метод считывает данные из органов управления диалоговой панели и записывает их в соответствующие переменные. Вызов этого метода необходим, так как пользователь мог изменить адрес URL в поле URL Address диалоговой панели приложения:
UpdateData(TRUE);
Теперь в строке m_UrlAddress записан адрес URL, который необходимо разобрать на составные части. Для этого вызываем глобальную функцию AfxParseURL, передавая ей строку m_UrlAddress для разбора и переменные dwServiceType, m_ServerName, m_ObjectName, nPort. В них будет записан результат разбора адреса:
if (!AfxParseURL(m_UrlAddress, dwServiceType, m_ServerName,
m_ObjectName, nPort))
{
}
Обратите внимание, что имя сервера и имя объекта записываются непосредственно в переменные m_ServerName и m_ObjectName, привязанные к полям диалоговой панели. А вот тип сервиса (тип протокола) и номер порта записываются во временные переменные nPort и dwServiceType, так как их тип не соответствует строковому:
INTERNET_PORT nPort;
DWORD dwServiceType;
Если в строке m_UrlAddress записан неправильный адрес, то функция AfxParseURL возвращает нулевое значение. В этом случае мы выводим сообщение об ошибке и сбрасываем строки m_ObjectName, m_PortNumber, m_ServerName, m_ServiceType:
AfxMessageBox("AfxParseURL Error");
m_ObjectName = "";
m_PortNumber = "";
m_ServerName = "";
m_ServiceType = "";
Если адрес успешно разобран, мы проверяем тип сервиса dwServiceType и записываем в строку m_ServiceType соответствующий текст. Чтобы не загромождать приложение мы таким образом распознаем только четыре основных типа сервиса:
switch(dwServiceType)
{
case AFX_INET_SERVICE_FTP:
m_ServiceType = "AFX_INET_SERVICE_FTP";
break;
case AFX_INET_SERVICE_HTTP:
m_ServiceType = "AFX_INET_SERVICE_HTTP";
break;
case AFX_INET_SERVICE_GOPHER:
m_ServiceType = "AFX_INET_SERVICE_GOPHER";
break;
case AFX_INET_SERVICE_FILE:
m_ServiceType = "AFX_INET_SERVICE_FILE";
break;
default:
// Формируем строку из значения переменной dwServiceType
m_ServiceType.Format("%d", dwServiceType);
}
Если вы указали другой тип сервиса мы записываем в строку m_PortNumber соответствующее числовое значение. Для этого мы используем метод Format класса CString:
m_PortNumber.Format("%d", nPort);
¨ Метод Format класса CString очень удобен для записи в строку форматированных значений каких-либо переменных. По своему назначению и формату вызова данный метод напоминает хорошо известную вам функцию sprintf. Только в функции sprintf
строка, в которую записываются форматированные данные, определяется первым параметром, а метод Format вызывается для объекта представляющего эту строку.
После того, как все переменные, привязанные к полям редактирования диалоговой панели, заполнены, вызываем метод UpdateData с параметром FALSE. Он отображает их содержимое в диалоговой панели:
UpdateData(FALSE);
Как связаться с авторами
Авторы имеют почтовый адрес в сети GlasNet. Все свои замечания и предложения по содержанию книг серий "Библиотека системного программиста", а также "Персональный компьютер - шаг за шагом" вы можете присылать нам по следующему адресу:
: frolov@glas.apc.org
Наш почтовый адрес доступен не только пользователям сети Internet. Абоненты других компьютерных сетей также могут передавать нам сообщения. Ниже мы приводим наш адрес в различных сетях:
Глобальная сеть | Наш адрес | ||
CompuServe | >internet:frolov@glas.apc.org | ||
GlasNet | frolov | ||
Relcom | frolov@glas.apc.org | ||
UUCP | uunet!cdp!glas!frolov |
Вы также можете присылать свои пожелания почтой по адресу:
* Издательский отдел АО "ДИАЛОГ-МИФИ".
Индекс 115409, город Москва, улица Москворечье,
дом 31, корпус 2.
Приносим свои извинения за то, что не можем ответить на каждое письмо. Мы также не занимаемся рассылкой книг, дискет и исходных текстов к нашим книгам. По этому вопросу обращайтесь непосредственно в издательство “Диалог-МИФИ”.