Как устроено приложение FtpView
Основу приложения FtpView составляют два класса CFtpViewApp и CFtpViewDlg. Класс CFtpViewApp является основным классом приложения. Он выполняет инициализацию и отображает диалоговую панель приложения. Класс CFtpViewDlg управляет этой диалоговой панелью, а также соединяется с Internet для получения списка объектов на сервере FTP.
На рисунке 2.13 представлена страница ClassView окна проекта Project Workspace. На ней вы можете просмотреть структуру классов нашего приложения.
Рис. 2.13. Классы приложения FtpView
Как вызвать исключение CInternetException - функция AfxThrowInternetException
Чтобы принудительно вызвать исключение CInternetException из своего приложения воспользуйтесь глобальной функцией AfxThrowInternetException:
void AFXAPI AfxThrowInternetException(
DWORD dwContext,
DWORD dwError = 0
);
Функции AfxThrowInternetException передаются два параметра. Через параметр dwError передается код ошибки, а через параметр dwContext - идентификатор контекста операции, вызвавшей ошибку. По умолчанию в качестве кода ошибки используется нулевое значение. В этом случае функция AfxThrowInternetException определяет код ошибки самостоятельно, обращаясь к функции GetLastError программного интерфейса Windows.
Функция AfxThrowInternetException создает объект класса CInternetException, присваивает элементам m_dwError и m_dwContext этого объекта значения, полученные через параметры dwContext и dwError и вызывает исключение.
В режиме отладки данная функция выводит в окне Debug сообщение о вызове исключения CInternetException с соответствующим кодом ошибки - "Warning: throwing CInternetException for error...".
Класс CFileFind
Класс CFileFind предназначен для поиска файлов на локальном компьютере. Этот класс наследуется от базового класса CObject:
CObject -> CFileFind -> CFtpFileFind
|
-> CGopherFileFind
Класс CFileFind служит базовым классом для двух классов WinInet - CFtpFileFind и CGopherFileFind, которые предназначены для поиска файлов в сети Internet на серверах FTP и Gopher.
В следующей таблице мы привели описание методов класса CFileFind:
Метод | Описание | ||
CFileFind | Конструктор класса CFileFind | ||
GetLength | Определяет длину файла в байтах | ||
GetFileName | Определяем имя файла с расширением | ||
GetFilePath | Определяет полный путь файла | ||
GetFileTitle | Определяет заголовок файла, то есть его имя не учитывая расширение | ||
GetFileURL | Определяет адрес файла в формате URL | ||
GetRoot | Определяет корневой каталог, в котором расположен файл | ||
GetCreationTime | Определяет время создания файла | ||
GetLastAccessTime | Определяет время последнего обращения к файлу | ||
GetLastWriteTime | Определяет время последнего изменения файла | ||
MatchesMask | Определяет состояние заданных атрибутов файла | ||
IsDots | Определяет, состоит ли имя файла из символов "." или "..", которые означают каталог верхнего уровня | ||
IsReadOnly | Определяет, является ли данный файл доступным только для чтения | ||
IsDirectory | Определяет, является ли очередной объект, полученный методом FindNext, каталогом или файлом | ||
IsCompressed | Определяет, является ли данный файл компрессованным | ||
IsSystem | Проверяет, является ли файл системным | ||
IsHidden | Определяет, является ли данный файл скрытым | ||
IsTemporary | Позволяет распознать временные файлы | ||
IsNormal | Определяет, является ли файл “нормальным”. Под словосочетанием “нормальный файл” понимаются файлы у которых не установлены другие атрибуты | ||
IsArchived | Определяет является ли данный файл архивным | ||
Close | Завершает поиск файлов | ||
FindFile | Начинает поиск файла или файлов в указанном каталоге | ||
FindNextFile | Продолжает поиск файла или файлов в указанном каталоге. Вы должны использовать этот метод после обращения к методу FindFile |
Класс CFtpConnection
Класс CFtpConnection наследуется от базового класса CInternetConnection:
CObject -> CInternetConnection -> CFtpConnection
Класс CFtpConnection предназначен для соединения с серверами FTP. Методы этого класса позволяют приложению обмениваться файлами с сервером FTP, а также выполнять различные сервисные операции, такие как создание и удаление каталогов, переименование и удаление файлов и т. д.
Для класса CFtpConnection определен конструктор класса, но вам никогда не потребуется обращаться к нему напрямую. Объект CFtpConnection создается косвенно при вызове метода GetFtpConnection для объекта класса CInternetSession:
// Определяем указатель на объект класса CFtpConnection
CFtpConnection* m_FtpConnection = NULL;
// Пытаемся соединиться с сервером sServer
m_FtpConnection =
m_InternetSession -> GetFtpConnection( sServer );
Метод Close закрывает соединение с сервером FTP. Вы должны вызвать этот метод после завершения работы с объектом CFtpConnection. В принципе, вызов метода Close можно совсем опустить. В этом случае соединение будет разорвано автоматически деструктором класса CFtpConnection.
Класс CFtpFileFind
Класс CFtpFileFind наследуется от базового класса CFileFind и позволяет провести поиск файлов на сервере FTP.
Для нас будут представлять интерес конструктор класса CFtpFileFind и все остальные три метода, входящие в состав этого класса. Название этих методов мы привели в следующей таблице:
Метод | Описание | ||
CFtpFileFind | Конструктор класса CFtpFileFind | ||
FindFile | Начинает поиск файла или файлов на сервере FTP | ||
FindNextFile | Продолжает поиск файла или файлов в указанном каталоге сервера FTP. Вы должны использовать этот метод после обращения к методу FindFile | ||
GetFileURL | Определяет адрес файла в формате URL |
Если вы решите заняться разработкой приложения, взаимодействующего с серверами FTP, вы будете активно использовать все методы данного класса. Поэтому мы приведем их описания.
Класс CFtpViewApp
Главный класс приложения CFtpViewApp, определен в файле FtpView.h. Мы привели исходный текст этого файла в листинге 2.4. Класс CFtpViewApp наследуется от базового класса CWinApp. При этом переопределяется единственный виртуальный метод InitInstance, который выполняет инициализацию приложения и отображает на экране главную диалоговою панель приложения.
Листинг 2.4. Файл FtpView.h
#ifndef __AFXWIN_H__
#error include 'stdafx.h' before including this file for PCH
#endif
#include "resource.h" // Включаемый файл содержащий
// Идентификаторы ресурсов приложения
//============================================================
// Определение класса CFtpViewApp
// Методы класса CDialogApp определены в файле FtpView.cpp
//============================================================
class CFtpViewApp : public CWinApp
{
public:
CFtpViewApp();
// Overrides
// В следующем блоке ClassWizard помещает описания
// переопределенных виртуальных методов класса
//{{AFX_VIRTUAL(CFtpViewApp)
public:
virtual BOOL InitInstance();
//}}AFX_VIRTUAL
// Implementation
//{{AFX_MSG(CFtpViewApp)
// В этом блоке ClassWizard размещает описания методов
// класса. Не редактируйте содержимое этого блока вручную
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
Определение конструктора класса CFtpViewApp, метода InitInstance, таблицы сообщений, а также определение объекта данного класса вы найдете в файле FtpView.cpp. Исходный текст этого файла мы представили в листинге 2.5. Заметим, что файлы FtpView.h и FtpView.cpp мы оставляем без изменения какими их создал MFC AppWizard.
Весь программный код, который будет взаимодействовать с сервером FTP и обслуживать диалоговую панель IDD_FTPVIEW_DIALOG, мы добавим к классу CFtpViewDlg. По большей части мы будем использовать для этого средства MFC ClassWizard, так что вручную вам надо будет ввести только исходный текст добавленных методов.
Листинг 2.5. Файл FtpView.cpp
//============================================================
// Приложение для просмотра структуры каталогов
// серверов FTP
//
// (C) Фролов Г.В., 1997
// E-mail: frolov@glas.apc.org
// WWW: http://www.glasnet.ru/~frolov
// или
// http://www.dials.ccas.ru/frolov
//============================================================
// Файл содержит определение методов и таблицы сообщений
// главного класса приложения
//============================================================
// Включаемые файлы
#include "stdafx.h"
#include "FtpView.h"
#include "FtpViewDlg.h"
// Для отладочной версии приложения включается дополнительные
// определения
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
//============================================================
// Таблица сообщений класса CFtpViewApp
//============================================================
BEGIN_MESSAGE_MAP(CFtpViewApp, CWinApp)
//{{AFX_MSG_MAP(CFtpViewApp)
//}}AFX_MSG
ON_COMMAND(ID_HELP, CWinApp::OnHelp)
END_MESSAGE_MAP()
//============================================================
// Конструктор класса CFtpViewApp
//============================================================
CFtpViewApp::CFtpViewApp()
{
// TODO:
}
//////////////////////////////////////////////////////////////
// Объект главного класса приложения
CFtpViewApp theApp;
//============================================================
// Метод InitInstance класса CFtpViewApp.
// Выполняет инициализацию приложения
//============================================================
BOOL CFtpViewApp::InitInstance()
{
#ifdef _AFXDLL
Enable3dControls();
#else
Enable3dControlsStatic();
#endif
CFtpViewDlg dlg;
m_pMainWnd = &dlg;
int nResponse = dlg.DoModal();
if (nResponse == IDOK)
{
// TODO: Нажата кнопка OK
}
else if (nResponse == IDCANCEL)
{
// TODO: Нажата кнопка Cancel
}
// Так как диалоговая панель закрыта, возвращаем значение
// FALSE чтобы завершить приложение
return FALSE;
}
Класс CFtpViewDlg
Все изменения, которые мы будем вносить в наш проект затронут, в основном, только класса CFtpViewDlg. Это и понятно - именно к диалоговой панели IDD_FTPVIEW_DIALOG, которая управляется данным классом, мы добавили новые органы управления для взаимодействия с сервером FTP.
Приложения, которые используют для доступа к ресурсам сети Internet классы MFC WinInet, должны иметь как минимум один объект класса CInternetSession. Этот объект представляет собой “сеанс” связи с Internet.
В окне Project Workspace щелкните правой клавишей мыши по имени класса CFtpViewDlg. Откроется контекстное меню, из которого следует выбрать строку Add Variable. На экране появится диалоговая панель Add Member Variable (рис. 2.8).
Рис. 2.8. Диалоговая панель Add Member Variable
В поле Variable Type введите имя класса CInternetSession, а в поле Variable Declaration имя нового элемента класса CFtpViewDlg - m_InternetSession. Переключатель Access переведите в положение Protect. Нажмите кнопку OK. В класс CFtpViewDlg будет добавлен новый элемент - объект класса CInternetSession. Так как мы выбрали тип доступа Protect, то этот элемент будет расположен в секции protected и будет доступен только методам данного класса.
Повторите описанную процедуру и добавьте к классу CFtpViewDlg еще три элемента - строку sCurentDirectory класса CString, указатель m_ImageList на класс CImageList и указатель m_FtpConnection на класс CFtpConnection.
С помощью MFC ClassWizard привяжите переменные к органам управления диалоговой панели IDD_FTPVIEW_DIALOG. Для этого откройте MFC ClassWizard, перейдите на страницу Member Variables. В поле Class name выберите имя класса CFtpViewDlg. Затем последовательно выбирайте идентификаторы органов управления из списка Control IDs, нажимайте кнопку Add Variable и в открывающейся панели Add Member Variable вводите имя, категорию и тип переменной.
Добавляя переменные, пользуйтесь рисунком 2.9. На нем видно, какие переменные привязаны к органам управления диалоговой панели. Только кнопка OK не имеет собственной переменной, так как она нам не понадобится.
Рис. 2.9. Диалоговая панель MFC ClassWizard
Перейдите в диалоговой панели MFC ClassWizard на страницу Message Maps и добавьте несколько методов-обработчиков сообщений от органов управления диалоговой панели IDD_FTPVIEW_DIALOG. Для кнопки Connect, имеющей идентификатор IDC_CONNECT, и кнопки On Top с идентификатором IDC_ON_TOP добавьте обработчики командного сообщения BN_CLICKED - методы OnConnect и OnOnTop. Они будут вызываться при нажатии на эти кнопки. Для списка IDC_FTP_LIST добавьте обработчик сообщения NM_DBLCLK - метод OnDblclkFtpList. Он будет вызываться при двойном щелчке левой кнопкой мыши внутри списка.
Теперь остается совсем немного. Надо добавить метод DirectoryView и деструктор к классу CFtpViewDlg. MFC ClassWizard в этом вам не помощник. Откройте окно Project Workspase, если оно закрыто, и щелкните правой клавишей мыши по названию класса CFtpViewDlg. Откроется контекстное меню, из которого надо выбрать строку Add Function. На экране появится диалоговая панель Add Member Function (рис. 2.10).
Рис. 2.10. Диалоговая панель Add Member Function
Чтобы добавить метод DirectoryView, введите в поле Function Declaration его название, а в поле Function Type - тип значения, возвращаемого этим методом - BOOL. Повторите описанную операцию еще один раз и добавьте к классу CFtpViewDlg деструктор ~CFtpViewDlg. Для этого введите в поле Function Declaration строку ~CFtpViewDlg, а поле Function Type оставьте пустым.
MFC ClassWizard создает только шаблоны методов. Рабочий программный код вы должны добавить в них самостоятельно. Ниже мы привели исходные тексты файлов FtpViewDlg.h и FtpViewDlg.cpp, в соответствии с которыми вам надо доработать свой проект.
Класс CFtpViewDlg определен в файле FtpViewDlg.h. Мы привели исходный текст этого файла в листинге 2.6. Для этого файла вам надо добавить директивы define, определяющие четыре константы - COL_NUM, MIN_LEN_BUF, DIRECTORY и FILE. Эти константы будут использоваться методами класса FtpViewDlg.
Листинг 2.6. Файл FtpViewDlg.h
//============================================================
// Определение класса FtpViewDlg и некоторых констант
//============================================================
// Определение констант
#define COL_NUM 4 // Количество колонок таблицы
#define MIN_LEN_BUF 30 // Минимальная длина буфера
#define DIRECTORY 0 // Пиктограмма каталога
#define FILE 1 // Пиктограмма файла
//////////////////////////////////////////////////////////////
// Класс CFtpViewDlg
class CFtpViewDlg : public CDialog
{
// Construction
public:
~CFtpViewDlg();
CFtpViewDlg(CWnd* pParent = NULL);
// Dialog Data
//{{AFX_DATA(CFtpViewDlg)
enum { IDD = IDD_FTPVIEW_DIALOG };
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
//{{AFX_VIRTUAL(CFtpViewDlg)
protected:
// Обмен данными - DDX/DDV
virtual void DoDataExchange(CDataExchange* pDX);
//}}AFX_VIRTUAL
// Implementation
protected:
CString sCurentDirectory; // Текущий каталог
CImageList* m_ImageList; // Список изображений
CFtpConnection* m_FtpConnection; // Сервер FTP
CInternetSession* m_InternetSession; // Сеанс связи
HICON m_hIcon; // Пиктограмма
// приложения
protected:
// Метод, просматривающий содержимое каталога
BOOL DirectoryView();
// Методы обрабатывающие сообщения
//{{AFX_MSG(CFtpViewDlg)
virtual BOOL OnInitDialog();
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
afx_msg void OnOnTop();
afx_msg void OnDblclkFtpList(NMHDR* pNMHDR,
LRESULT* pResult);
afx_msg void OnConnect();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
¨ В листинге файла FtpViewDlg.h, в блоке AFX_MSG, описание метода OnDblclkFtpList разбито на две строки. Это сделано исключительно из-за ограничений, налагаемых типографией. Вы должны поместить данное описание на одной строке, в противном случае MFC ClassWizard будет выдавать сообщение об ошибке и вы не сможете воспользоваться его средствами для просмотра и изменения программного кода
Конструктор, деструктор, методы класса CFtpViewDlg, а также таблица сообщений определены в файле FtpViewDlg.cpp. Мы привели исходный текст файла FtpViewDlg.cpp в листинге 2.7. В соответствии с текстом этого файла вы должны доработать методы OnInitDialog, OnConnect, DirectoryView, OnDblclkFtpList, OnOnTop.
Листинг 2.7. Файл FtpViewDlg.cpp
#include "stdafx.h"
#include "FtpView.h"
#include "FtpViewDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
//============================================================
// Конструктор класса CFtpViewDlg
//============================================================
CFtpViewDlg::CFtpViewDlg(CWnd* pParent /*=NULL*/)
: CDialog(CFtpViewDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CFtpViewDlg)
m_FtpAddress = _T("");
//}}AFX_DATA_INIT
// При использовании метода LoadIcon нет необходимости
// вызывать DestroyIcon
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
//============================================================
// Деструктор класса CFtpViewDlg
//============================================================
CFtpViewDlg::~CFtpViewDlg()
{
// Если соединение с сервером установлено, закрываем его
if (m_FtpConnection != NULL)
{
m_FtpConnection -> Close();
delete m_FtpConnection;
}
// Завершаем сеанс связи с Internet
if (m_InternetSession != NULL)
{
m_InternetSession -> Close();
delete m_InternetSession;
}
// Удаляем список изображений
delete m_ImageList;
}
//============================================================
// Метод DoDataExchange класса CFtpViewDlg
// Выполняет привязку органов управления диалоговой панели
// IDD_FTPVIEW_DIALOG и соответствующих элементов класса
// CFtpViewDlg
//============================================================
void CFtpViewDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CFtpViewDlg)
DDX_Control(pDX, IDC_STATUS, m_Status);
DDX_Control(pDX, IDOK, m_Ok);
DDX_Control(pDX, IDC_ON_TOP, m_OnTop);
DDX_Control(pDX, IDC_CONNECT, m_Connect);
DDX_Control(pDX, IDC_FTP_LIST, m_FtpList);
DDX_Text(pDX, IDC_FTP_ADDRESS, m_FtpAddress);
//}}AFX_DATA_MAP
}
//============================================================
// Таблица сообщений класса CFtpViewDlg
//============================================================
BEGIN_MESSAGE_MAP(CFtpViewDlg, CDialog)
//{{AFX_MSG_MAP(CFtpViewDlg)
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
// Сообщение от кнопки Connect
ON_BN_CLICKED(IDC_CONNECT, OnConnect)
// Сообщение от кнопки On Top
ON_BN_CLICKED(IDC_ON_TOP, OnOnTop)
// Сообщение с кодом извещения NM_DBLCLK от списка
ON_NOTIFY(NM_DBLCLK, IDC_FTP_LIST, OnDblclkFtpList)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
//============================================================
// Метод OnInitDialog класса CFtpViewDlg
// Выполняет инициализацию диалоговой панели, а также сеанса
// связи с Internet (создает объект класса CInternetSession)
//============================================================
BOOL CFtpViewDlg::OnInitDialog()
{
// Вызываем метод OnInitDialog базового класса CDialog
CDialog::OnInitDialog();
// Устанавливаем пиктограммы, которые будут отображаться
// в случае минимизации диалоговой панели
SetIcon(m_hIcon,TRUE); // Пиктограмма стандартного размера
SetIcon(m_hIcon,FALSE); // Пиктограмма маленького размера
//=========================================================
// Выполняем инициализацию списка IDC_FTP_LIST
//=========================================================
// Структура, для описания характеристик колонок списка
LV_COLUMN lv_column;
// Переменная для определения размера списка
CRect rectList;
// Названия для колонок списка
TCHAR szColHeader[COL_NUM][10] = {
_T("Name"),
_T("Length"),
_T("Date"),
_T("Time"),
};
// Определяем размер области, которую занимает список
// IDC_FTP_LIST в диалоговой панели
m_FtpList.GetWindowRect(&rectList);
// Указываем поля структуры lv_column, которые будут
// использоваться
lv_column.mask = LVCF_FMT | // Используется поле fmt
LVCF_SUBITEM | // Используется поле iSubItem
LVCF_TEXT | // Используется поле pszText
LVCF_WIDTH; // Используется поле cx
// Задаем выравнивание по левому краю
lv_column.fmt = LVCFMT_LEFT;
// Ширина колонки
lv_column.cx = (rectList.Width() / COL_NUM) - 1;
// Определяем характеристики колонок списка
for (int i = 0; i < COL_NUM; i++)
{
// Номер колонки
lv_column.iSubItem = i;
// Заголовок колонки
lv_column.pszText = szColHeader[i];
// Добавляем колонку с заданными свойствами к списку
m_FtpList.InsertColumn(i, &lv_column);
}
// Создаем список из двух изображений размера 16 х 16
m_ImageList = new CImageList();
m_ImageList -> Create(16, 16, TRUE, 2, 2);
// Добавляем в список две пиктограммы -
// IDI_DIRECTORY (изображение каталога) и
// IDI_FILE(изображение файла )
m_ImageList -> Add(AfxGetApp()->LoadIcon(IDI_DIRECTORY));
m_ImageList -> Add(AfxGetApp()->LoadIcon(IDI_FILE));
// Выбираем список изображений m_ImageList для
// использования в списке IDC_FTP_LIST
m_FtpList.SetImageList(m_ImageList, LVSIL_SMALL);
//=========================================================
// Выбираем адрес сервера FTP, который используется по
// умолчанию
//=========================================================
m_FtpAddress = "dials.ccas.ru"; // Сервер FTP “ДиалогНаука”
// Отображаем адрес на экране
UpdateData(FALSE);
//=========================================================
// Инициализируем сеанс связи с Internet
//=========================================================
// Создаем сеанс связи с Internet, указываем в качестве
// имени программы-клиента название приложения FtpView
m_InternetSession = new CInternetSession("FtpView");
// В случае ошибки отображаем сообщение и завершаем
// приложение
if(!m_InternetSession)
{
AfxMessageBox("New Session Error", MB_OK);
OnOK();
}
// Инициализируем указатель m_FtpConnection
m_FtpConnection = NULL;
return TRUE;
}
//============================================================
// Метод OnPaint класса CFtpViewDlg
// Отображает на экране пиктограмму в случае минимизации
// главной диалоговой панели приложения
//============================================================
void CFtpViewDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this);
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 класса CFtpViewDlg
// Сообщает идентификатор пиктограммы, отображаемой в случае
// минимизации приложения
//============================================================
HCURSOR CFtpViewDlg::OnQueryDragIcon()
{
return (HCURSOR) m_hIcon;
}
//============================================================
// Метод OnOnTop класса CFtpViewDlg
// Переходит в каталог верхнего уровня
//============================================================
void CFtpViewDlg::OnOnTop()
{
// Блокируем список IDC_FTP_LIST
m_FtpList.EnableWindow(FALSE);
// Изменяем строку текущего каталога sCurentDirectory так,
// чтобы она показывала на каталог верхнего уровня.
// Ищем последнее вхождение символа / в строку с именем
// каталога
int iNum = sCurentDirectory.ReverseFind('/');
if(iNum == -1)
{
// Если символ / не обнаружен, значит мы находимся в
// корневом каталоге
AfxMessageBox("No top directory");
}
else
{
// Удаляем из строки с именем текущего каталога названия
// последнего каталога
sCurentDirectory = sCurentDirectory.Left(iNum);
// Меняем форму курсора (курсор “ожидание”)
CWaitCursor wait;
// Отображаем содержимое каталога верхнего уровня
DirectoryView();
}
// Снимаем блокировку списка IDC_FTP_LIST
m_FtpList.EnableWindow(TRUE);
// Отображаем на диалоговой панели новый путь каталога
m_Status.SetWindowText(sCurentDirectory);
return;
}
//============================================================
// Метод OnDblclkFtpList класса CFtpViewDlg
// Переходит в выбранный каталог
//============================================================
void CFtpViewDlg::OnDblclkFtpList(NMHDR* pNMHDR,
LRESULT* pResult)
{
int iTotalNumber; // Количество элементов списка
CString sSelItem; // Название каталога
CString sLength_Dir; // Длина файла или строка Dir
// Блокируем список IDC_FTP_LIST
m_FtpList.EnableWindow(FALSE);
// Определяем количество элементов в списке IDC_FTP_LIST
iTotalNumber = m_FtpList.GetItemCount();
// Определяем, какой объект списка выбран
for(int i = 0; i < iTotalNumber; i++)
{
// Атрибут LVIS_SELECTED установлен
// у выбранного элемента списка
if(LVIS_SELECTED == m_FtpList.GetItemState( i,
LVIS_SELECTED ))
{
// Определяем название выбранного элемента списка
// (имя файла или каталога)
sSelItem = m_FtpList.GetItemText( i, 0 );
// Считываем данные из колонки Length
sLength_Dir = m_FtpList.GetItemText( i, 1 );
if(sLength_Dir == "Dir") // Выбран каталог
// Переходим в выбранный каталог
sCurentDirectory =
sCurentDirectory + "/" + sSelItem;
else // Выбран файл
// Отображаем имя файла
AfxMessageBox("You select file " + sSelItem);
break;
}
}
// Меняем форму курсора (курсор “ожидание”)
CWaitCursor wait;
// Отображаем содержимое выбранного каталога
DirectoryView();
// Отображаем в диалоговой панели новый путь каталога
m_Status.SetWindowText(sCurentDirectory);
// Снимаем блокировку списка IDC_FTP_LIST
m_FtpList.EnableWindow(TRUE);
*pResult = 0;
}
//============================================================
// Метод OnConnect класса CFtpViewDlg
// Соединяется с указанным сервером FTP
//============================================================
void CFtpViewDlg::OnConnect()
{
// Текущий каталог на сервере FTP
CString sCurrentFtpDirectory = "";
// Блокируем кнопки Connect, OK и On Top
m_Connect.EnableWindow(FALSE);
m_Ok.EnableWindow(FALSE);
m_OnTop.EnableWindow(FALSE);
// Если вы ранее уже соединились с сервером FTP, разрываем
// эту связь и удаляем объект m_FtpConnection
if (m_FtpConnection != NULL)
{
m_FtpConnection -> Close();
delete m_FtpConnection;
m_FtpConnection = NULL;
}
// Считываем из диалоговой панели адрес сервера FTP, так
// как пользователь уже мог его изменить
UpdateData(TRUE);
// Пытаемся соединиться с сервером FTP
try
{
// Меняем форму курсора (курсор “ожидание”)
CWaitCursor wait;
// Соединяемся с сервером FTP. Эта операция
// может вызвать исключение CInternetException
m_FtpConnection =
m_InternetSession->GetFtpConnection(m_FtpAddress);
}
catch (CInternetException* pEx)
{
// Обрабатываем исключение CInternetException
TCHAR szErr[1024]; // временный буфер для сообщения
// Выводим сообщение об ошибке
if (pEx->GetErrorMessage(szErr, 1024))
AfxMessageBox(szErr);
else
AfxMessageBox("GetFtpConnection Error");
// Удаляем исключение
pEx->Delete();
// Обнуляем указатель m_FtpConnection
m_FtpConnection = NULL;
}
// Если соединение не установлено сообщяем об этом
if( m_FtpConnection == NULL )
m_Status.SetWindowText("Connect not established");
// Если соединение установлено, определяем текущий каталог
// и отображаем его содержимое на экране
else
{
// Определяем текущий каталог сервера FTP
BOOL fResult=
m_FtpConnection ->
GetCurrentDirectory(sCurrentFtpDirectory);
if(fResult)
sCurentDirectory = sCurrentFtpDirectory;
else
AfxMessageBox("GetCurrentDirectory Error");
// Меняем форму курсора (курсор “ожидание”)
CWaitCursor wait;
// Отображаем содержимое выбранного каталога
DirectoryView();
// Отображаем на диалоговой панели новый путь каталога
m_Status.SetWindowText(sCurentDirectory);
}
// Снимаем блокировку кнопок Connect, OK и On Top
m_Connect.EnableWindow(TRUE);
m_Ok.EnableWindow(TRUE);
m_OnTop.EnableWindow(TRUE);
}
//============================================================
// Метод DirectoryView класса CFtpViewDlg
// Просматривает содержимое каталога и отображает его в
// таблице m_FtpList
//============================================================
BOOL CFtpViewDlg::DirectoryView()
{
// Переменная, сигнализирующая о получении последнего
// элемента каталога
BOOL fResult;
// Временная переменная, определяющая тип объекта -
// файл или каталог
BOOL fDirectory;
// Структура для добавления нового элемента к списку
LV_ITEM lv_item;
// Удалить все элементы из списка IDC_FTP_LIST
m_FtpList.DeleteAllItems();
// Создаем объект класса CFtpFileFind, указывая
// объект, представляющий уже установленное соединение
// с сервером FTP
CFtpFileFind m_FtpFileFind(m_FtpConnection);
// Получаем имена всех объектов текущего каталога
if(fResult =
m_FtpFileFind.FindFile(_T(sCurentDirectory + "/*")))
{
for(int n = 0;fResult; n++)
{
// Получаем очередной объект из каталога
fResult = m_FtpFileFind.FindNextFile();
// Определяем что это - каталог или файл
fDirectory = m_FtpFileFind.IsDirectory();
//============= Определяем имя объекта ==============
// Временные строка для имени каталога или файла
CString fileName;
// Определяем имя объекта
fileName = m_FtpFileFind.GetFileName();
// Заполняем структуру lv_item, сведениями об
// очередном объекте каталога сервера FTP. Указываем,
// что в список добавляется текст и изображение
lv_item.mask = LVIF_TEXT | LVIF_IMAGE;
// Указываем номер строки в списке
lv_item.iItem = n;
// Заполняем первую колонку
lv_item.iSubItem = 0;
// Выбираем изображение для нового элемента списка в
// зависимости от типа объекта
lv_item.iImage = (fDirectory) ? DIRECTORY : FILE;
// Указываем имя каталога или файла
lv_item.pszText = fileName.GetBuffer(MIN_LEN_BUF);
// Добавляем новый элемент к списку IDC_FTP_LIST
m_FtpList.InsertItem(&lv_item);
//============= Определяем длину файла =============
// Длинна файла
DWORD dwLength = 0;
// Временные строка для формирования текстового
// представления длинны файла
CString sLength;
// Заполняем колонку Length для новой записи и
// записываем в нее длинну файла или строку Dir, если
// новый объект - каталог.
// Добавляется только текст без пиктограммы
lv_item.mask = LVIF_TEXT;
// Указываем номер строки в списке
lv_item.iItem = n;
// Заполняем вторую колонку
lv_item.iSubItem = 1;
// Если очередной объект является каталогом, то
// вместо в колонке Length записываем строку Dir
if(fDirectory)
{
lv_item.pszText = "Dir";
}
// Если очередной объект является файлом, то
// записываем его длину в колонку Length
else
{
// Определяем длину файла
dwLength = m_FtpFileFind.GetLength();
// Формируем текстовое представление длины файла
sLength.Format("%d", dwLength);
lv_item.pszText = sLength.GetBuffer(MIN_LEN_BUF);
}
// Добавляем запись во второй колонке списка (колонка
// Length)
m_FtpList.SetItem(&lv_item);
//======== Определяем дату и время создания =========
// Дата и время создания каталога или файла
CTime mTime;
// Временные строки для формирования текстового
// представления даты и времени
CString sDate;
CString sTime;
// Определяем время изменения файла или каталога
if(!m_FtpFileFind.GetLastWriteTime(mTime))
break;
// Добавляется только текст без пиктограммы
lv_item.mask = LVIF_TEXT;
// Указываем номер строки в списке
lv_item.iItem = n;
// Заполняем третью колонку
lv_item.iSubItem = 2;
// Выделяем из объекта mTime день, месяц и год
sDate = mTime.Format("%d.%m.%y");
// Записываем сформированную дату в структуру lv_item
lv_item.pszText = sDate.GetBuffer(MIN_LEN_BUF);
// Добавляем запись во второй колонке списка (колонка
// Date)
m_FtpList.SetItem(&lv_item);
// Заполняем четвертую колонку, записываем в нее
// время последнего изменения файла (каталога)
lv_item.iSubItem = 3;
// Выделяем из объекта mTime часы, минуты и секунды
sTime = mTime.Format("%H:%M:%S");
// Записываем сформированную строку, содержащую время
lv_item.pszText = sTime.GetBuffer(MIN_LEN_BUF);
// Добавляем запись во второй колонке списка (колонка
// Time)
m_FtpList.SetItem(&lv_item);
}
// Заканчиваем поиск объектов в каталоге, закрываем
// объект m_FtpFileFind
m_FtpFileFind.Close();
}
// Если каталог не содержит других объектов - каталогов и
// файлов, выводин соответствующее сообщение
else
AfxMessageBox("File's not found or error");
return TRUE;
}
Кроме уже описанных нами файлов в проект FtpView входят еще два исходных файла, содержащих программный код. Это файлы stdafx.cpp и включаемый файл stdafx.h. Исходный текст файла stdafx.cpp содержится в листинге 2.8. Как видите, он состоит из единственной директивы #include, включающей файл stdafx.h.
Листинг 2.8. Файл stdafx.cpp
// Включаем файл stdafx.h, определенный в нашем приложении
#include “stdafx.h“
Файл stdafx.h задействует часто используемые включаемые системные файлы - afxwin.h, afxext.h, afxcmn.h и afxinet.h. Эти файлы не изменяются. Поэтому Microsoft Visual C++ компилирует их только один раз. За счет этого значительно сокращается время, затрачиваемое на повторное построение проекта.
Последний включаемый файл afxinet.h содержит описание классов, структур и констант библиотеки MFC, относящихся к программному интерфейсу WinInet (листинг 2.9). MFC AppWizard не включает этот файл по умолчанию. Вы должны добавить соответствующую директиву #include самостоятельно.
#include "stdafx.h"
Листинг 2.9. Файл stdafx.h
// Исключает редко используемые определения при обработке
// файлов заголовков
#define VC_EXTRALEAN
// Основные компоненты библиотеки MFC
#include <afxwin.h>
// Расширения MFC
#include <afxext.h>
#ifndef _AFX_NO_AFXCMN_SUPPORT
// Используется для органов управления Windows
#include <afxcmn.h>
#endif // _AFX_NO_AFXCMN_SUPPORT
// Включаемый файл для библиотеки WinInet.
// MFC AppWizard не включает этот файл, вы должны сделать это
// самостоятельно
#include "afxinet.h"
Класс CGopherConnection
Класс CGopherConnection управляет соединением с сервером Gopher. Класс CGopherConnection наследуется от базового класса CInternetConnection:
CObject -> CInternetConnection -> CGopherConnection
В состав класса CGopherConnection входят конструктор и три метода - OpenFile, CreateLocator, GetAttribute. Метод OpenFile открывает файл на сервере Gopher. С помощью метода CreateLocator можно выполнить поиск файлов на сервере Gopher, а метод GetAttribute позволяет получить различную информацию о объекте на сервере.
С классом CGopherConnection непосредственно связаны еще два класса - CGopherLocator и CGopherFileFind. Эти классы предназначены для работы с серверами Gopher.
Серверы Gopher, также как и сервера WWW, предоставляют доступ к гипертекстовой информации. Однако они имеют значительно меньше возможностей и таких серверов постепенно становится все меньше и меньше. Существует мнение, что серверы Gopher остались только в тех организациях, которые не в состоянии оплатить создание сервера WWW и перенос на него всей накопленной информации. Поэтому мы не будем подробно останавливаться на соответствующих классах MFC. Дополнительную информацию о них вы можете получить из документации Microsoft Visual C++, а примеры программ в книге Special Edition Using Visual C++ 4.2.
Класс CGopherFile
Также как класс CHttpFile, класс CGopherFile наследуется от базового класса CInternetFile. Вместе с другими классами WinInet он позволяет организовать поиск и получение файлов с серверов Gopher.
В класс CGopherFile входит конструктор CGopherFile и метод Close, который закрывает соединение с сервером Gopher.
Класс CGopherFileFind
Класс CGopherFileFind наследуется от базового класса CFileFind и используется для поиска файлов на серверах Gopher. В следующей таблице мы привели описание различных методов класса CGopherFileFind:
Метод | Описание | ||
CGopherFileFind | Конструктор класса CGopherFileFind. Создает объект класса CGopherFileFind | ||
FindFile | Начинает поиск файла или файлов на сервере Gopher | ||
FindNextFile | Продолжает поиск файла или файлов в указанном каталоге сервера Gopher. Вы должны использовать этот метод после обращения к методу FindFile | ||
GetLocator | Определяет объект CGopherLocator | ||
GetScreenName | Определяет имя экрана Gopher | ||
GetLength | Определяет длину файла в байтах |
Класс CGopherLocator
Класс CGopherLocator наследуется непосредственно от базового класса CObject. Этот класс предназначен для доступа к серверам Gopher.
CObject -> CGopherLocator
В состав метода CGopherLocator входит конструктор класса, метод GetLocatorType и оператор LPCTSTR.
Метод GetLocatorType разбирает локатор (gopher locator) и определяет его атрибуты, а оператор LPCTSTR позволяет получить прямой доступ к данным, записанным в объекте CGopherLocator как к обычной строке символов.
Класс CHttpConnection
Класс CHttpConnection позволяет приложению взаимодействовать с сервером WWW. Этот класс наследуется от базового класса CInternetConnection:
CObject -> CInternetConnection -> CHttpConnection
Кроме конструктора в состав класса CHttpConnection входит только один метод OpenRequest, который устанавливает соединение с сервером HTTP.
Конструктор класса CHttpConnection никогда не вызывается напрямую. Объект класса CHttpConnection создается при вызове метода GetHttpConnection класса CInternetSession. Поэтому мы опустим описание конструктора класса и сразу перейдем к методу OpenRequest.
Класс CHttpFile
Класс CHttpFile наследуется от базового класса CInternetFile. Он позволяет работать с сервером WWW по протоколу HTTP. В следующей таблице мы представили описание методов класса CHttpFile:
Метод | Описание | ||
CHttpFile | Конструктор класса. Создает объект CHttpFile | ||
AddRequestHeaders | Добавляет заголовок к запросу HTTP, передаваемому на сервер WWW | ||
SendRequest | Передает запрос HTTP на сервер WWW | ||
QueryInfo | Получает ответ или заголовок запроса от сервера WWW | ||
QueryInfoStatusCode | Определяет код состояния, связанный с данным запросом HTTP | ||
GetVerb | Определяет действие, которое было указано в запросе, переданном на сервер WWW | ||
GetObject | Определяет объект, для которого был выполнен запрос на сервер WWW | ||
GetFileURL | Позволяет получить имя файла на сервере WWW в формате URL | ||
Close | Закрывает объект CHttpFile и освобождает все используемые им ресурсы |
Класс CInternetConnection
Класс CInternetConnection управляет наиболее общими характеристиками соединения с серверами Internet. Если приложению требуется использовать расширенный сервис серверов FTP, HTTP и системы Gopher, воспользуйтесь классами CFtpConnection, CHttpConnection и CGopherConnection. Эти классы наследуются от базового класса CInternetConnection, добавляя к нему набор специфических методов. Сам класс CInternetConnection наследуется от базового класса CObject:
CObject -> CInternetConnection -> CFtpConnection
|
-> CHttpConnection
|
-> CGopherConnection
В состав класса CInternetConnection, кроме конструктора, входят три метода GetContext, GetSession, GetServerName и оператор HINTERNET.
Все методы класса CInternetConnection предназначены для определения параметров соединения с сервером. Метод GetContext позволяет узнать идентификатор контекста объекта, представляющего соединение. Метод GetSession определяет объект класса CInternetSession, в рамках которого установлено соединение с сервером. Метод GetServerName возвращает имя сервера.
Оператор HINTERNET не представляет особого интереса и позволяет узнать идентификатор сеанса связи с Internet. Он используется, если в вашем приложении одновременно применяются классы MFC, управляющие WinInet и функции программного интерфейса WinInet.
Мы не будем напрямую вызывать методы класса CInternetConnection в своих приложениях и поэтому не станем останавливаться на них более подробно и рассмотрим только оператор HINTERNET, так как он входит во многие другие классы WinInet.
Класс CInternetException
Для обработки ошибок, возникающих при работе с WinInet, в состав библиотеки MFC включен новый класс CInternetException. Точно также как и другие классы MFC, предназначенные для обработки различных исключительных ситуаций, класс CInternetException наследован от базового класса CException:
CObject -> CException -> CInternetException
Класс CInternetFile
В 28 томе, посвященном библиотеке MFC мы описывали классы CFile и CStdioFile, предназначенные для работы с файловой системой компьютера. Среди классов WinInet, входящих в библиотеку MFC, существует класс CInternetFile, наследованный от базового класса CStdioFile. В этом классе определены только самые общие методы для работы с серверами Internet.
От класса CInternetFile наследуются еще два класса WinInet - CGopherFile и CHttpFile. Эти классы ориентированны на работу, соответственно, с серверами Gopherf и HTTP:
CObject -> CFile -> CStdioFile -> CInternetFile -> CGopherFile
|
-> CHttpFile
Краткое описание методов, входящих в состав класса CInternetFile мы представили в следующей таблице:
Метод | Описание | ||
CInternetFile | Конструктор класса CInternetFile | ||
Abort | Закрывает файл на сервере, не принимая во внимание все возможные предупреждения и ошибки | ||
Close | Закрывает файл CInternetFile и освобождает используемые им ресурсы | ||
Flush | При записи данных на сервер классы WinInet выполняют их буферизацию. Метод Flush принудительно передает данные из буфера на сервер | ||
HINTERNET | Возвращает идентификатор текущего сеанса связи с Internet | ||
Read | Считывает данные с сервера | ||
ReadString | Считывает строку символов из файла на сервере | ||
Seek | Перемещает указатель в открытом файле на сервере | ||
SetReadBufferSize | Устанавливает размер буфера для данных, которые загружаются с сервера | ||
SetWriteBufferSize | Устанавливает размер буфера для данных, которые записываются на сервер | ||
Write | Записывает данные на сервер | ||
WriteString | Записывает в файл на сервере строку символов, закрытую нулем |
Кроме перечисленных методов в состав класса CInternetFile входит элемент данных m_hFile, содержащий идентификатор файла.
Класс CInternetSession
Класс CInternetSession представляет сеанс. Вы должны создать объект класса CInternetSession перед использованием остальных классов и методов WinInet. Вы можете либо непосредственно создать объект класса CInternetSession, либо сначала наседовать от класса CInternetSession собственный клас и использовать уже его.
Класс CInternetSession наследуется от базового класса CObject, лежащего в основе большинства классов библиотеки MFC:
CObject -> CInternetSession
Кроме конструктора, в состав класса CInternetSession входят несколько методов, выполняющих разнообразные действия. Они позволяют определить и изменить характеристиками данного сеанса связи, открыть для чтения объект на указанном сервере Internet, установить соединение с серверами FTP, WWW и Gopher и т. д. В следующей таблице мы привели список этих методов:
Метод | Описание | ||
CInternetSession | Конструктор класса CInternetSession | ||
Close | Закрывает соединение с Internet. Вы должны вызвать этот метод после того, как вы закончите использовать объект CInternetSession | ||
EnableStatusCallback | Управляет работой функции обратного вызова WinInet. Эта функция реализована как метод OnStatusCallback класса CInternetSession | ||
GetContext | Определяет значение идентификатора контекста для данного сеанса связи | ||
GetFtpConnection | Устанавливает сеанс связи с сервером FTP | ||
GetGopherConnection | Устанавливает сеанс связи с сервером Gopher | ||
GetHttpConnection | Устанавливает сеанс связи с сервером WWW | ||
HINTERNET | Возвращает идентификатор текущего сеанса связи с Internet | ||
OnStatusCallback | Данный метод вызывается когда изменяется состояние сеанса связи. Чтобы разрешить использование этой функции необходимо воспользоваться методом EnableStatusCallback | ||
OpenURL | Открывает объект, расположенный по заданному адресу URL, для загрузки в локальный компьютер | ||
QueryOption | Запрашивает различные характеристики соединения с Internet. Например время, по истечении которого, запрос отменяется в случае если на него не получен ответ, размеры буферов, используемых для чтения и записи и т. д. Вы можете менять все эти характеристики при помощи метода SetOption, также входящего в класс CInternetSession | ||
ServiceTypeFromHandle | Определить тип сервиса (ftp, http, gopher, file), соответствующий данному идентификатору | ||
SetOption | Устанавливает различные параметры сеанса связи с Internet. Чтобы узнать значение текущих параметров связи следует воспользоваться методом QueryOption |
Рассмотрим более подробно конструктор класса и те его методы, которые будут нами использоваться в дальнейшем.
Класс CLookApp
Главный класс приложения CLookApp, наследованный от базового класса CWinApp, определен во включаемом файле Look.h. Исходный текст этого файла представлен в листинге 4.1. Фактически в классе CLookApp определен только конструктор класса и переопределен метод InitInstance базового класса CWinApp.
Листинг 4.1. Файл Look.h
#ifndef __AFXWIN_H__
#error include 'stdafx.h' before including this file for PCH
#endif
#include "resource.h"
//////////////////////////////////////////////////////////////
// Определение класса CLookApp
//
class CLookApp : public CWinApp
{
public:
CLookApp();
// Overrides
//{{AFX_VIRTUAL(CLookApp)
public:
virtual BOOL InitInstance();
//}}AFX_VIRTUAL
// Implementation
//{{AFX_MSG(CLookApp)
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
//////////////////////////////////////////////////////////////
Реализация класса CLookApp содержится в файле Look.cpp (листинг 4.2). В нем определены конструктор класса CLookApp, метод InitInstance и таблица сообщений класса CLookApp. Кроме того, в файле Look.cpp объявлен глобальный объект theApp главного класса приложения CLookApp.
Листинг 4.2. Файл Look.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
//////////////////////////////////////////////////////////////
// Таблица сообщений класса CLookApp
BEGIN_MESSAGE_MAP(CLookApp, CWinApp)
//{{AFX_MSG_MAP(CLookApp)
// DO NOT EDIT
//}}AFX_MSG
ON_COMMAND(ID_HELP, CWinApp::OnHelp)
END_MESSAGE_MAP()
//////////////////////////////////////////////////////////////
// Конструктор класса CLookApp
CLookApp::CLookApp()
{
// TODO: add construction code here,
// Place all significant initialization in InitInstance
}
//////////////////////////////////////////////////////////////
// Объект глаавного класса приложения
CLookApp theApp;
//////////////////////////////////////////////////////////////
// Метод InitInstance класса CLookApp.
// Выполняет инициализацию приложения
BOOL CLookApp::InitInstance()
{
// Разрешаем использование органов управления ActiveX
AfxEnableControlContainer();
// Выполняем стандартную инициализацию
#ifdef _AFXDLL
Enable3dControls();
#else
Enable3dControlsStatic();
#endif
// Отображаем на экране диалоговую панель приложения
CLookDlg dlg;
m_pMainWnd = &dlg;
int nResponse = dlg.DoModal();
if (nResponse == IDOK)
{
// TODO: Нажата клавиша OK
}
else if (nResponse == IDCANCEL)
{
// TODO: Нажата клавиша Cancel
}
return FALSE;
}
Класс CLookDlg
Основную работу по управлению диалоговой панелью приложения выполняет класс CLookDlg. Именно в него мы добавляли элементы, представляющие органы управления и методы, обрабатывающие сообщения от диалоговой панели.
Класс CLookDlg и органы управления панели IDD_LOOK_DIALOG
Чтобы нам было удобно работать с органами управления диалоговой панели IDD_LOOK_DIALOG, запустите MFC ClassWizard и привяжите к ним переменные, добавив их к классу CLookDlg. К полям редактирования IDC_COMBO_ADDRESS, IDC_TITLE_BAR и IDC_STATUS_TEXT привяжите строки m_address, m_TitleBar и m_StatusText. Эти переменные будут использоваться нами, чтобы узнать адрес сервера, выбранный из списка IDC_COMBO_ADDRESS и вывести в полях IDC_TITLE_BAR и IDC_STATUS_TEXT заголовок страницы и строку состояния.
К линейному индикатору IDC_PROGRESS привяжите объект m_progress. Обратите внимание, что это управляющий объект класса CProgressCtrl и чтобы изменять его состояние мы будем пользоваться методами этого класса.
И, наконец, самое главное. К навигатору IDC_EXPLORER вы должны привязать управляющий объект m_explorer. Для него надо выбрать класс CWebBrowser. Напомним, что этот класс был добавлен в наш проект, когда мы вставили в него орган управления Microsoft Web Browser Control. Этот класс содержит большое количество методов, позволяющих управлять навигатором - переходить к просмотру заданных страниц, обновлять отображаемую информацию и т. д.
Рис. 4.10. Диалоговая панель IDD_LOOK_DIALOG и MFC ClassWizard
Внешний вид диалоговой панели MFC ClassWizard после того как мы добавили ко всем органам управления панели IDD_LOOK_DIALOG управляющие объекты (кроме кнопок) представлен на рисунке 4.10.
Класс CWebBrowser
Определение класса CWebBrowser расположено в файле webbrowser.h, исходный текст которого представлен в листинге 4.1. Методы GetClsid и Create определены непосредственно в самом классе CWebBrowser. Остальные методы класса CWebBrowser определены в файле webbrowser.cpp, содержащимся в листинге 4.3. Мы оставили комментарии на английском языке, которые были добавлены во время вставки Microsoft Web Browser Control в проект.
Листинг 4.3. Файл webbrowser.h
#ifndef __WEBBROWSER_H__
#define __WEBBROWSER_H__
// Machine generated IDispatch wrapper class(es) created by
// Microsoft Visual C++
// NOTE: Do not modify the contents of this file. If this
// class is regenerated by Microsoft Visual C++, your
// modifications will be overwritten.
//////////////////////////////////////////////////////////////
// CWebBrowser wrapper class
class CWebBrowser : public CWnd
{
protected:
DECLARE_DYNCREATE(CWebBrowser)
public:
CLSID const& GetClsid()
{
static CLSID const clsid
= { 0xeab22ac3, 0x30c1, 0x11cf,
{ 0xa7, 0xeb, 0x0, 0x0, 0xc0, 0x5b, 0xae, 0xb }
};
return clsid;
}
virtual BOOL Create(
LPCTSTR lpszClassName,
LPCTSTR lpszWindowName, DWORD dwStyle,
const RECT& rect,
CWnd* pParentWnd, UINT nID,
CCreateContext* pContext = NULL)
{
return CreateControl(
GetClsid(),
lpszWindowName,
dwStyle,
rect,
pParentWnd,
nID);
}
BOOL Create(LPCTSTR lpszWindowName, DWORD dwStyle,
const RECT& rect, CWnd* pParentWnd, UINT nID,
CFile* pPersist = NULL, BOOL bStorage = FALSE,
BSTR bstrLicKey = NULL)
{
return CreateControl(
GetClsid(),
lpszWindowName,
dwStyle,
rect,
pParentWnd,
nID,
pPersist,
bStorage,
bstrLicKey);
}
// Operations
public:
яя // method 'QueryInterface' not emitted because of invalid
яя // return type or parameter type
яя unsigned long AddRef();
яя unsigned long Release();
яя // method 'GetTypeInfoCount' not emitted because of invalid
яя // return type or parameter type
яя // method 'GetTypeInfo' not emitted because of invalid
яя // return type or parameter type
яя // method 'GetIDsOfNames' not emitted because of invalid
яя // return type or parameter type
яя // method 'Invoke' not emitted because of invalid return
яя // type or parameter type
яя void GoBack();
яя void GoForward();
яя void GoHome();
яя void GoSearch();
яя void Navigate(
яяяяя LPCTSTR URL, VARIANT* Flags, VARIANT* TargetFrameName,
яяяяя VARIANT* PostData, VARIANT* Headers);
яя void Refresh();
яя void Refresh2(VARIANT* Level);
яя void Stop();
яя LPDISPATCH GetApplication();
яя LPDISPATCH GetParent();
яя LPDISPATCH GetContainer();
яя LPDISPATCH GetDocument();
яя BOOL GetTopLevelContainer();
яя CString GetType();
яя long GetLeft();
яя void SetLeft(long nNewValue);
яя long GetTop();
яя void SetTop(long nNewValue);
яя long GetWidth();
яя void SetWidth(long nNewValue);
яя long GetHeight();
яя void SetHeight(long nNewValue);
яя CString GetLocationName();
яя CString GetLocationURL();
яя BOOL GetBusy();
};
#endif // __WEBBROWSER_H__
ЌҐ ४®¬Ґ¤гҐвбп ў®бЁвм Ё§¬ҐҐЁп ў Ёбе®¤лҐ вҐЄбвл Є« бб CWebBrowser Ё ⥪бвл ҐЈ® ¬Ґв®¤®ў, а бЇ®«®¦ҐлҐ ў д ©« е webbrowser.h Ё webbrowser.cpp. ќвЁ д ©«л ¬®Јгв Ўлвм ᮧ¤ л Microsoft Visual C++ § ®ў®, Ґб«Ё ўл Ї®ўв®а® ўбв ўЁвҐ ®аЈ гЇа ў«ҐЁп Microsoft Web Browser ў Їа®ҐЄв. ‚ н⮬ б«гз Ґ ўбҐ Ё§¬ҐҐЁп, ўҐбҐлҐ ў ¬Ё ў д ©«л webbrowser.h Ё webbrowser.cpp Ўг¤гв гЁз⮦Ґл.
…б«Ё г ў б ўбҐ ¦Ґ ў®§ЁЄҐв Ґ®Ўе®¤Ё¬®бвм ¬®¤ЁдЁжЁа®ў вм Є« бб CWebBrowser, ᮧ¤ ©вҐ ®ўл© Є« бб, Ї®а®¦¤Ґл© ®в Є« бб CWebBrowser Ё ЁбЇ®«м§г©вҐ ҐЈ®.
¨ Љ®Ј¤ ўл ¤®Ў ў«пҐвҐ ў Їа®ҐЄв ®аЈ гЇа ў«ҐЁп Microsoft Web Browser Control, ў д ©«Ґ ®ЇаҐ¤Ґ«ҐЁп Є« бб ®в¬Ґз Ґвбп, зв® ап¤ ¬Ґв®¤®ў (QueryInterface, AddRef, Release, GetTypeInfoCount, GetTypeInfo, GetIDsOfNames, Invoke) Ґ Ї®¤Є«озҐл, в Є Є Є ®Ё Ё¬Ґов ҐЇа ўЁ«мл© вЁЇ ў®§ўа й Ґ¬®Ј® § зҐЁп Ё«Ё ҐЇа ўЁ«мл© вЁЇ Ї а ¬Ґва®ў. ‚ б«гз Ґ Ґб«Ё ўл Ї®«м§гҐвҐбм Microsoft Visual C++ ўҐабЁЁ 5.0 нвЁ б®®ЎйҐЁп Ґ Ї®пў«повбп, ® ЇҐаҐзЁб«ҐлҐ ¬Ґв®¤л в Є¦Ґ Ґ Ўг¤гв ¤®бвгЇл
‚ᥠ¬Ґв®¤л Є« бб CWebBrowser, § ЁбЄ«о票Ґ¬ ¬Ґв®¤ GetClsid Ё ¤ўге ¬®¤ЁдЁЄ жЁ© ¬Ґв®¤ Create, ®ЇаҐ¤Ґ«Ґл ў д ©«Ґ webbrowser.cpp. €бе®¤л© вҐЄбв нв®Ј® д ©« ЇаҐ¤бв ў«Ґ ў «ЁбвЁЈҐ 4.4. ЊҐв®¤л GetClsid Ё Create ®ЇаҐ¤Ґ«Ґл ҐЇ®б।б⢥® ў ®ЇЁб ЁЁ Є« бб CWebBrowser («ЁбвЁЈ 4.3).
‹ЁбвЁЈ 4.4. ” ©« webbrowser.cpp
// Machine generated IDispatch wrapper class(es) created by
// Microsoft Visual C++
// NOTE: Do not modify the contents of this file.я If this
// class is regenerated by Microsoft Visual C++, your
// modifications will be overwritten.
#include "stdafx.h"
#include "webbrowser.h"
//////////////////////////////////////////////////////////////
// CWebBrowser
IMPLEMENT_DYNCREATE(CWebBrowser, CWnd)
//////////////////////////////////////////////////////////////
// CWebBrowser properties
//////////////////////////////////////////////////////////////
// CWebBrowser operations
unsigned long CWebBrowser::AddRef()
{
яя unsigned long result;
яя InvokeHelper(0x60000001, DISPATCH_METHOD, VT_I4,
яяяяя (void*)&result, NULL);
яя return result;
}
unsigned long CWebBrowser::Release()
{
яя unsigned long result;
яя InvokeHelper(0x60000002, DISPATCH_METHOD, VT_I4,
яяяяя (void*)&result, NULL);
яя return result;
}
void CWebBrowser::GoBack()
{
яя InvokeHelper(0x64, DISPATCH_METHOD, VT_EMPTY, NULL, NULL);
}
void CWebBrowser::GoForward()
{
яя InvokeHelper(0x65, DISPATCH_METHOD, VT_EMPTY, NULL, NULL);
}
void CWebBrowser::GoHome()
{
яя InvokeHelper(0x66, DISPATCH_METHOD, VT_EMPTY, NULL, NULL);
}
void CWebBrowser::GoSearch()
{
яя InvokeHelper(0x67, DISPATCH_METHOD, VT_EMPTY, NULL, NULL);
}
void CWebBrowser::Navigate(
яя LPCTSTR URL,
яя VARIANT* Flags,
яя VARIANT* TargetFrameName,
яя VARIANT* PostData,
яя VARIANT* Headers)
{
яя static BYTE parms[] =
яяяяя VTS_BSTR VTS_PVARIANT VTS_PVARIANT
яяяяя VTS_PVARIANT VTS_PVARIANT;
яя InvokeHelper(0x68, DISPATCH_METHOD, VT_EMPTY, NULL, parms,
яяяяяя URL, Flags, TargetFrameName, PostData, Headers);
}
void CWebBrowser::Refresh()
{
яя InvokeHelper(DISPID_REFRESH, DISPATCH_METHOD, VT_EMPTY,
яяяяя NULL, NULL);
}
void CWebBrowser::Refresh2(VARIANT* Level)
{
яя static BYTE parms[] = VTS_PVARIANT;
яя InvokeHelper(0x69, DISPATCH_METHOD, VT_EMPTY, NULL, parms,
яяяяя Level);
}
void CWebBrowser::Stop()
{
яя InvokeHelper(0x6a, DISPATCH_METHOD, VT_EMPTY, NULL, NULL);
}
LPDISPATCH CWebBrowser::GetApplication()
{
яя LPDISPATCH result;
яя InvokeHelper(0xc8, DISPATCH_PROPERTYGET, VT_DISPATCH,
яяяяя (void*)&result, NULL);
яя return result;
}
LPDISPATCH CWebBrowser::GetParent()
{
яя LPDISPATCH result;
яя InvokeHelper(0xc9, DISPATCH_PROPERTYGET, VT_DISPATCH,
яяяяя (void*)&result, NULL);
яя return result;
}
LPDISPATCH CWebBrowser::GetContainer()
{
яя LPDISPATCH result;
яя InvokeHelper(0xca, DISPATCH_PROPERTYGET, VT_DISPATCH,
яяяяя (void*)&result, NULL);
яя return result;
}
LPDISPATCH CWebBrowser::GetDocument()
{
яя LPDISPATCH result;
яя InvokeHelper(0xcb, DISPATCH_PROPERTYGET, VT_DISPATCH,
яяяяя (void*)&result, NULL);
яя return result;
}
BOOL CWebBrowser::GetTopLevelContainer()
{
яя BOOL result;
яя InvokeHelper(0xcc, DISPATCH_PROPERTYGET, VT_BOOL,
яяяяя (void*)&result, NULL);
яя return result;
}
CString CWebBrowser::GetType()
{
яя CString result;
яя InvokeHelper(0xcd, DISPATCH_PROPERTYGET, VT_BSTR,
яяяяя (void*)&result, NULL);
яя return result;
}
long CWebBrowser::GetLeft()
{
яя long result;
яя InvokeHelper(0xce, DISPATCH_PROPERTYGET, VT_I4,
яяяяя (void*)&result, NULL);
яя return result;
}
void CWebBrowser::SetLeft(long nNewValue)
{
яя static BYTE parms[] = VTS_I4;
яя InvokeHelper(0xce, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL,
яяяяя parms, nNewValue);
}
long CWebBrowser::GetTop()
{
яя long result;
яя InvokeHelper(0xcf, DISPATCH_PROPERTYGET, VT_I4,
яяяяя (void*)&result, NULL);
яя return result;
}
void CWebBrowser::SetTop(long nNewValue)
{
яя static BYTE parms[] = VTS_I4;
яя InvokeHelper(0xcf, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL,
яяяяя parms, nNewValue);
}
long CWebBrowser::GetWidth()
{
яя long result;
яя InvokeHelper(0xd0, DISPATCH_PROPERTYGET, VT_I4,
яяяяя (void*)&result, NULL);
яя return result;
}
void CWebBrowser::SetWidth(long nNewValue)
{
яя static BYTE parms[] = VTS_I4;
яя InvokeHelper(0xd0, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL,
яя parms, nNewValue);
}
long CWebBrowser::GetHeight()
{
яя long result;
яя InvokeHelper(0xd1, DISPATCH_PROPERTYGET, VT_I4,
яяяяя (void*)&result, NULL);
яя return result;
}
void CWebBrowser::SetHeight(long nNewValue)
{
яя static BYTE parms[] = VTS_I4;
яя InvokeHelper(0xd1, DISPATCH_PROPERTYPUT, VT_EMPTY, NULL,
яя parms, nNewValue);
}
CString CWebBrowser::GetLocationName()
{
яя CString result;
яя InvokeHelper(0xd2, DISPATCH_PROPERTYGET, VT_BSTR,
яяяяя (void*)&result, NULL);
яя return result;
}
CString CWebBrowser::GetLocationURL()
{
яя CString result;
яя InvokeHelper(0xd3, DISPATCH_PROPERTYGET, VT_BSTR,
яяяяя (void*)&result, NULL);
яя return result;
}
BOOL CWebBrowser::GetBusy()
{
яя BOOL result;
яя InvokeHelper(0xd4, DISPATCH_PROPERTYGET, VT_BOOL,
яяяяя (void*)&result, NULL);
яя return result;
}
‚ᥠ¬Ґв®¤л, ®ЇаҐ¤Ґ«ҐлҐ ў д ©«Ґ webbrowser.cpp, ўл§лў ов ўбЇ®¬®Ј ⥫мл© ¬Ґв®¤ InvokeHelper Є« бб CWnd, ЇҐаҐ¤ ў п Ґ¬г а §«ЁзлҐ Ї а ¬Ґвал. ‚ § ўЁбЁ¬®бвЁ ®в бў®Ёе Ї а ¬Ґва®ў, ¬Ґв®¤ InvokeHelper, ў бў®о ®зҐаҐ¤м, ўл§лў Ґв ⥠Ё«Ё ЁлҐ ¬Ґв®¤л ®аЈ гЇа ў«ҐЁп ActiveX. ‚ 襬 б«гз Ґ ў Є зҐб⢥ нв®Ј® ®аЈ гЇа ў«ҐЁп ўлбвгЇ Ґв Microsoft Web Browser Control.
Џ®¤а®Ў®Ґ ®ЇЁб ЁҐ Microsoft Web Browser Control, ўЄ«оз п ®ЇЁб ЁҐ гЇа ў«по饣® Є« бб , ᬮваЁвҐ бва ЁжҐ http://www.microsoft.com бҐаўҐа WWW Є®¬Ї ЁЁ Microsoft. ‚ б«Ґ¤го饩 в Ў«ЁжҐ ¬л ¤ ¤Ё¬ Єа вЄ®Ґ ®ЇЁб ЁҐ ®б®ўле ¬Ґв®¤®ў Є« бб CWebBrowser:
ЊҐв®¤ |
ЋЇЁб ЁҐ |
GetBusy |
Џ®§ў®«пҐв г§ вм, ўлЇ®«пҐв «Ё ®аЈ гЇа ў«ҐЁп Microsoft Web Browser Control ў ¤ л© ¬®¬Ґв ўаҐ¬ҐЁ § Јаг§Єг ¤ ле Ё§ Internet |
GetHeight |
ЋЇаҐ¤Ґ«пҐв ўҐавЁЄ «мл© а §¬Ґа ®Є (frame window), ᮤҐа¦ 饣® ®аЈ гЇа ў«ҐЁп Web Browser |
GetLeft |
ЋЇаҐ¤Ґ«пҐв а ббв®пЁҐ ¬Ґ¦¤г ўгв॥© «Ґў®© бв®а®®© ®аЈ гЇа ў«ҐЁп Web Browser Ё «Ґў®© бв®а®®© ҐЈ® Є®вҐ©Ґа (ᮤҐа¦ 饣® ҐЈ® ®Є ) |
GetLocationName |
ЋЇаҐ¤Ґ«пҐв Ё¬п аҐбгаб Internet, Є®в®ал© ®в®Ўа ¦ Ґвбп ®аЈ ®¬ гЇа ў«ҐЁп Microsoft Web Browser Control |
GetLocationURL |
ЋЇаҐ¤Ґ«пҐв URL Ё¬п аҐбгаб Internet, Є®в®ал© ®в®Ўа ¦ Ґвбп ®аЈ ®¬ гЇа ў«ҐЁп Microsoft Web Browser Control |
GetTop |
ЋЇаҐ¤Ґ«пҐв а ббв®пЁҐ ¬Ґ¦¤г ўгв॥© ўҐа奩 бв®а®®© ®аЈ гЇа ў«ҐЁп Web Browser Ё ўҐа奩 бв®а®®© ҐЈ® Є®вҐ©Ґа |
GetWidth |
ЋЇаҐ¤Ґ«пҐв Ј®аЁ§®в «мл© а §¬Ґа ®Є (frame window), ᮤҐа¦ 饣® ®аЈ гЇа ў«ҐЁп Web Browser |
GoBack |
‚Ґагвмбп Є Їа®б¬®ва㠯।л¤г饩 бва Ёжл WWW |
GoForward |
ЏҐаҐ©вЁ Є Їа®б¬®ваг б«Ґ¤го饩 бва Ёжл WWW. ќв®в ¬Ґв®¤ ¬®¦® ЁбЇ®«м§®ў вм, Ґб«Ё ўл ўҐаг«Ёбм Є Їа®б¬®ва㠯।л¤г饩 бва Ёжл WWW б Ї®¬®ймо ¬Ґв®¤ GoBack |
GoHome |
ЏҐаҐ©вЁ Є Їа®б¬®ваг ¤®¬ 襩 бва Ёжл WWW. Ђ¤аҐб ¤®¬ 襩 бва Ёжл Microsoft Internet Explorer ¬®¦® Ё§¬ҐЁвм зҐаҐ§ Ї Ґ«м гЇа ў«ҐЁп Control Panel, § ЇгбвЁў ЇаЁ«®¦ҐЁҐ Internet. ЏаЁ«®¦ҐЁҐ Internet ®в®Ўа ¦ Ґв нЄа Ґ ¤Ё «®Ј®ўго Ї Ґ«м Internet Properties. ‚ Ґ© ¤® ўлЎа вм бва Ёжг Navigation, § ⥬ ўлЎа вм Ё§ бЇЁбЄ Page бва®Єг Start Page ( з «м п Ё«Ё ¤®¬ ипп бва Ёж ) Ё ўўҐбвЁ ҐҐ ¤аҐб ў Ї®«Ґ Address |
GoSearch |
ЏҐаҐ©вЁ Є Їа®б¬®ваг Ї®ЁбЄ®ў®© бва Ёжл WWW. Ђ¤аҐб Ї®ЁбЄ®ў®© бва Ёжл Microsoft Internet Explorer ¬®¦® Ё§¬ҐЁвм зҐаҐ§ Ї Ґ«м гЇа ў«ҐЁп Control Panel, § ЇгбвЁў ЇаЁ«®¦ҐЁҐ Internet |
Navigate |
ЏҐаҐ©вЁ Є Їа®б¬®ваг бва Ёжл WWW б § ¤ л¬ ¤аҐб®¬. €¬Ґ® нв®в ¬Ґв®¤ ¬л Ўг¤Ґ¬ ЁбЇ®«м§®ў вм ў ЇаЁ«®¦ҐЁЁ Look зв®Ўл ЇҐаҐ©вЁ Є Їа®б¬®ваг ®ЇаҐ¤Ґ«Ґ®© бва Ёжл WWW |
Refresh, Refresh2 |
ЋЎ®ўЁвм Ёд®а¬ жЁо ⥪г饩 бва Ёжл WWW |
SetHeight |
“бв ў«Ёў Ґв ўҐавЁЄ «мл© а §¬Ґа ®Є (frame window), ᮤҐа¦ 饣® ®аЈ гЇа ў«ҐЁп Web Browser |
SetLeft |
“бв ў«Ёў Ґв а ббв®пЁҐ ¬Ґ¦¤г ўгв॥© «Ґў®© бв®а®®© ®аЈ гЇа ў«ҐЁп Web Browser Ё «Ґў®© бв®а®®© ҐЈ® Є®вҐ©Ґа |
SetTop |
“бв ў«Ёў Ґв а ббв®пЁҐ ¬Ґ¦¤г ўгв॥© ўҐа奩 бв®а®®© ®аЈ гЇа ў«ҐЁп Web Browser Ё ўҐа奩 бв®а®®© ҐЈ® Є®вҐ©Ґа |
SetWidth |
“бв ў«Ёў Ґв Ј®аЁ§®в «мл© а §¬Ґа ®Є (frame window), ᮤҐа¦ 饣® ®аЈ гЇа ў«ҐЁп Web Browser |
Stop |
Ћбв ®ўЁвм § Јаг§Єг бва Ёжл WWW |
Љ« бб CWebBrowser, ЇаҐ¤бв ў«пойЁ© ®аЈ гЇа ў«ҐЁп Microsoft Web Browser Control, в Є¦Ґ ᮤҐа¦Ёв жҐ«л© ап¤ ¬Ґв®¤®ў, Є®в®алҐ ўл§лў овбп ў а §«Ёзле бЁвг жЁпе. ‚ б«Ґ¤го饩 в Ў«ЁжҐ ¬л ЇаЁўҐ«Ё бЇЁб®Є нвЁе ¬Ґв®¤®ў Ё ¤ «Ё Ё¬ Єа вЄЁҐ ®ЇЁб Ёп.
ЊҐв®¤ |
ЋЇЁб ЁҐ |
BeforeNavigate |
‚л§лў Ґвбп Є®Ј¤ ўЁЈ в®а ЇҐаҐе®¤Ёв Є Їа®б¬®ваг ¤агЈ®Ј® URL |
CommandStateChange |
‚лЇ®«ҐЁҐ ®ЇаҐ¤Ґ«Ґле Є®¬ ¤ а §аҐиҐ® Ё«Ё § ЇаҐйҐ® |
DownloadBegin |
Ќ з « бм § Јаг§Є аҐбгаб |
DownloadComplete |
‡ Јаг§Є аҐбгаб § ўҐаи Ґвбп, ®бв ў«Ёў Ґвбп Ё«Ё ЇаҐалў Ґвбп |
FrameBeforeNavigate |
Ќ ўЁЈ в®а ЇаЁбвгЇ Ґв Є § Јаг§ЄҐ ®ў®Ј® аҐбгаб б ¤агЈЁ¬ ¤аҐб®¬ URL. Џа®Ёб室Ёв, Ґб«Ё ¤ ®© бва ЁжҐ WWW ЇаЁбгвбвўгов д३¬л |
FrameNavigateComplete |
‚л§лў Ґвбп Ї®б«Ґ в®Ј®, Є Є ўЁЈ в®а § Јаг§Ёв ®ўл© аҐбгаб. |
FrameNewWindow |
‘®§¤ ® ®ў®Ґ ®Є®. Џа®Ёб室Ёв, Ґб«Ё ¤ ®© бва ЁжҐ WWW ЇаЁбгвбвўгов д३¬л |
NavigateComplete |
Ќ ўЁЈ в®а гбЇҐи® § Јаг§Ё« ®ўл© аҐбгаб |
NewWindow |
Ќ®ў®Ґ ®Є® ¤®«¦® Ўлвм ᮧ¤ ® ¤«п ®в®Ўа ¦ҐЁп аҐбгабб |
ProgressChange |
€§¬ҐЁ«®бм б®бв®пЁҐ Їа®жҐбб § Јаг§ЄЁ |
Quit |
ЏаЁ«®¦ҐЁҐ Internet Explorer Ј®в®ў® § ўҐаиЁвмбп |
StatusTextChange |
€§¬ҐпҐвбп ⥪бв ў Ї Ґ«Ё б®бв®пЁп |
TitleChange |
‡ Ј®«®ў®Є ¤®Єг¬Ґв ў ®ЄҐ ўЁЈ в®а Ї®«гзҐ Ё«Ё Ё§¬ҐҐ |
WindowActivate |
ЋЄ® ўЁЈ в®а Ї®«гзЁ«® гЇа ў«ҐЁҐ |
WindowMove |
ЋЄ® ўЁЈ в®а ЇҐаҐ¬ҐбвЁ«®бм |
WindowResize |
€§¬ҐҐ а §¬Ґа ®Є ўЁЈ в®а |
Классы WinInet
Библиотека MFC значительно упрощают использование программного интерфейса WinInet. Начиная с версии 4.2 в MFC добавлен целый ряд новых классов созданных на основе программного интерфейса WinInet.
Рисунок 1.1 представляет вашему вниманию схему классов WinInet.
CObject -> CInternetSession
|
-> CInternetConnection -> CHttpConnection
| |
| -> CFtpConnection
| |
| -> CGopherConnection
|
-> CFile -> CStdioFile -> CInternetFile -> CHttpFile
| |
| -> CGopherFile
|
-> CFileFind -> CFtpFileFind
| |
| -> CGopherFileFind
|
-> CGopherLocator
|
-> CException -> CInternetException
Рис. 1.1. Схема классов WinInet
Более полное описание классам MFC, предназначенным для работы с WinInet, мы дадим несколько позже, а сейчас только представим их список с краткими пояснениями:
Класс | Описание | ||
CInternetSession | Класс подготавливает сеанс связи с Internet. Это самый общий класс, который необходимо использовать для работы с другими классами WinInet | ||
CInternetConnection | Управляет соединением с серверами в Internet вне зависимости от их типа (FTP, WWW, Gopher) | ||
CFtpConnection | Управляет соединением с серверами FTP по протоколу FTP. Позволяет выполнять манипуляции с файлами и каталогами сервера | ||
CHttpConnection | Управляет соединением с серверами WWW по протоколу HTTP | ||
CGopherConnection | Используется для соединения с серверами Gopher | ||
CInternetFile | Используется для получения файлов с серверов WWW и Gopher | ||
CHttpFile | Класс позволяет передать запрос серверу WWW и получить от него ответ (данные) | ||
CGopherFile | Предназначен для работы с серверами Gopher | ||
CFileFind | Используется для поиска файлов | ||
CFtpFileFind | Выполняет поиск файлов на сервере FTP | ||
CGopherFileFind | Выполняет поиск файлов на сервере Gopher | ||
CGopherLocator | Создает объект, связанный с файлом Gopher | ||
CInternetException | Представляет исключения, связанные с ошибками при работе WinInet |
Практически все классы библиотеки MFC, управляющие интерфейсом WinInet, а также несколько глобальных функций WinInet определены во включаемом файле afxinet.h. Исключение составляет только класс CFileFind, который определен в другом включаемом файле библиотеки MFC - afx.h. Данные включаемые файлы должны быть указаны в исходных текстах приложений, работающих с интерфейсом WinInet:
#include <afxinet.h> // Используется интерфейсом WinInet
#include <afx.h> // Содержит определение класса CFileFind
Кнопки “Вперед” и “Назад”
В нашем варианте навигатора отсутствуют кнопки, позволяющие вернуться к просмотру страниц WWW, которые вы уже посетили во время текущего сеанса связи. Это крайне неудобно, так как затрудняет обход дерева гипертекстовых ссылок серверов WWW.
Добавить возможность возврата к предыдущим страницам WWW очень просто. Орган управления Microsoft Web Browser Control сам запоминает путь ваших хождений по паутине Internet. В состав класса CWebBrowser входят методы GoBack и GoForward, которые позволяют просматривать уже посещенные вами страницы.
Методы GoBack и GoForward имеют простой прототип - у них отсутствуют параметры и они не возвращают никакого значения. Интересно, что в документации на Microsoft Web Browser Control, которую мы получили через сеть Internet, указывается, что эти методы возвращают значение типа HRESULT, определяющее результат выполнения метода:
void CWebBrowser::GoBack()
void CWebBrowser::GoForward()
С помощью редактора ресурсов добавьте к диалоговой панели IDD_LOOK_DIALOG приложения Look, две кнопки. Первую назовите Back (назад) и присвойте ей идентификатор IDC_BACK, а вторую - Forward (вперед) и воспользуйтесь идентификатором IDC_FORWARD.
После того как кнопки заняли свое место в диалоговой панели, запустите MFC ClassWizard и добавьте к классу CLookDlg два метода для обработки командных сообщений от кнопок Back и Forward. Согласитесь с предложением MFC ClassWizard и оставьте для них названия OnBack и OnForward.
Затем непосредственно из MFC ClassWizard перейдите к просмотру и редактированию методов OnBack и OnForward, выбрав одно из названий этих методов из списка и нажав кнопку Edit code. Добавьте к OnBack и OnForward вызовы, соответственно, методов GoBack и GoForward класса CWebBrowser.
Постройте проект и запустите приложение. Посетите несколько страниц WWW и попробуйте вернуться к уже просмотренным страницам, воспользовавшись кнопками Back и Forward. Вы обнаружите, что кнопки работают правильно, но когда вы выходите за границу уже просмотренного материала, на экране появляется ужасная диалоговая панель, показанная на рисунке 4.13.
Рис. 4.13. Предупреждающая диалоговая панель
Класс CWebBrowser имеет средства для управления кнопками просмотра Back и Forward. Для этого предназначен виртуальный метод CommandStateChange, который вызывается самим органом управления. Чтобы переназначить метод CommandStateChange надо воспользоваться средствами MFC ClassWizard (рис. 3.4):
void CBrowserDlg::OnCommandStateChangeExplorer(long Command, BOOL Enable)
{
}
В качестве значения параметра Command, методу CommandStateChange передается отдна из следующих констант - CSC_UPDATECOMMANDS, CSC_NAVIGATEFORWARD или CSC_NAVIGATEBACK. Эти константы определяются следующим образом:
typedef enum CommandStateChangeConstants {
CSC_UPDATECOMMANDS = 0xFFFFFFFF,
CSC_NAVIGATEFORWARD = 0x00000001,
CSC_NAVIGATEBACK = 0x00000002
} CommandStateChangeConstants;
Второй параметр Enable определяет, новое состояние кнопки - заблокирована или доступна. Когда требуется изменить состояние кнопки Back, вызывается метод OnCommandStateChangeExplorer. В качестве первого параметра ему передается значение CSC_NAVIGATEBACK. Когда надо изменить состояние кнопки Forward, в первом параметре передается значение CSC_NAVIGATEFORWARD.
Чтобы управлять состоянием кнопок IDC_BACK и IDC_FORWARD нужно сначала привязать к ним две переменные. Для этого следует воспользоваться средствами MFC ClassWizard.
Откройте в редакторе ресурсов диалоговую панель приложения и выберите в ней кнопку Forward или Back. Запустите MFC ClassWizard. Выберите в панели MFC ClassWizard страницу Member Variables. В списке идентификаторов органов управления диалоговой панели Control IDs укажите идентификатор IDC_BACK, принадлежащий кнопке Back и нажмите кнопку Add Variables. На экране появится диалоговая панель Add Member Variables (рис. 4.14). Введите в поле Member Variables name имя переменной, которая будет связана с кнопкой. Мы предлагаем использовать имя m_Back.
Рис. 4.14. Диалоговая панель Add Member Variables
Обратите внимание, что из списка категории органа управления Category должна быть выбрана строка Control, а из списка типа переменной Variables type - строка CButton. Таким образом мы привяжем к кнопке переменную m_Back класса CButton.
Выбирая из списка Category строку Control мы указываем, что нам надо привязать к органу управления объект соответствующего класса, через который мы затем сможем иметь над ним полный контроль.
¨ Как мы говорили в предыдущих томах серии БСП, посвященных библиотеке MFC, к одному органу управления с помощью MFC ClassWizard можно привязать несколько переменных. Однако это верно только если указывается категория Value. Если вы используете категорию Control, то к одному органу управления можно привязать только одну переменную. Попытка привязать еще одну переменную вызывает сообщение об ошибке (рис. 4.15)
Рис. 4.15. Предупреждение
Повторите описанную процедуру и привяжите к кнопке IDC_FORWARD переменную m_Forward класса CButton.
Когда вы привяжите к кнопкам переменные, MFC ClassWizard внесет изменения в исходные тексты приложения. Во-первых в класс CLookDlg, управляющий диалоговой панелью будет включены два новых элемента данных, представляющих кнопки:
class CLookDlg : public CDialog
{
public:
CLookDlg(CWnd* pParent = NULL);
// Dialog Data
//{{AFX_DATA(CLookDlg)
enum { IDD = IDD_LOOK_DIALOG };
CButton m_Forward; // Кнопка Forward
CButton m_Back; // Кнопка Back
CWebBrowser m_explorer;
CString m_address;
//}}AFX_DATA
...
Во-вторых, будут добавлены новые записи в таблице обмена данными, расположенной в методе DoDataExchange класса CLookDlg. Новые записи являются вызовами методов DDX_Control, которые выполняют обмен данными между органом управления и привязанной к нему переменной:
void CLookDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CLookDlg)
DDX_Control(pDX, IDC_FORWARD, m_Forward); // Кнопка Forward
DDX_Control(pDX, IDC_BACK, m_Back); // Кнопка Back
DDX_Control(pDX, IDC_EXPLORER, m_explorer);
DDX_CBString(pDX, IDC_COMBO_ADDRESS, m_address);
//}}AFX_DATA_MAP
}
Конструктор класса CFtpFileFind
Конструктор класса CFtpFileFind имеет только один обязательный параметр pConnection. В нем вы должны указать объект класса CFtpConnection, представляющий соединение с сервером FTP, в рамках которого вы будете осуществлять поиск файлов или каталогов:
CFtpFileFind(
CFtpConnection* pConnection,
DWORD dwContext = 1
);
В качестве второго параметра вы можете указать идентификатор контекста, который будет соответствовать данному объекту класса CFtpFileFind.
Конструктор класса CFtpViewDlg
Конструктор класса CFtpViewDlg вызывается при создании объекта соответствующего класса, которое выполняется методом InitInstance главного класса приложения CFtpViewApp:
CFtpViewDlg dlg;
Конструктор класса CFtpViewDlg вызывает конструктор своего базового класса CDialog. При этом ему передается идентификатор диалоговой панели IDD и идентификатор главного окна приложения pParent. Диалоговая панель нашего приложения имеет идентификатор IDD_FTPVIEW_DIALOG, но в определении класса CFtpViewDlg указано, что IDD соответствует IDD_FTPVIEW_DIALOG:
enum { IDD = IDD_FTPVIEW_DIALOG };
В теле конструктора расположен блок AFX_DATA_INIT. В нем ClassWizard поместил код инициализации элемента данных класса m_FtpAddress. Конструктор также инициализирует m_hIcon, записывая в него идентификатор пиктограммы IDR_MAINFRAME:
//============================================================
// Конструктор класса CFtpViewDlg
//============================================================
CFtpViewDlg::CFtpViewDlg(CWnd* pParent /*=NULL*/)
: CDialog(CFtpViewDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CFtpViewDlg)
m_FtpAddress = _T("");
//}}AFX_DATA_INIT
// При использовании метода LoadIcon нет необходимости
// вызывать DestroyIcon
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
Конструктор класса CInternetSession
Конструктор класса CInternetSession имеет следующий прототип:
CInternetSession(
LPCTSTR pstrAgent = NULL,
DWORD dwContext = 1,
DWORD dwAccessType = PRE_CONFIG_INTERNET_ACCESS,
LPCTSTR pstrProxyName = NULL,
LPCTSTR pstrProxyBypass = NULL,
DWORD dwFlags = 0
);
Посмотрите, как определен конструктор класса CInternetSession в исходных текстах библиотеки MFC. Вы найдете соответствующий программный код в файле Inet.cpp.
Конструктор класса CInternetSession вызывает единственную функцию программного интерфейса WinInet - InternetOpen, которая выполняет инициализацию WinInet.
Параметры конструктора класса CInternetSession передаются непосредственно функции InternetOpen:
m_dwContext = dwContext;
if (pstrAgent == NULL)
pstrAgent = AfxGetAppName();
m_hSession = InternetOpen(pstrAgent, dwAccessType,
pstrProxyName, pstrProxyBypass, dwFlags);
Вернемся теперь к обсуждению параметров конструктора. Все параметры конструктора класса CInternetSession являются необязательными и при создании объекта данного класса вы их можете не указывать.
Через параметр pstrAgent можно явным образом указать название приложения, или программного модуля, работающего с WinInet. Это название используется протоколом HTTP, и передается серверу в качестве имени пользовательского агента.
Если вызвать конструктор класса CInternetSession без параметров или указать в качестве параметра pstrAgent значение NULL, то конструктор самостоятельно определит имя приложения. Для этого конструктор использует глобальную функцию AfxGetAppName (см. фрагмент из файла Inet.cpp представленный выше).
Параметр dwContext определяет идентификатор контекста. Созданный объект будет ассоциироваться с данным идентификатором контекста.
Параметр dwAccessType определяет тип доступа к сети. Можно использовать одно из значений, перечисленных в следующей таблице:
Константа | Тип доступа | ||
INTERNET_OPEN_TYPE_PRECONFIG | Используется тип доступа, указанный в регистрационной базе Windows | ||
INTERNET_OPEN_TYPE_DIRECT | Прямой доступ к Internet | ||
INTERNET_OPEN_TYPE_PROXY | Доступ через proxy сервер |
|
Откройте Control Panel и выберите приложение Internet, которое предназначено для настройки различных параметров доступа к сети Internet |
Рис. 1.2. Диалоговая панель Internet Properties
Если включен переключатель Connect to the Internet as needed в группе Dialing, значит ваш компьютер подключается к сети через модем с использованием Dial-Up Networking. Если включен переключатель Connect through a proxy server, значит вы подключены к сети через специальный proxy сервер. Настройки этого сервера вы можете просмотреть, нажав кнопку Setting. В случае, если оба эти переключателя отключены, значит вы подключены к сети напрямую.
Константы PRE_CONFIG_INTERNET_ACCESS и INTERNET_OPEN_TYPE_PRECONFIG определены в файле wininet.h. Ниже мы привели соответствующий фрагмент этого файла:
//
// access types for InternetOpen()
//
#define INTERNET_OPEN_TYPE_PRECONFIG 0 // use registry configuration
#define INTERNET_OPEN_TYPE_DIRECT 1 // direct to net
#define INTERNET_OPEN_TYPE_PROXY 3 // via named proxy
#define PRE_CONFIG_INTERNET_ACCESS INTERNET_OPEN_TYPE_PRECONFIG
#define LOCAL_INTERNET_ACCESS INTERNET_OPEN_TYPE_DIRECT
#define GATEWAY_INTERNET_ACCESS 2 // Internet via gateway
#define CERN_PROXY_INTERNET_ACCESS INTERNET_OPEN_TYPE_PROXY
Как видите, значения констант PRE_CONFIG_INTERNET_ACCESS и INTERNET_OPEN_TYPE_PRECONFIG полностью совпадают.
Если тип доступа, определен параметром dwAccessType как INTERNET_OPEN_TYPE_PROXY, то через параметр pstrProxyName следует указать имя proxy сервера, а через параметр pstrProxyBypass - указатель на строку со списком адресов дополнительных серверов. Вы можете указать в качестве параметра pstrProxyBypass значение NULL. При этом список серверов будет взят из регистрационной базы данных Windows.
Если используются другие типы доступа, то в качестве параметра dwAccessType надо указать значение NULL. Параметр pstrProxyBypass в этом случае значения не имеет.
Последний параметр конструктора dwFlags определяет различные характеристики, перечисленные в следующей таблице:
Константа |
Описание |
INTERNET_FLAG_DONT_CACHE |
Данные, получаемые WinInet из сети кэшируются в специальном каталоге на жестком диске локального компьютера. В случае если пользователь часто запрашивает у WinInet одни и те же файлы, то для ускорения они могут браться не из сети, а из кэша. Константа INTERNET_FLAG_DONT_CACHE запрещает кэшировть принимаемые данные |
INTERNET_FLAG_ASYNC |
Устанавливает асинхронный режим работы WinInet. Последующие операции с объектом могут завершится с ошибкой ERROR_IO_PENDING. Когда операция закончится, функция обратного вызова, будет вызвана с кодом INTERNET_STATUS_REQUEST_COMPLETE |
INTERNET_FLAG_OFFLINE |
Операции по загрузке информации выполняются только из кэша. В том случае, если запрашиваемая информация в кэше отсутствует, возвращается ошибка |
Конструктор класса CLookDlg
Конструктор класса CLookDlg вызывается при создании объекта данного класса методом InitInstance главного класса приложения. Он вызывает конструктор базового класса CDialog. При этом ему указывается идентификатор диалоговой панели IDD, который определен в классе CLookDlg следующим образом:
enum { IDD = IDD_LOOK_DIALOG };
Конструктор базового класса загружает шаблон диалоговой панели IDD_LOOK_DIALOG и подготавливает все к отображению ее на экране.
Затем выполняется инициализация строк m_address, m_StatusText и m_TitleBar и загружается пиктограмма приложения:
// Инициализируем строки
//{{AFX_DATA_INIT
m_address = _T("");
m_StatusText = _T("");
m_TitleBar = _T("");
//}}AFX_DATA_INIT
// Загружаем пиктограмму приложения
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
Литература
1.
Фролов А. В., Фролов Г. В. Microsoft Visual C++ и MFC: В 2 ч. М.: Диалог-МИФИ, 1996. (Б-ка системного программиста; Т.24, 28.).
2. Фролов А. В., Фролов Г. В. Операционная система Microsoft Windows 3.1 для программиста: В 3 ч. М.: Диалог-МИФИ, 1994. (Б-ка системного программиста; Т.11-13.).
3. Фролов А. В., Фролов Г. В. Графический интерфейс GDI в Microsoft Windows. М.: Диалог-МИФИ, 1994. (Б-ка системного программиста; Т.14.).
4. Фролов А. В., Фролов Г. В. Операционная система Microsoft Windows 3.1 для программиста. Дополнительные главы. М.: Диалог-МИФИ, 1994. (Б-ка системного программиста; Т.17.).
5. Фролов А. В., Фролов Г. В. Операционная система Microsoft Windows 95 для программиста. М.: Диалог-МИФИ, 1994. (Б-ка системного программиста; Т.22.).
6. Фролов А. В., Фролов Г. В. Программирование для Windows NT: В 2 ч. М.: Диалог-МИФИ, 1996. (Б-ка системного программиста; Т.26-27.).
7. Viktor Toth. Visual C++™ 4 Unleashed. Sams Publishing, 1996.
Локальный вариант WebHelp
В приложении WebHelp файлы справочной системы приложения находятся непосредственно в Internet. Измените приложение так, чтобы файлы справочной системы можно было расположить на локальном диске компьютера. Для этого достаточно записать соответствующий htm файл на жесткий диск локального компьютера и соответствующим образом изменить третий параметр функции ShellExecute, так чтобы он указывал на локальный файл.
Запустите измененное приложение WebHelp и выберите из меню Help строку Web Help. Сразу запустится навигатор Internet Explorer и в нем появится описание приложения. При этом совершенно необязательно, чтобы компьютер был соединен с сетью Internet. Более того, компьютер вообще может не иметь ни модема, ни сетевой карты - справочная система все равно будет работать, так как HTML файлы со справочной информацией расположены на локальном диске компьютера.
Метод AddRequestHeaders
Метод AddRequestHeaders добавляет один или несколько заголовков к запросу HTTP, который затем будет передаваться на сервер. Данный метод только подготавливает запрос HTTP, для выполнения фактической передачи запроса серверу необходимо воспользоваться методом SendRequest класса CHttpFile.
В классе CHttpFile определены два метода AddRequestHeaders, которые имеют различный набор параметров:
BOOL AddRequestHeaders(
LPCTSTR pstrHeaders,
DWORD dwFlags = HTTP_ADDREQ_FLAG_ADD_IF_NEW,
int dwHeadersLen = -1
);
BOOL AddRequestHeaders(
CString& str,
DWORD dwFlags = HTTP_ADDREQ_FLAG_ADD_IF_NEW
);
Строка с заголовками, которые надо добавить к запросу, указывается методу AddRequestHeaders через параметр pstrHeaders, как указатель типа LPCTSTR или через строку str класса CString. В первом случае вы должны использовать строку, закрытую нулем, или специально указать длину строки при помощи параметра dwHeadersLen. Если вы добавляете к запросу сразу несколько заголовков, то они должны быть разделены парой символов - CR и LF.
Параметр dwFlags позволяет изменить способ добавления заголовков к запросу. Для этого вы должны указать в качестве этого параметра один из флагов, представленных в следующей таблице:
Флаг | Описание | ||
HTTP_ADDREQ_FLAG_COALESCE | Объединить заголовки, которое имеют одинаковые имена | ||
HTTP_ADDREQ_FLAG_REPLACE | Замещает заголовок с указанным именем. Если методу AddRequestHeaders передается только название заголовка, без значения, то соответствующий заголовок удаляется из запроса. Если вы используете этот режим добавления, то вы можете указать методу AddRequestHeaders только один заголовок.
Совместно с этим флагом может использоваться флаг HTTP_ADDREQ_FLAG_ADD | ||
HTTP_ADDREQ_FLAG_ADD_IF_NEW | Добавляет новый заголовок только в том случае, если заголовок с таким именем отсутствует. В противном случае метод AddRequestHeaders завершается с ошибкой | ||
HTTP_ADDREQ_FLAG_ADD | Добавляет заголовок только в том случае, если заголовок с таким именем отсутствует. Может использоваться совместно с флагом HTTP_ADDREQ_FLAG_REPLACE |
В случае успешного завершения метод AddRequestHeaders возвращает ненулевое значение. Если метод завершился с ошибкой, то он возвращает ноль, а причину ошибки можно узнать с помощью функции GetLastError.
Метод Close
Одно приложение может создать несколько объектов класса CInternetSession. Объект CInternetSession должен существовать на протяжении всего сеанса связи с Internet. Когда вам понадобится завершить работу с Internet, вызовите для объекта CInternetSession виртуальный метод Close, определенный в классе CInternetSession:
virtual void Close();
Следует отметить, что деструктор класса CInternetSession сам вызывает метод Close.
По окончании работы с файлом на сервере, его следует закрыть. Для этого вы можете воспользоваться методом Close:
virtual void Close();
throw( CInternetException );
В случае ошибки, метод Close может вызвать исключение CInternetException. Поэтому вы должны учесть такую возможность и поместить вызов этого метода внутри блока try.
Виртуальный метод Close закрывает объект CHttpFile и освобождает все используемые им ресурсы. Вы можете использовать данный метод после передачи запроса серверу с методом SendRequest и или после того как вы открыли объект на сервере Internet с помощью метода OpenURL.
Прототип метода Close представлен ниже:
virtual void Close( );
Метод Close не имеет параметров и не возвращает значения.
Когда вы завершите поиск файлов, следует вызвать метод Close. Он завершает поиск и освобождает все задействованные ресурсы. После того как вы вызвали метод Close, вы можете повторить поиск, используя тот же самый объект CFileFind:
void Close( );
Метод DirectoryView
Метод DirectoryView класса CFtpViewDlg выполняет львиную долю работы всего нашего приложения. Именно этот метод после соединения с сервером FTP определяет названия и основные характеристики объектов в заданном каталоге сервера, а затем отображает их в списке IDC_FTP_LIST на главной диалоговой панели приложения:
BOOL CFtpViewDlg::DirectoryView()
{
// Переменная, сигнализирующая о получении последнего
// элемента каталога
BOOL fResult;
// Временная переменная, определяющая тип объекта -
// файл или каталог
BOOL fDirectory;
Метод DirectoryView заполняет список IDC_FTP_LIST именами каталогов и файлов сервера FTP. Чтобы удалить из списка элементы, занесенные в него ранее, вызываем метод DeleteAllItems для объекта m_FtpList, управляющего этим списком (см. метод DoDataExchange):
// Удалить все элементы из списка IDC_FTP_LIST
m_FtpList.DeleteAllItems();
Для поиска файлов и каталогов на сервере FTP предназначен класс CFtpFileFind, входящий в состав библиотеки классов MFC. Метод DirectoryView создает объект этого класса. В качестве параметра конструктору класса CFtpFileFind передается указатель m_FtpConnection на объект, представляющий соединение с сервером FTP:
CFtpFileFind m_FtpFileFind(m_FtpConnection);
Далее мы вызываем для только что созданного объекта m_FtpFileFind метод FindFile. Он выполняет поиск каталогов и файлов в каталоге, путь которого указан в качестве параметра:
// Получаем имена всех объектов текущего каталога
if(fResult =
m_FtpFileFind.FindFile(_T(sCurentDirectory + "/*")))
{
. . .
}
Если каталог не содержит других объектов - каталогов и файлов, или в случае возникновения ошибки, метод FindFile возвращает ненулевое значение. Тогда на экран выводится сообщение File's not found or error и работа метода DirectoryView завершается.
В случае, если метод FindFile завершается успешно, это означает, что указанный каталог содержит другие каталоги или файлы. Тогда мы начинаем в цикле вызывать метод FindNextFile. Он получает имя очередного файла или каталога и мы отображаем его вместе с некоторой дополнительной информацией в списке объектов каталога. Когда метод FindNextFile вернет значение FALSE, это значит, что мы считали последний объект каталога. В этом случае мы добавляем этот последний объект к списку, завершаем цикл и выходим из метода DirectoryView:
for(int n = 0;fResult; n++)
{
// Получаем очередной объект из каталога
fResult = m_FtpFileFind.FindNextFile();
. . .
}
После обращения к методу FindNextFile можно вызывать другие методы класса CFtpFileFind. Они позволяют определить различные характеристики обнаруженных объектов. Например, вы можете узнать являются ли они каталогами или файлами, получить их имя, размер, дату создания и т. д.
Так, сначала мы определяем, является ли очередной объект, полученный методом FindNextFile файлом или каталогом и записываем полученный результат в fDirectory. Если мы получили каталог, то метод IsDirectory возвращает значение 1, а если файл, то - 0. Мы будем использовать значение fDirectory, сравнивая его с константой DIRECTORY, определенной как 0 и FILE, определенной как 1 в файле FtpViewDlg.h.
Далее с помощью метода GetFileName определяется имя объекта (файла или каталога) и записывается во временную строку fileName класса CString:
CString fileName;
// Определяем имя объекта
fileName = m_FtpFileFind.GetFileName();
Теперь, когда мы узнали тип объекта и его имя можно добавить элемент к первой колонке в списке. Для этого необходимо заполнить поля структуры lv_item и передать ее методу InsertItem объекта, управляющего списком:
// Структура для добавления нового элемента к списку
LV_ITEM lv_item;
. . .
// Заполняем структуру lv_item, сведениями об
// очередном объекте каталога сервера FTP. Указываем,
// что в список добавляется текст и изображение
lv_item.mask = LVIF_TEXT | LVIF_IMAGE;
// Указываем номер строки в списке
lv_item.iItem = n;
// Заполняем первую колонку
lv_item.iSubItem = 0;
// Выбираем изображение для нового элемента списка в
// зависимости от типа объекта
lv_item.iImage = (fDirectory) ? DIRECTORY : FILE;
// Указываем имя каталога или файла
lv_item.pszText = fileName.GetBuffer(MIN_LEN_BUF);
// Добавляем новый элемент к списку IDC_FTP_LIST
m_FtpList.InsertItem(&lv_item);
После заполнения первой колонки списка необходимо заполнить вторую, записав в нее длину файла или, если данный элемент списка описывает каталог, то строку Dir. Точно также как в случае с именем объекта, сначала заполняется структура lv_item, а затем она передается методу InsertItem.
Обратите внимание, что в отличие от первой колонки, во второй колонки не используется пиктограмма, поэтому в поле mask структуры lv_item заносится только константа LVIF_TEXT. Другое отличие состоит в том, что полю iSubItem структуры lv_item присваивается значение 1, указывающее, что мы будем добавлять элемент во вторую колонку (нумерация iSubItem начинается с нуля):
//============= Определяем длину файла =============
// Длинна файла
DWORD dwLength = 0;
// Временные строка для формирования текстового
// представления длинны файла
CString sLength;
// Заполняем колонку Length для новой записи и
// записываем в нее длину файла или строку Dir, если
// новый объект - каталог.
// Добавляется только текст без пиктограммы
lv_item.mask = LVIF_TEXT;
// Указываем номер строки в списке
lv_item.iItem = n;
// Заполняем вторую колонку
lv_item.iSubItem = 1;
// Если очередной объект является каталогом, то
// вместо в колонке Length записываем строку Dir
if(fDirectory)
{
lv_item.pszText = "Dir";
}
// Если очередной объект является файлом, то
// записываем его длину в колонку Length
else
{
// Определяем длину файла
dwLength = m_FtpFileFind.GetLength();
// Формируем текстовое представление длины файла
sLength.Format("%d", dwLength);
lv_item.pszText = sLength.GetBuffer(MIN_LEN_BUF);
}
// Добавляем запись во второй колонке списка (колонка
// Length)
m_FtpList.SetItem(&lv_item);
Теперь остается заполнить только третью и четвертую колонки списка, в которых надо записать дату и время создания или изменения файла (каталога). Для определения этих данных вызывается метод GetLastWriteTime класса CFtpFileFind, который записывает полученную информацию в объект mTime класса CTime:
// Дата и время создания каталога или файла
CTime mTime;
// Временные строки для формирования текстового
// представления даты и времени
CString sDate;
CString sTime;
// Определяем время изменения файла или каталога
if(!m_FtpFileFind.GetLastWriteTime(mTime))
break;
Затем мы подготавливаем структуру lv_item, заполняя ее поля соответствующими значениями:
// Добавляется только текст без пиктограммы
lv_item.mask = LVIF_TEXT;
// Указываем номер строки в списке
lv_item.iItem = n;
// Заполняем третью колонку
lv_item.iSubItem = 2;
// Выделяем из объекта mTime день, месяц и год
sDate = mTime.Format("%d.%m.%y");
// Записываем сформированную дату в структуру lv_item
lv_item.pszText = sDate.GetBuffer(MIN_LEN_BUF);
Чтобы добавить запись в колонке Date обращаемся к методу SetItem и передаем ему указатель на структуру lv_item:
// Добавляем запись во второй колонке списка (колонка Date)
m_FtpList.SetItem(&lv_item);
Затем мы немного модифицируем только что заполненную структуру lv_item, изменяя в ней только поля iSubItem и pszText:
// Заполняем четвертую колонку, записываем в нее
// время последнего изменения файла (каталога)
lv_item.iSubItem = 3;
// Выделяем из объекта mTime часы, минуты и секунды
sTime = mTime.Format("%H:%M:%S");
// Записываем сформированную строку, содержащую время
lv_item.pszText = sTime.GetBuffer(MIN_LEN_BUF);
Опять вызываем метод SetItem, передавая ему модифицированную структуру lv_item. Этот вызов добавит информацию о времени последнего изменения файла в колонке Time:
// Добавляем запись во второй колонке списка (колонка Time)
m_FtpList.SetItem(&lv_item);
Когда при очередном вызове метод FindNextFile возвращает нулевое значение, значит найден последний объект из каталога. В список добавляется последняя строка и на этом работа цикла заполнения списка завершается. Заканчиваем поиск объектов в данном каталоге вызывая метод Close и возвращаем управление с помощью оператора return:
// Заканчиваем поиск объектов в каталоге, закрываем
// объект m_FtpFileFind
m_FtpFileFind.Close();
Метод DoDataExchange
С помощью MFC ClassWizard мы привязали к органам управления диалоговой панели несколько переменных. Всю работу по связыванию этих переменных и органов управления выполняет метод DoDataExchange. В блоке AFX_DATA_MAP размещены вызовы соответствующих методов DDX:
//============================================================
// Метод DoDataExchange класса CFtpViewDlg
//============================================================
void CFtpViewDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CFtpViewDlg)
DDX_Control(pDX, IDC_STATUS, m_Status);
DDX_Control(pDX, IDOK, m_Ok);
DDX_Control(pDX, IDC_ON_TOP, m_OnTop);
DDX_Control(pDX, IDC_CONNECT, m_Connect);
DDX_Control(pDX, IDC_FTP_LIST, m_FtpList);
DDX_Text(pDX, IDC_FTP_ADDRESS, m_FtpAddress);
//}}AFX_DATA_MAP
}
Обратите внимание, что для большей части органов управления диалоговой панели используются обращения к методу DDX_Control. Он осуществляет привязку к органу диалоговой панели управляющего объекта соответствующего класса. Вызывая методы этого объекта можно выполнять над органом управления различные действия.
Только последний метод в блоке AFX_DATA_MAP отличается от остальных. Это метод DDX_Text, который используется для обмена данными между полем редактирования IDC_FTP_ADDRESS и строкой m_FtpAddress. Обмен выполняется при обращении к методу UpdateData.
Метод DoDataExchange класса CFtpViewDlg создается и модифицируется средствами MFC AppWizard и MFC ClassWizard. В большинстве случаев от вас не потребуется изменять этот метод вручную.
При разработке приложения мы привязали к некоторым органам управления диалоговой панели приложения соответствующие элементы данных и ввели их в состав класса CLookDlg. Чтобы обеспечить связь между этими органами управления и элементами данных класса, MFC ClassWizard добавил в блоке AFX_DATA_MAP метода DoDataExchange ряд методов DDX_:
DDX_Control(pDX, IDC_PROGRESS, m_Progress);
DDX_Control(pDX, IDC_EXPLORER, m_explorer);
DDX_Text(pDX, IDC_STATUS_TEXT, m_StatusText);
DDX_Text(pDX, IDC_TITLE_BAR, m_TitleBar);
DDX_CBString(pDX, IDC_COMBO_ADDRESS, m_address);
Линейный индикатор IDC_PROGRESS и навигатор IDC_EXPLORER связываются с элементами данных m_Progress и m_explorer при помощи методов DDX_Control. Таким образом, мы можем полностью управлять линейным индикатором и навигатором вызывая методы соответствующих классов.
Поля редактирования IDC_STATUS_TEXT и IDC_TITLE_BAR связываются со строками m_StatusText и m_TitleBar методами DDX_Text. Чтобы выполнить обмен данными между этими строками и полями редактирования мы будем обращаться к методу UpdateData.
И, наконец, последний метод в блоке DDX_CBString связывает список IDC_COMBO_ADDRESS со строкой m_address. Для того, чтобы узнать текущее состояние списка мы также будем обращаться к методу UpdateData.
Метод EnableStatusCallback
Чтобы разрешить программному интерфейсу WinInet вызывать метод OnStatusCallback, необходимо воспользоваться методом EnableStatusCallback, прототип которого мы представили ниже:
BOOL
EnableStatusCallback( BOOL bEnable = TRUE );
throw ( CInternetException );
Метод EnableStatusCallback имеет только один параметр, который разрешает или запрещает использование метода OnStatusCallback. По умолчанию параметр bEnable содержит значение TRUE, которое разрешает его использование.
Метод EnableStatusCallback возвращает ненулевое значение в случае успешного завершения или ноль в случае ошибки. Данный метод может вызывать исключение CInternetException. Вы можете определить причину исключения, воспользовавшись методами класса CInternetException.
Метод FindFile
Чтобы приступить к поиску файла или каталога с заданным имененм надо воспользоваться методом FindFile. Он также позволяет приступить к поиску файлов и каталогов по шаблону имени. Прототип метода FindFile представлен ниже:
virtual BOOL FindFile(
LPCTSTR pstrName = NULL,
DWORD dwFlags = INTERNET_FLAG_RELOAD
);
Имя файла или каталога, который вы желаете найти или соответствующий этому имени шаблон, вы должны записать в строку и передать указатель на нее методу FindFile через параметр pstrName. Чтобы выполнить поиск всех объектов - и файлов и каталогов, расположенных в текущем каталоге сервера FTP, вы можете указать в качестве шаблона для поиска символ звездочки * или просто использовать в качестве параметра pstrName значение NULL. Такой же эффект получается если вы просто опустите параметры метода и для них будут использованы значения, принятые по умолчанию.
Параметр dwFlags позволяет управлять процессом поиска. Вы, например, можете указать методу FindFile, что поиск следует осуществлять не используя данные которые записаны в кэш. Вот список флагов, которые можно использовать:
¨ INTERNET_FLAG_RELOAD
¨ INTERNET_FLAG_DONT_CACHE
¨ INTERNET_OPEN_FLAG_RAW_DATA
¨ INTERNET_FLAG_SECURE
¨ INTERNET_OPEN_FLAG_USE_EXISTING
Их описание мы приводили, когда рассказывали о методе OpenRequest класса CHttpConnection.
В случае успешного завершения метод AddRequestHeaders возвращает ненулевое значение. Если метод завершился с ошибкой, то он возвращает ноль, а причину ошибки можно узнать с помощью функции GetLastError.
Метод FindNextFile
После успешно завершившегося вызова метода FindFile вы должны вызвать виртуальный метод FindNextFile один или несколько раз для поиска всех файлов, соответствующих вашим требованиям. Только после того как вы хотя бы один раз вызвали метод FindNextFile вы можете воспользоваться другими методами класса CFindFile, чтобы определить характеристики обнаруженных файлов:
virtual BOOL FindNextFile( );
Метод FindNextFile возвращает ненулевое значение, если вы можете продолжить поиск и снова вызвать метод FindNextFile. Если метод FindNextFile вернул нулевое значение, значит был обнаружен последний файл соответствующий указанному вами шаблону поиска. В этом случае вы можете определить его характеристики, воспользовавшись методами класса FindFile и должны закончить поиск.
Метод FtpFileDownload
Метод FtpFileDownload имеет единственный параметр, через который передается имя файла, выбранного пользователем из списка объектов сервера FTP:
BOOL CFtpViewDlg::FtpFileDownload( CString sFileName )
{
. . .
}
Для начала метод FtpFileDownload запрашивает у пользователя имя файла, под которым файл с сервера FTP будет записан на диске локального компьютера.
Для облегчения этой задачи мы воспользовались классом CFileDialog, который входит в состав библиотеки классов MFC и предназначен для управления стандартной диалоговой панелью Save As. Объявляем объект mFileOpen этого класса:
CFileDialog mFileOpen(FALSE, NULL, sFileName);
¨ Класс CFileDialog, а также некоторые другие классы стандартных диалоговых панелей были описаны нами в 28 томе серии “Библиотека системного программиста”.
Конструктору класса CFileDialog мы указали три параметра. Первый параметр имеет значение FALSE и определяет, что объект mFileOpen будет управлять диалоговой панелью Save As. Если бы мы указали вместо FALSE значение TRUE, то была бы создана диалоговая панель Open.
Второй параметр конструктора может задавать расширение для имен файлов, которое будет выбрано по умолчанию, но мы не используем эту возможность, так как наше приложение способно загружать с сервера FTP файлы различных типов с разными расширениями.
Третий параметр конструктора sFileName содержит имя файла, которое мы выбрали из списка. Это имя будет предложено в диалоговой панели Save As по умолчанию.
Конструктор класса CFileDialog не открывает диалоговой панели Save As. Он только создает управляющий объект mFileOpen. Чтобы диалоговая панель Save As появилась на экране вызывается метод DoModal класса CFileDialog:
result = mFileOpen.DoModal();
Метод DoModal создает модальную диалоговую панель. Поэтому он возвращает управление только тогда, когда пользователь выберет файл или откажется от выбора и нажмет кнопку Cancel.
Если пользователь откажется от выбора и нажмет кнопку Cancel, то метод DoModal вернет значение IDCANCEL. Тогда мы выводим на экран соответствующее сообщение и завершаем метод FtpFileDownload, возвращая значение FALSE:
// Проверяем как была закрыта диалоговая панель Open -
// по нажатию кнопки OK или Cancel
if(result == IDCANCEL)
{
// Если пользователь отказался от выбора файлов и
// нажал кнопку Cancel отображаем соответствующее
// сообщение и возвращаем значение FALSE
AfxMessageBox("File not selected");
return FALSE;
}
Если пользователь выбрал файл из диалоговой панели Save As, то метод DoModal возвращает значение IDOK. В этом случае мы определяем полный путь файла, включая имя диска, путь каталога и имя файла и записываем его во временную строку sLocalFileName. Эта строка определена в данном метода как объект класса CString:
else if(result == IDOK)
{
sLocalFileName = mFileOpen.GetPathName();
}
Через параметр sFileName методу FtpFileDownload было передано имя файла, выбранного пользователем из списка файлов и каталогов сервера FTP. Мы не стали передавать полный путь файла целиком, так как имя файла можно использовать для инициализации диалоговой панели Save As. Текущий путь каталога сервера FTP записан в строке sCurentDirectory, поэтому чтобы сформировать полный путь файла, выбранного на сервере, достаточно выполнить следующую операцию:
sFileName = sCurentDirectory + "/" + sFileName;
Теперь в строке sFileName записан полный путь файла, расположенного на сервере FTP, а в строке sLocalFileName - полный путь файла на диске локального компьютера.
Остается загрузить файл с сервера FTP. Для этого мы вызываем метод GetFile, входящий в класс CFtpConnection. Метод GetFile имеет много различных параметров, но в нашем приложении мы используем только три. Первый параметр задает полный путь файла, который надо получить с сервера FTP, второй - полный путь файла на локальном компьютере в который полученный файл будет записан, а третий - определяет поведение метода в том случае если второй параметр задает файл, уже существующий на диске. В данном случае в качестве третьего параметра используется значение FALSE. Оно означает, что если на диске локального компьютера уже есть файл с таким именем, он перезаписывается (предварительно у пользователя запрашивается подтверждение на перезапись файла). Вы можете использовать в качестве третьего параметра значение TRUE или вовсе его не указывать. Тогда метод GetFile не будет перезаписывать уже существующий файл, а просто завершится с ошибкой:
fResult = m_FtpConnection ->
GetFile( sFileName.GetBuffer(MIN_LEN_BUF),
sLocalFileName.GetBuffer(MIN_LEN_BUF),
FALSE
);
В случае успешного завершения метод GetFile возвращает ненулевое значение, а если произошла какая-нибудь ошибка - нуль. Мы используем значение, возвращаемое методом GetFile в качестве результата работы самого метода FtpFileDownload:
return fResult;
Метод FtpFileDownload класса CFtpViewDlg
Метод FtpFileDownload класса CFtpViewDlg имеет единственный параметр sFileName, через который ему передается строка, содержащая имя файла на сервере FTP. Этот файл надо загрузить на локальный компьютер:
BOOL CFtpViewDlg::FtpFileDownload( CString sFileName )
{
}
Первая часть метода FtpFileDownload практически полностью соответствует более ранним версиям этого метода. В ней создается и отображается на экране стандартная диалоговая панель Save As. Эта панель позволяет пользователю указать имя файла и каталог на локальном компьютере в который записывается файл, загружаемый с сервера FTP. По умолчанию в качестве имени файла предлагается использовать имя загружаемого файла. Это имя передается конструктору класса CFileDialog через параметр sFileName:
// Создаем объект, управляющий панелью Save As
CFileDialog mFileOpen(FALSE, NULL, sFileName);
// Отображаем панель Save As на экране
int result = mFileOpen.DoModal();
После того как пользователь выберет файл и нажмет кнопку OK, или откажется от выбора и нажмет кнопку Cancel, диалоговая панель Save As закрывается и метод DoModal возвращает соответствующий код завершения.
Если пользователь отказался от выбора файла и нажал кнопку Cancel, то метод DoModal возвращает значение IDCANCEL. В этом случае мы только выводим соответствующее предупреждающее сообщение и завершаем работу метода FtpFileDownload не выполняя загрузки файла:
if(result == IDCANCEL)
{
AfxMessageBox("File not selected");
return FALSE;
}
Если пользователь выбрал файл и нажал кнопку OK (или выбрал файл, выполнив по его имени двойной щелчок левой кнопкой мыши), то метод DoModal возвращает значение IDOK. В этом случае мы определяем полный путь выбранного пользователем файла и записываем его в строку sLocalFileName:
CString sLocalFileName;
. . .
else if(result == IDOK)
{
sLocalFileName = mFileOpen.GetPathName();
}
Через единственный параметр метода FtpFileDownload ему передается строка sFileName, содержащая имя файла выбранного пользователем для загрузки с сервера. Чтобы получить полный путь этого файла на сервере мы добавляем имя файла к текущему каталогу. Результат записываем обратно в строку sFileName:
// Формируем полное имя файла для загрузки его с сервера FTP
sFileName = sCurentDirectory + "/" + sFileName;
Чтобы мы смогли определить во время загрузки файла какая его часть загружена, необходимо узнать размер файла. Для этой цели мы создаем объект класса CFtpFileFind и выполняем поиск данного файла на сервере.
Сначала мы вызываем метод FindFile, передавая ему в качестве параметра полный путь файла, который надо найти на сервере, а затем, в случае успеха, вызываем метод FindNextFile который позволит нам определить характеристики, и в том числе длину, обнаруженного файла.
Надо заметить, что файл sFileName обязательно будет обнаружен, так как мы уже нашли его раньше (см. метод DirectoryView). Конечно мы не учитываем в этом случае возможность разрыва связи, удаление файла администратором и сервера ит. д.:
// Создаем объект класса CFtpFileFind
CFtpFileFind m_FtpFileFind(m_FtpConnection);
// Выполняем поиск выбранного нами файла
if(fResult =
m_FtpFileFind.FindFile(_T(sFileName)))
{
// Если поиск закончился успешно, получаем его
// характеристики
fResult = m_FtpFileFind.FindNextFile();
. . .
}
Повторный поиск файла мы выполняем исключительно потому, что так наиболее просто узнать его размер. Для этого достаточно вызвать метод GetLength:
// Временная переменная для хранения размера файла
DWORD dwLength = 0;
// Определяем длину файла
dwLength = m_FtpFileFind.GetLength();
В соответствии с длинной загружаемого файла устанавливаются новые границы изменения значений для линейного индикатора и новый шаг приращения.
Мы будем загружать файл с сервера FTP блоками по READ_BLOCK байт в каждом (последний блок может иметь меньшую длину). Поэтому мы сможем изменить состояние линейного индикатора dwLength / READ_BLOCK раз:
// Устанавливаем новые границы для линейного индикатора
m_LoadProgress.SetRange(0, (int)(dwLength/READ_BLOCK) );
// Устанавливаем шаг приращения равный единице
m_LoadProgress.SetStep(1);
Заметим, что чем меньше загружаемый файл, тем более резко будет меняться значение линейного индикатора, отражающего процесс загрузки. Если размер загружаемого файла будет меньше, чем размер буфера (READ_BLOCK), то линейный индикатор вообще не будет задействован. В принципе, вы можете сделать линейный индикатор более чувствительным, если будете загружать файл меньшими порциями - уменьшите значение READ_BLOCK.
Перед тем как приступить к самому интересному - загрузке файла с сервера FTP, заканчиваем поиск и вызываем метод Close для объекта m_FtpFileFind:
// Так как мы искали только один файл, заканчиваем поиск
m_FtpFileFind.Close();
Перед тем как приступить к загрузке файла с сервера мы должны его открыть. Для этого следует воспользоваться методом OpenFile, входящим в состав класса CFtpConnection. Он возвращает указатель на объект класса CInternetFile:
// Определяем указатель на файл Internet
CInternetFile* iFile;
// Открываем выбранный нами файл на сервере FTP
iFile = m_FtpConnection -> OpenFile(
sFileName.GetBuffer(MIN_LEN_BUF),
GENERIC_READ,
FTP_TRANSFER_TYPE_BINARY
);
Первый параметр метода OpenFile задает имя файла, который надо открыть. Второй параметр выбирает режим в котором открывается файл. Константа GENERIC_READ означает, что файл открывается для чтения. Третий и последний параметр метода OpenFile устанавливает режим передачи двоичных данных. Мы выбрали этот режим чтобы иметь возможность загружать не только текстовые, но и двоичные файлы.
Файл, получаемый с сервера FTP, мы должны сохранить на локальном компьютере в файле под именем sLocalFileName. Создаем файл sLocalFileName, используя возможности класса CFile:
// Создаем и открываем файл на локальном диске компьютера
CFile fLocalFile(
sLocalFileName,
CFile::modeCreate | CFile::modeWrite
);
Файл создается с атрибутами CFile::modeCreate и CFile::modeWrite, поэтому если файла с именем sLocalFileName нет - он будет создан, а если такой файл уже есть, то он перезаписывается. У пользователя при этом запрашивается подтверждение на перезапись файла.
Для чтения информации из файла на сервере мы будем обращаться к методу Read класса CInternetFile. Этот метод считывает порцию данных из файла и записывает их во временный буфер. Буфер мы предварительно создаем, при помощи функции malloc:
// Создаем буфер для чтения файла с сервера FTP
void* ptrBuffer;
ptrBuffer = malloc( READ_BLOCK );
Затем в цикле мы приступаем к чтению данных из файла на сервере и записи их в файл на локальном компьютере. Цикл будет продолжаться до тех пор, пока не будет достигнут конец файла.
Операция чтения файла с сервера выполняется методом Read, определенным в классе CInternetFile. Каждый вызов метода Read считывает READ_BLOCK байт и записывает их в буфер ptrBuffer. Количество байт, которое действительно было считано из файла на сервере, возвращается методом Read и записывается во временную переменную nReadCount.
Как только после вызова метода Read значение nReadCount станет меньше READ_BLOCK значит достигнут конец файла и можно выходить из цикла чтения:
UINT nReadCount = 0;
do
{
. . .
// Читаем из файла на сервере READ_BLOCK байт
nReadCount = iFile -> Read( ptrBuffer, READ_BLOCK );
. . .
} while (nReadCount == READ_BLOCK);
Если во время чтения файла с сервера возникнет ошибка, например разорвется связь, то метод Read вызовет соответствующее исключение CInternetException. Мы организуем обработку такой ситуации и помещаем вызов метода Read в блок try, а ниже определяем блок catch:
try
{
// Читаем из файла на сервере READ_BLOCK байт
nReadCount = iFile -> Read( ptrBuffer, READ_BLOCK );
}
Блок catch выполняет обработку исключения CInternetException. Обращаясь к методу GetErrorMessage мы получаем текстовое описание причины, вызвавшей исключение и отображаем ее на экране. Если метод GetErrorMessage не может определить причину исключения, он возвращает нулевое значение и мы отображаем на экране строку GetFtpConnection Error:
catch (CInternetException* pEx)
{
// Обрабатываем исключение CInternetException
TCHAR szErr[1024]; // временный буфер для сообщения
// Выводим сообщение об ошибке
if (pEx->GetErrorMessage(szErr, 1024))
AfxMessageBox(szErr);
else
AfxMessageBox("GetFtpConnection Error");
// Так как возникла ошибка, значит данные не считаны
nReadCount = 0;
// Удаляем исключение
pEx->Delete();
}
Чтобы прервать дальнейшее выполнение цикла загрузки файла мы записываем в переменную nReadCount нулевое значение. Затем удаляем исключение, вызывая для него метод Delete.
Данные, которые считаны из файла на сервере и находятся в буфере ptrBuffer, надо записать в файл fLocalFile на локальном диске компьютера. Для этого передаем буфер ptrBuffer методу Write и указываем, что надо записать в файл nReadCount байт. Напомним, что при достижении конца файла на сервере метод Read считывает остаток файла, размер которого может быть меньше размера буфера:
fLocalFile.Write( ptrBuffer, nReadCount );
Когда очередной блок из файла считан, увеличиваем значение линейного индикатора на одну позицию. За время загрузки файла линейный индикатор изменит свое значение от крайне левого до крайне правого:
// Увеличиваем значение на линейном индикаторе
m_LoadProgress.StepIt();
После того, как файл полностью получен, переводим линейный индикатор загрузки в начальное положение. Вызываем для этого метод SetPos с нулевым значением в качестве параметра:
// После окончания загрузки файла сбрасываем
// линейный индикатор
m_LoadProgress.SetPos( 0 );
Так как открытый файл на сервере FTP более нам не нужен, закрываем его, а затем удаляем из памяти соответствующий управляющий объект:
// Закрываем файл на сервере
iFile -> Close();
// Удаляем объект iFile
delete iFile;
Также закрываем и локальный файл, в который скопирован файл с сервера FTP:
// Закрываем файл на локальном компьютере
fLocalFile.Close();
Освобождаем буфер ptrBuffer, вызывая функцию free:
// Освобождаем буфер ptrBuffer
free( ptrBuffer );
Метод GetCurrentDirectory
Метод GetCurrentDirectory позволяет определить имя текущего каталога на сервере FTP. В состав класса CFtpConnection входят два метода GetCurrentDirectory, имеющие различный набор параметров.
Прототип метода GetCurrentDirectory с одним параметром представлен ниже. Как видите, этому методу передается ссылка на строку strDirName. В нее метод GetCurrentDirectory записывает имя текущего каталога сервера:
BOOL GetCurrentDirectory( CString& strDirName ) const;
В случае успешного завершения метод GetCurrentDirectory возвращает ненулевое значение и ноль в случае ошибки. Чтобы определить причину возникшей ошибки можно воспользоваться функцией GetLastError.
Другой метод GetCurrentDirectory имеет два параметра. Параметр pstrDirName должен содержать указатель на буфер, в который будет записано имя текущего каталога. Размер этого буфера вы должны записать в переменную типа DWORD и передать указатель на него через параметр lpdwLen:
BOOL GetCurrentDirectory(
LPTSTR pstrDirName,
LPDWORD lpdwLen
) const;
В случае успешного завершения метод GetCurrentDirectory возвращает ненулевое значение, а в переменную по адресу lpdwLen записывает длину строки с именем каталога.
Метод GetCurrentDirectoryAsURL
В класс CFtpConnection входят два метода GetCurrentDirectoryAsURL, различающиеся своими парамтерами, которые позволяют определить текущий каталог на сервере FTP в формате URL. Прототипы этих методов мы привели ниже:
BOOL GetCurrentDirectoryAsURL( CString& strDirName ) const;
BOOL GetCurrentDirectoryAsURL(
LPTSTR pstrDirName, LPDWORD lpdwLen
) const;
Назначение параметров представленных выше методов GetCurrentDirectoryAsURL полностью соответствует уже описанным нами методам GetCurrentDirectory, за исключением того, что эти методы определяют текущий каталог в формате URL.
Метод GetFile
Метод GetFile копирует файл с сервера FTP на диск локального компьютера. При этом вы фактически не имеете никакой возможности следить за процессом копирования. Если вы должны знать, какая часть файла скопирована в данный момент, то вместо метода GetFile надо использовать пару методов - метод OpenFile класса CFtpConnection и метод Read класса CInternetFile. Сначала надо открыть файл на сервере FTP при помощи метода OpenFile, а затем считывать из него данные с помощью метода Read. Мы продемонстрируем оба этих метода получения файла с сервера FTP в разделе “Загрузка файлов с сервера FTP”.
Ниже мы привели прототип метода GetFile:
BOOL GetFile(
LPCTSTR pstrRemoteFile,
LPCTSTR pstrLocalFile,
BOOL bFailIfExists = TRUE,
DWORD dwAttributes = FILE_ATTRIBUTE_NORMAL,
DWORD dwFlags = FTP_TRANSFER_TYPE_BINARY,
DWORD dwContext = 1
);
Имя файла на сервере, который надо получить, передается методу GetFile через параметр pstrRemoteFile, а имя файла на диске локального компьютера - через параметр pstrLocalFile. Вы должны обязательно задать только эти два параметра. Остальные параметры имеют значения, принимаемые по умолчанию, и могут не указываться.
Параметр bFailIfExists определяет действие метода GetFile в случае, если в качестве параметра pstrLocalFile вы указали имя файла, который уже существует на диске локального компьютера. Если вы укажете в качестве параметра bFailIfExists значение TRUE или опустите этот параметр, тогда метод GetFile завершится с ошибкой. Если же параметр bFailIfExists равен FALSE то файл на локальном диске будет перезаписан. Предварительно у пользователя запрашивается разрешение на перезапись файла.
Метод GetFile позволяет выбрать атрибуты для файла, который создается на локальном диске компьютера. Эти атрибуты передаются методу через параметр dwAttributes.
Атрибут | Описание | ||
FILE_ATTRIBUTE_NORMAL | Нормальный файл | ||
FILE_ATTRIBUTE_READONLY | Файл, который можно открыть только для чтения | ||
FILE_ATTRIBUTE_HIDDEN | Скрытый файл | ||
FILE_ATTRIBUTE_SYSTEM | Системный файл | ||
FILE_ATTRIBUTE_TEMPORARY | Временный файл | ||
FILE_ATTRIBUTE_COMPRESSED | Компрессованый файл | ||
FILE_ATTRIBUTE_DIRECTORY | Каталог | ||
FILE_ATTRIBUTE_ARCHIVE | Архивный файл |
В случае успешного завершения метод GetFile возвращает ненулевое значение. Если метод завершился с ошибкой, то он возвращает ноль, а причину ошибки можно узнать с помощью функции GetLastError.
Метод передачи данных с сервера FTP на локальный компьютер можно задавать через параметр dwFlags. Если вам надо передать двоичный файл без всяких перекодировок, укажите в качестве этого параметра значение FTP_TRANSFER_TYPE_BINARY (метод FTP Image - тип I).
Если вам надо принять только текстовые данные, то вы можете использовать для этого параметра значение FTP_TRANSFER_TYPE_ASCII. При этом выполняется перекодировка данных в зависимости от программного обеспечения, установленного на сервере (метод FTP ASCII - тип A).
Идентификатор контекста для операции загруки файла можно указать в параметре dwContext. По умолчанию в качестве идентификатора контекста используется значение 1.
Метод GetFileURL
Метод GetFileURL возвращает имя файла в формате URL. Вы можете использовать данный метод после передачи запроса серверу с помощью метода SendRequest и или после того как вы открыли объект на сервере Internet с помощью метода OpenURL.
Прототип метода GetFileURL представлен ниже:
virtual CString GetFileURL( ) const;
Обнаружив файл при помощи метода FindNextFile, вы можете определить его адрес в формате URL, вызвав виртуальный метод GetFileURL:
virtual CString GetFileURL( ) const;
Метод GetFileURL возвращает адрес файла в строке класса CString.
Если в качестве имени файла для поиска вы указали шаблон, то чтобы узнать имя обнаруженного объекта - файла или каталога вы можете воспользоваться методом GetFileURL класса CFtpFileFind:
CString GetFileURL( ) const;
Он возвращает адрес обнаруженного объекта в формате URL. Для определения имени объекта вы также можете воспользоваться некоторыми методами базового класса CFileFind.
Метод GetFtpConnection
Метод GetFtpConnection выполняет соединение с заданным сервером FTP. При этом он создает соответствующий объект класса CFTPConnection, который будет представлять соединение с данным сервером. Это, кстати, единственный способ, который рекомендуется использовать для создания объектов класса CFtpConnection. Нельзя создавать объекты этого класса, напрямую обращаясь к его конструктору.
После того как вы соединились с сервером FTP и объект класса CFtpConnection создан, вы можете вызывать для него методы этого класса чтобы выполнять различные операции с сервером. Так, например, при помощи метода OpenFile вы можете открыть файл, расположенный на сервере FTP для последующего чтения или записи.
Метод GetFtpConnection имеет множество различных параметров. Однако только первый параметр вы должны будете указать в обязательном порядке. Остальные параметры можно опустить. В этом случае для них будут использоваться значения, принятые по умолчанию, которые подходят в большинстве случаев. Ниже представлен прототип метода GetFtpConnection:
CFtpConnection*
GetFtpConnection(
LPCTSTR pstrServer,
LPCTSTR pstrUserName = NULL,
LPCTSTR pstrPassword = NULL,
INTERNET_PORT nPort = INTERNET_INVALID_PORT_NUMBER,
BOOL bPassive = FALSE
);
throw( CInternetException );
Как мы уже говорили, метод GetFtpConnection создает объект класса CFtpConnection и возвращает указатель на него. Если в ходе соединения с сервером FTP возникнут какие-либо проблемы, например сервера FTP, который вы указали, вообще не существует в сети или он не активен в настоящее время, тогда метод GetFtpConnection может вызвать исключение CInternetException. Обработав данное исключение, вы сможете определить причины ошибки.
Рассмотрим теперь более подробно параметры метода.
Наиболее важный параметр pstrServer. Через него вы передаете методу GetFtpConnection адрес сервера, с которым необходимо установить соединение. Вполне естественно, что этот параметр является обязательным (конечно, корпорация Microsoft могла бы предусмотреть и для этого параметра значение по умолчанию, например ftp://ftp.microsoft.com).
Следующие два параметра pstrUserName и pstrPassword задают имя и пароль, под которым выполняется соединение с сервером FTP. Если вы не укажете имя, то по умолчанию используется anonymous. Если имя не указано, то пароль также не должен задаваться. В этом случае в качестве пароля для соединения с сервером WinInet будет использовать адрес вашей электронной почты.
Заметим, что если вы указали имя lpszUsername, то это не означает, что вы должны обязательно задавать и пароль. В случае если имя задано, а пароль нет (через параметр lpszPassword передается значение NULL или параметр не используется совсем), то в качестве пароля используется пустая строка.
Следующий параметр метода GetFtpConnection - nPort. Он определяет номер порта TCP/IP который используется сервером FTP для соединения. По умолчанию в качестве этого параметра используется значение INTERNET_INVALID_PORT_NUMBER. В этом случае метод GetFtpConnection использует при соединении с сервером FTP стандартный для него порт номер 21.
Последний параметр метода - bPassive определяет режим работы с сервером FTP. Если параметр bPassive содержит значение TRUE, то выполняется пассивное соединение с сервером.
Метод GetHttpConnection
Метод GetHttpConnection имеет сходное название с методом GetFtpConnection, и служит для соединения с сервером WWW. Для этого он создает объект класса CHttpConnection, который будет представлять соединение с сервером WWW.
Заметим, что в отличие от ранее рассмотренного метода GetFtpConnection, метод GetHttpConnection не выполняет соединения с сервером в полном смысле этого слова. Физическое соединение в сети не устанавливается. Отсюда, кстати следует, что даже если вы укажите данному методу адрес несуществующего сервера WWW, он не заметит подвоха, послушно установит “соединение” и создаст объект CHttpConnection.
Фактическое соединение с сервером WWW произойдет несколько позже, когда вы будете передавать запросы серверу, используя методы класса CHttpConnection.
Ниже мы привели прототип метода GetHttpConnection:
CHttpConnection*
GetHttpConnection(
LPCTSTR pstrServer,
INTERNET_PORT nPort = INTERNET_INVALID_PORT_NUMBER,
LPCTSTR pstrUserName = NULL,
LPCTSTR pstrPassword = NULL
);
throw( CInternetException );
Только первый параметр метода GetHttpConnection является обязательным. Он задает адрес сервера WWW с которым надо соединиться. Второй параметр - nPort - задает имя порта TCP/IP, который используется сервером WWW для соединения со своими клиентами.
По умолчанию в качестве параметра nPort используется значение INTERNET_INVALID_PORT_NUMBER. В этом случае метод GetHttpConnection использует порт номер 80, стандартный для серверов WWW.
Последние два параметра метода GetHttpConnection - pstrUserName и pstrPassword задают имя пользователя и пароль, под которым ваше приложение будет соединятся с сервером WWW.
Метод GetHttpConnection создает объект класса CHttpConnection и возвращает указатель на него. В случае возникновения ошибок, метод GetHttpConnection может вызвать исключение CInternetException, которое вы должны обрабатывать в своем приложении.
Метод GetLastWriteTime
В состав класса CFileFind входят несколько методов, которые определяют различные временные характеристики файла. Вы можете узнать время создания файла, время последнего обращения к файлу и время последнего изменения файла. Для этих целей предназначены методы GetCreationTime, GetLastAccessTime и GetLastWriteTime. Они имеют сходный формат, поэтому мы рассмотрим только метод GetLastWriteTime, остальные методы вы изучите самостоятельно.
Определены два варианта метода GetLastWriteTime, которые используют для своей работы либо традиционную структуру FILETIME, либо более соответствующий концепции библиотеки MFC объект класса CTime:
virtual BOOL GetLastWriteTime( FILETIME* pFileTime ) const;
virtual BOOL GetLastWriteTime( CTime& refTime ) const;
В случае успешного завершения метод GetLastWriteTime возвращает ненулевое значение. Если метод завершился с ошибкой, то он возвращает ноль.
Метод GetLength
После того, как вы нашли файл при помощи метода FindNextFile, вы можете определить его длину. Для этого следует воспользоваться методом GetLength, который возвращает длину файла в байтах:
DWORD GetLength( ) const;
Метод IsDirectory
Метод FindNextFile позволяет обнаружить не только файлы, но также и каталоги. Метод IsDirectory определяет какой объект получен методом FindNextFile - файл или каталог:
BOOL IsDirectory( ) const;
Если объект является каталогом, тогда метод IsDirectory возвращает значение TRUE, а если файлом - тогда FALSE.
Метод OnButtonBack
Просмотрев несколько страниц WWW, пользователь может вернуться к уже просмотренным страницам, если нажмет кнопку Back. В этом случае вызывается метод OnButtonBack класса CLookDlg, который возвращает навигатор к просмотру предыдущих страниц:
m_explorer.GoBack();
Метод OnButtonNext
Если вы перешли к уже просмотренным страницам, нажав кнопку Back, вы можете вернуться обратно, если нажмете кнопку Next. В ответ на это вызывается метод OnButtonNext класса CLookDlg, который дает соответствующую команду навигатору:
m_explorer.GoForward();
Метод OnButtonRefresh
Когда пользователь нажимает на кнопку Refresh, вызывается метод OnButtonRefresh класса CLookDlg. Этот метод обновляет текущую страницу, отображаемую в данный момент навигатором. Для этого используется метод Refresh:
m_explorer.Refresh();
Метод OnButtonStop
Пользователь может прервать загрузку страницы WWW, если нажмет кнопку Stop. В этом случае вызывается метод OnButtonStop останавливающий загрузку при помощи метода Stop:
m_explorer.Stop();
Метод OnConnect
Метод OnConnect класса CFtpViewDlg вызывается, когда вы нажимаете кнопку Connect чтобы соединится с сервером FTP. Адрес сервера FTP, с которым устанавливается соединение, должен быть введен в поле редактирования IDC_FTP_ADDRESS. Это поле располагается на диалоговой панели с левой стороны от кнопки Connect.
Перед тем как устанавливать соединение с сервером FTP, метод OnConnect блокирует кнопки управления, расположенные на диалоговой панели - Connect, OK и On top. Блокировка выполняется с помощью метода EnableWindow, определенного в классе CWnd. Этот метод вызывается для объектов m_Connect, m_Ok и m_OnTop класса CButton, представляющих эти кнопки:
// Блокируем кнопки Connect, OK и On Top
m_Connect.EnableWindow(FALSE);
m_Ok.EnableWindow(FALSE);
m_OnTop.EnableWindow(FALSE);
Если вы ранее уже соединились с сервером FTP и указатель m_FtpConnection не равен значению NULL, разрываем эту связь и удаляем объект m_FtpConnection. Затем присваиваем m_FtpConnection значение NULL:
if (m_FtpConnection != NULL)
{
m_FtpConnection -> Close();
delete m_FtpConnection;
m_FtpConnection = NULL;
}
Пользователь мог изменить адрес сервера, с которым надо установить соединение, поэтому обновляем строку m_FtpAddress, считывая значение из поля редактирования IDC_FTP_ADDRESS. Для этого опять (раньше в методе OnInitDialog) вызываем метод UpdateData, но теперь указываем ему параметр TRUE. Он означает, что состояние органов управления диалоговой панели должно быть записано в привязанные к ним переменные:
UpdateData(TRUE);
Теперь, когда адрес сервера известен, пытаемся с ним соединиться. Для этого вызываем метод GetFtpConnection класса CInternetSession объекта. В случае ошибки метод GetFtpConnection может вызвать исключение CInternetException.
Чтобы организовать обработку этого исключения помещаем вызов метода GetFtpConnection в блок try и создаем соответствующий блок catch:
// Пытаемся соединиться с сервером FTP
try
{
// Меняем форму курсора (курсор “ожидание”)
CWaitCursor wait;
// Соединяемся с сервером FTP. Эта операция
// может вызвать исключение CInternetException
m_FtpConnection =
m_InternetSession->GetFtpConnection(m_FtpAddress);
}
Так как процесс соединения с сервером может занять достаточно много времени, изменяем форму курсора. Для этого достаточно создать объект wait класса CWaitCursor. Курсор примет свою прежнюю форму автоматически, когда объект wait будет удален. В данном случае это произойдет при выходе из блока try.
В случае если работа метода GetFtpConnection вызовет исключение CInternetException, вызывается соответствующий блок catch. Такое может произойти, например, если сервер FTP с заданным адресом не существует или он не работает в данное время.
Обработчик исключения вызывает для него метод GetErrorMessage. Он возвращает текстовое описание причины исключения, которое затем отображается на экране с помощью функции AfxMessageBox. Если метод GetErrorMessage не может вернуть текстового описания, то на экране отображается сообщение GetFtpConnection Error.
Чтобы завершить обработку исключения удаляем его, вызывая для исключения метод Delete. Так как исключение означает, что установить соединение с FTP сервером не удалось, присваиваем указателю m_FtpConnection значение NULL:
catch (CInternetException* pEx)
{
// Обрабатываем исключение CInternetException
TCHAR szErr[1024]; // временный буфер для сообщения
// Выводим сообщение об ошибке
if (pEx->GetErrorMessage(szErr, 1024))
AfxMessageBox(szErr);
else
AfxMessageBox("GetFtpConnection Error");
// Удаляем иссключение
pEx->Delete();
// Обнуляем указатель m_FtpConnection
m_FtpConnection = NULL;
}
Если соединение не установлено, тогда выводим соответствующую надпись в поле IDC_STATUS, снимаем блокировку кнопок Connect, OK и On Top и завершаем работу метода. Чтобы снять блокировку кнопок, вызываем для управляющих ими объектов метод EnableWindow с параметром TRUE:
if( m_FtpConnection == NULL )
m_Status.SetWindowText("Connect not established");
...
m_Connect.EnableWindow(TRUE);
m_Ok.EnableWindow(TRUE);
m_OnTop.EnableWindow(TRUE);
Если соединение с сервером FTP установлено успешно, определяем текущий каталог. Для этого вызываем метод GetCurrentDirectory, передавая ему в качестве параметра строку sCurrentFtpDirectory. Эта строка определена в методе OnConnect как объект класса CString:
// Определяем текущий каталог сервера FTP
BOOL fResult=
m_FtpConnection ->
GetCurrentDirectory(sCurrentFtpDirectory);
if(fResult)
sCurentDirectory = sCurrentFtpDirectory;
else
AfxMessageBox("GetCurrentDirectory Error");
В случае успешного завершения метод GetCurrentDirectory запишет в строку sCurrentFtpDirectory полный путь текущего каталога и мы скопируем его в строку sCurentDirectory, являющуюся элементом класса CFtpViewDlg.
Узнав текущий каталог, вызываем метод DirectoryView, определенный в классе CFtpViewDlg, который считывает имена файлов и каталогов сервера FTP и отображает их в списке на диалоговой панели. Перед вызовом метода DirectoryView мы создаем объект класса CWaitCursor, поэтому во время длительного процесса опроса текущего каталога сервера курсор изменит свою форму. Заметим, что после заполнения списка при выходе управления из блока в котором определен объект wait класса CWaitCursor, форма курсора автоматически восстанавливается:
// Меняем форму курсора (курсор “ожидание”)
CWaitCursor wait;
// Отображаем содержимое выбранного каталога
DirectoryView();
После того, как содержимое каталога выведено в списке на диалоговой панели, отображаем в поле IDC_STATUS путь каталога и снимаем блокировку с кнопок Connect, OK и On Top:
// Отображаем на диалоговой панели новый путь каталога
m_Status.SetWindowText(sCurentDirectory);
Метод OnDblclkFtpList
В списке IDC_FTP_LIST показываются имена файлов и каталогов сервера FTP. Файлы выделяются пиктограммой
, а каталоги пиктограммой и строкой Dir в столбце Length. Чтобы вы имели возможность просмотра не только того каталога, с которым вас по умолчанию соединил сервер FTP, но также и других вложенных каталогов, мы предусмотрели метод OnDblclkFtpList.¨ Наше приложение не меняет текущий каталог сервера FTP. Для этого предназначен метод SetCurrentDirectory класса CFtpConnection. Изменяется только каталог, в котором осуществляется поиск файлов и других каталогов
Метод OnDblclkFtpList вызывается когда пользователь выполняет двойной щелчок левой клавишей мыши по имени каталога или имени файла. В качестве параметров методу OnDblclkFtpList передаются указатель pNMHDR на структуру типа NMHDR и указатель pResult на переменную типа LRESULT.
Рассмотрим метод OnDblclkFtpList более подробно. Сначала он блокирует список IDC_FTP_LIST, вызывая метод EnableWindow с параметром FALSE:
CString sSelItem; // Название каталога
// Блокируем список IDC_FTP_LIST
m_FtpList.EnableWindow(FALSE);
Затем с помощью метода GetItemCount мы определяем количество элементов в списке IDC_FTP_LIST и записываем его во временную переменную iTotalNumber типа int:
iTotalNumber = m_FtpList.GetItemCount();
Далее мы пытаемся определить элемент, который выбран из списка. К сожалению мы не обнаружили простого способа выполнить эту задачу. Поэтому последовательно проверяем все элементы списка до тех пор, пока не найдем элемент, у которого установлен атрибут LVIS_SELECTED, означающий, что он выбран.
Для определения атрибутов элемента списка вызываем метод GetItemState. В качестве первого параметра методу GetItemState указывается индекс элемента, атрибуты которого надо определить, а в качестве второго - комбинацию атрибутов состояние которых нужно узнать. В нашем случае в качестве второго параметра фигурирует только константа LVIS_SELECTED, так как нас интересует только выбран данный элемент или нет:
// Определяем, какой объект списка выбран
for(int i = 0; i < iTotalNumber; i++)
{
if(LVIS_SELECTED == m_FtpList.GetItemState(i,LVIS_SELECTED))
{
. . .
break;
}
}
Если метод m_FtpList.GetItemState( i, LVIS_SELECTED )) возвращает значение LVIS_SELECTED, значит элемент с индексом i выбран из списка. В этом случае определяем имя соответствующего объекта и его размер, считывая их непосредственно из первой и второй колонки списка:
// Определяем название выбранного элемента списка
// (имя файла или каталога)
sSelItem = m_FtpList.GetItemText( i, 0 );
// Считываем данные из колонки Length
sLength_Dir = m_FtpList.GetItemText( i, 1 );
Если вместо длины файла во второй колонке записана строка Dir, значит из списка выбран каталог. Тогда мы добавляем название этого каталога к концу строки, содержащей текущий каталог сервера FTP.
В противном случае вы выбрали из списка не каталог, а файл и на экран выводится предупреждающее сообщение, о том что вы выбрали файл с определенным именем:
if(sLength_Dir == "Dir") // Выбран каталог
sCurentDirectory = sCurentDirectory + "/" + sSelItem;
else // Выбран файл
AfxMessageBox("You select file " + sSelItem);
После этого изменяем форму курсора и вызываем метод DirectoryView, который считывает имена объектов, расположенных в каталоге sCurentDirectory и отображает их в списке диалоговой панели приложения.
Чтобы изменить форму курсора мы создаем объект wait класса CWaitCursor. Когда при выходе из метода OnDblclkFtpList этот объект удаляется, курсор автоматически восстанавливает свою форму:
. . .
// Меняем форму курсора (курсор “ожидание”)
CWaitCursor wait;
// Отображаем содержимое выбранного каталога
DirectoryView();
}
Затем в поле IDC_STATUS отображается новый путь каталога и снимается блокировка со списка, так что мы опять можем выбирать из него файлы и каталоги:
// Отображаем на диалоговой панели новый путь каталога
m_Status.SetWindowText(sCurentDirectory);
// Снимаем блокировку списка IDC_FTP_LIST
m_FtpList.EnableWindow(TRUE);
В завершении метода OnDblclkFtpList мы записываем по адресу pResult нулевое значение, которое означает, что метод успешно завершен:
*pResult = 0;
Метод OnDownloadBeginExplorer
Когда навигатор приступает к загрузке очередного объекта с сервера, будь то сама страница HTML, рисунок, анимация или что либо еще, вызывается метод OnDownloadBeginExplorer.
В этом случае мы инициализируем линейный индикатор, который будет показывать ход загрузки данного объекта:
m_Progress.SetRange(0, 100);
m_Progress.SetStep(0);
m_Progress.SetPos(0);
Метод OnDownloadCompleteExplorer
По окончании загрузки очередного объекта, навигатор вызывает метод OnDownloadCompleteExplorer. В нем мы сбрасываем линейный индикатор в начальное положение:
m_Progress.SetPos(0);