SQLite – это встраиваемый движок баз данных. Слово «встраиваемый» означает, что SQLite не использует парадигму клиент-сервер, то есть движок SQLite не является отдельно работающим процессом, с которым взаимодействует программа, а предоставляет библиотеку, с которой программа компонуется и движок становится составной частью программы. Это значит, что для своей работы SQLite не требует установки. Это, а также довольно простой набор API-функций, делает ее наиболее простым инструментом для разработки приложений, использующих в своей работе базы данных.

Чтобы начать работу с SQLite нам необходимо загрузить исходный код библиотеки с официального сайта http://sqlite.org. На официальном сайте SQLite есть возможность загрузить уже собранные бинарные версии библиотеки для Windows, Linux и Mac OS X. Но во-первых, Windows Mobile в списке платформ, для которых SQLite доступна в бинарном виде, отсутствует, а во-вторых, индейцы не ищут легких путей, да и при сборке SQLite со статической линковкой CRT библиотек можно избежать зависимости от Microsoft Visual C++ Runtime не таскать за собой дополнительные файлы.
Для работы лучше использовать версию исходного кода SQLite в виде одного файла. На сайте в разделе загрузок он имеет название sqlite-amalgamation-x_y_z.zip, где x, y, z представляют собой версию библиотеки.
Итак, начнем. Превым делом нам необходимо создать проект статической библиотеки. Для этого в Visual Studio выбираем пункт меню File -> New -> Project, идем в раздел Visual C++ -> Smart Device, выбираем тип проекта Win32 Smart Device Project, указываем имя проекта sqlite3, жмем OK.

Создаем проект SQLite3 для Smart Device в Visual Studio
Создаем проект SQLite3 для Smart Device в Visual Studio

После этого на экране появится мастер настройки параметров нового проекта. Идем в раздел Platforms и выбираем платформы для которых мы хотим собрать нашу библиотеку. Рекомендую выбирать все теоретически необходимые платформы, т.к. это намного проще чем потом добавлять их в проект с помощью Configuration Manager.
Выбираем платформы для сборки SQLite для Windows Mobile
Выбираем платформы для сборки SQLite для Windows Mobile

В разделе Application Settings указываем тип проекта Static Library и убираем маркер с Precompiled header, жмем Finish.
Выбираем тип проекта для сборки SQLite3
Выбираем тип проекта для сборки SQLite3

Теперь у нас есть пустой проект, в который нам нужно добавить исходный код из дистрибутива SQLite, а именно файлы sqlite3.h, sqlite3.c, sqlite3ext.h
После того как исходный код добавлен в проект, в Solution Explorer у нас должно получиться что-то подобное.
Вид Solution Explorer после добавления в проект исходного кода SQLite3
Вид Solution Explorer после добавления в проект исходного кода SQLite3

Это все. Об использовании SQLite я расскажу в своих следующих постах.

Previous ArticleNext Article
Технический директор IT-Dimension, компании-разработчика кросс-платформенного программного обеспечения

Leave a Reply

Your email address will not be published. Required fields are marked *

П.

Пишем мобильный клиент для Google Translate на C++

В этот раз я хочу рассказать о том как работать с еще одним online-сервисом, а именно с сервисом online-переводов Google Translate.

Для работы с этим сервисом у Google есть свой программный интерфейс, а именно AJAX Language API for Translation And Detection. Именно его мы и будем использовать.

Для того чтобы осуществить online-перевод текста необходимо сделать http-запрос к сервису переводов, доступному по адресу:

http://ajax.googleapis.com/ajax/services/language/translate

Параметры, которые необходимо передать сервису:

  • v=1.0 – версия сервиса
  • q=<sometext> – URL-encoded текст для перевода.
  • langpair=<source_language>%7C<result_language> – пара названий языков: исходного и результирующего


Например для перевода текста “Hello World” с английского на русский строка запроса будет выглядеть так:

http://ajax.googleapis.com/ajax/services/language/translate?v=1.0&q=Hello%20World&langpair=en%7Cru

Ну вот, небольшой теоретический экскурс закончен, можно приступать к кодингу:
wxGoogleTranslate.h

#ifndef _WX_GOOGLE_TRANSLATE_H
#define _WX_GOOGLE_TRANSLATE_H

#include <wx/wx.h>

class wxGoogleTranslate
{
	/// \brief Language Info
	struct wxGoogleTranslateLanguageInfo
	{
		/// \brief Full language name
		wxString languageName;
		/// \brief Language code
		wxString languageCode;
	};

	/// \brief Stores information about all supported languages
	static wxGoogleTranslateLanguageInfo m_LanguageInfoArray[];
	/**
	\brief Parses JSON response from Google Translate service
	\param response contains JSON response from Google Translate service
	\param translatedText contains translated text if parsing of JSON response was correct
	\param translateionDetails contains additional information from Google Translate service
		   usually it is error message
    \param translationStatus contains parsing status (error code)
	\return true if translation and parsing was successfull, otherwise false
	*/
	static bool ParseJSONResponse(const wxString & response,
		wxString & translatedText,
		wxString & translateionDetails,
		int & translationStatus);
public:
	/// \brief Returns the list of all suported languages
	/// \param result array for storing language names
	static void GetLanguages(wxArrayString & result);
	/**
	\brief Returns language code by language name
	\param languageName language name
	\return language code on success or empty string on error
	*/
	static wxString GetLanguageCode(const wxString & languageName);
	/**
	\brief Translates given text with Google Translate service
	\param source string to translate
	\param result translation result
	\param sourceLanguageCode source language code
	\param resultLanguageCode destination language code
	\param translationDetails error message
	\param errorCode error code
	\return true on success, otherwise false
	*/
	static bool Translate(const wxString & source, 
		wxString & result, 
		const wxString & sourceLanguageCode, 
		const wxString & resultLanguageCode,
		wxString & translationDetails,
		int & errorCode);
};

#endif

Итак, как я уже писал выше, для того чтобы сформировать корректный URL запроса нам необходимо чтобы текст для перевода был URL-encoded. Для этоко пишем функцию URLEncode()

wxString HexFromInt(const int &value)
{
	wxString szHexHolder;

	if( value < 16)
		szHexHolder.Printf(wxT("0%x"), value );
	else
		szHexHolder.Printf(wxT("%x"), value );

	return szHexHolder.MakeUpper();
}

wxString URLEncode(const wxString &value)
{
	wxString szToReturn = wxT("");
	unsigned int nPos = 0;

	while( value.length() > nPos ) 
	{
		wxChar cChar = value.GetChar(nPos);

		if( (cChar >= wxT('0') && cChar <= wxT('9')) || 
			(cChar >= wxT('a') && cChar <= wxT('z')) || 
			(cChar >= wxT('A') && cChar <= wxT('Z')) || 
			(cChar == wxT('-')) || (cChar == wxT('@')) || 
			(cChar == wxT('*')) || (cChar == wxT('_')) )
		{
			szToReturn.Append( cChar );
		}
		else
		{
			switch( cChar )
			{
			case wxT(' '):  szToReturn.Append(wxT('+')); break;
			case wxT('\n'): szToReturn.Append(wxT("%0D%0A")); break;
			default:
				{
					szToReturn.Append(wxT("%"));
					szToReturn += HexFromInt( cChar );
				}
			}
		}
		nPos++;
	}
	return szToReturn;
}
&#91;/sourcecode&#93;
На самом деле большая часть приведенного выше кода позаимствована из библиотеки wxHTTPEngine, но, к сожалению, исходная реализация не работала с русскими символами и пришлось ее немного доработать напильником.
Так, с URL-encoding'ом разобрались, но это еще не все. Перед тем как формировать URL-encoded строку нам необходимо текст преобразовать в UTF-8. Для этого можно использовать метод <strong>wxString::ToUTF8()</strong>.
Список поддерживаемых сервисом языков можно найти на странице описания Google Language API. У нас в программе для этого будет массив структур, каждая из которых будет содержать полное название языка и его код (который можно будет передать в параметр <strong>languagepair</strong>):

wxGoogleTranslate::wxGoogleTranslateLanguageInfo 
	wxGoogleTranslate::m_LanguageInfoArray[] =
{
	{wxT("AFRIKAANS"),				wxT("af")},
	{wxT("ALBANIAN"),				wxT("sq")},
	{wxT("AMHARIC"),				wxT("am")},
	{wxT("ARABIC"),					wxT("ar")},
	{wxT("ARMENIAN"),				wxT("hy")},
	{wxT("AZERBAIJANI"),			wxT("az")},
	{wxT("BASQUE"),					wxT("eu")},
	{wxT("BELARUSIAN"),				wxT("be")},
	{wxT("BENGALI"),				wxT("bn")},
	{wxT("BIHARI"),					wxT("bh")},
	{wxT("BULGARIAN"),				wxT("bg")},
	{wxT("BURMESE"),				wxT("my")},
	{wxT("CATALAN"),				wxT("ca")},
	{wxT("CHEROKEE"),				wxT("chr")},
	{wxT("CHINESE"),				wxT("zh")},
	{wxT("CHINESE_SIMPLIFIED"),		wxT("zh-CN")},
	{wxT("CHINESE_TRADITIONAL"),	wxT("zh-TW")},
	{wxT("CROATIAN"),				wxT("hr")},
	{wxT("CZECH"),					wxT("cs")},
	{wxT("DANISH"),					wxT("da")},
	{wxT("DHIVEHI"),				wxT("dv")},
	{wxT("DUTCH"),					wxT("nl")},
	{wxT("ENGLISH"),				wxT("en")},
	{wxT("ESPERANTO"),				wxT("eo")},
	{wxT("ESTONIAN"),				wxT("et")},
	{wxT("FILIPINO"),				wxT("tl")},
	{wxT("FINNISH"),				wxT("fi")},
	{wxT("FRENCH"),					wxT("fr")},
	{wxT("GALICIAN"),				wxT("gl")},
	{wxT("GEORGIAN"),				wxT("ka")},
	{wxT("GERMAN"),					wxT("de")},
	{wxT("GREEK"),					wxT("el")},
	{wxT("GUARANI"),				wxT("gn")},
	{wxT("GUJARATI"),				wxT("gu")},
	{wxT("HEBREW"),					wxT("iw")},
	{wxT("HINDI"),					wxT("hi")},
	{wxT("HUNGARIAN"),				wxT("hu")},
	{wxT("ICELANDIC"),				wxT("is")},
	{wxT("INDONESIAN"),				wxT("id")},
	{wxT("INUKTITUT"),				wxT("iu")},
	{wxT("ITALIAN"),				wxT("it")},
	{wxT("JAPANESE"),				wxT("ja")},
	{wxT("KANNADA"),				wxT("kn")},
	{wxT("KAZAKH"),					wxT("kk")},
	{wxT("KHMER"),					wxT("km")},
	{wxT("KOREAN"),					wxT("ko")},
	{wxT("KURDISH"),				wxT("ku")},
	{wxT("KYRGYZ"),					wxT("ky")},
	{wxT("LAOTHIAN"),				wxT("lo")},
	{wxT("LATVIAN"),				wxT("lv")},
	{wxT("LITHUANIAN"),				wxT("lt")},
	{wxT("MACEDONIAN"),				wxT("mk")},
	{wxT("MALAY"),					wxT("ms")},
	{wxT("MALAYALAM"),				wxT("ml")},
	{wxT("MALTESE"),				wxT("mt")},
	{wxT("MARATHI"),				wxT("mr")},
	{wxT("MONGOLIAN"),				wxT("mn")},
	{wxT("NEPALI"),					wxT("ne")},
	{wxT("NORWEGIAN"),				wxT("no")},
	{wxT("ORIYA"),					wxT("or")},
	{wxT("PASHTO"),					wxT("ps")},
	{wxT("PERSIAN"),				wxT("fa")},
	{wxT("POLISH"),					wxT("pl")},
	{wxT("PORTUGUESE"),				wxT("pt-PT")},
	{wxT("PUNJABI"),				wxT("pa")},
	{wxT("ROMANIAN"),				wxT("ro")},
	{wxT("RUSSIAN"),				wxT("ru")},
	{wxT("SANSKRIT"),				wxT("sa")},
	{wxT("SERBIAN"),				wxT("sr")},
	{wxT("SINDHI"),					wxT("sd")},
	{wxT("SINHALESE"),				wxT("si")},
	{wxT("SLOVAK"),					wxT("sk")},
	{wxT("SLOVENIAN"),				wxT("sl")},
	{wxT("SPANISH"),				wxT("es")},
	{wxT("SWAHILI"),				wxT("sw")},
	{wxT("SWEDISH"),				wxT("sv")},
	{wxT("TAJIK"),					wxT("tg")},
	{wxT("TAMIL"),					wxT("ta")},
	{wxT("TAGALOG"),				wxT("tl")},
	{wxT("TELUGU"),					wxT("te")},
	{wxT("THAI"),					wxT("th")},
	{wxT("TIBETAN"),				wxT("bo")},
	{wxT("TURKISH"),				wxT("tr")},
	{wxT("UKRAINIAN"),				wxT("uk")},
	{wxT("URDU"),					wxT("ur")},
	{wxT("UZBEK"),					wxT("uz")},
	{wxT("UIGHUR"),					wxT("ug")},
	{wxT("VIETNAMESE"),				wxT("vi")},
	{wxT("UNKNOWN"),				wxEmptyString}
};

Для получения списка языков будет использоваться метод wxGoogleTranslate::GetLanguages()

void wxGoogleTranslate::GetLanguages(wxArrayString & result)
{
	result.Clear();
	int count = sizeof(m_LanguageInfoArray) / 
		sizeof(wxGoogleTranslateLanguageInfo);
	for(int i = 0; i < count; i++)
	{
		result.Add(m_LanguageInfoArray&#91;i&#93;.languageName);
	}
}
&#91;/sourcecode&#93;
Для получения кода языка предназначен метод <strong>wxGoogleTranslate::GetLanguageCode()</strong>:

wxString wxGoogleTranslate::GetLanguageCode(const wxString & languageName)
{
	int count = sizeof(m_LanguageInfoArray) / 
		sizeof(wxGoogleTranslateLanguageInfo);
	for(int i = 0; i < count; i++)
	{
		if(m_LanguageInfoArray&#91;i&#93;.languageName.Lower().IsSameAs(
			languageName.Lower()))
		{
			return m_LanguageInfoArray&#91;i&#93;.languageCode;
		}
	}
	return wxEmptyString;
}
&#91;/sourcecode&#93;
Теперь можно реализовывать непосредственно метод для перевода текста:
&#91;sourcecode language="cpp"&#93;
bool wxGoogleTranslate::Translate(const wxString & source, 
		wxString & result, 
		const wxString & sourceLanguageCode, 
		const wxString & resultLanguageCode,
		wxString & translationDetails,
		int & errorCode)
{
	do
	{
		wxString urlEncodedSource = 
			URLEncode(wxString::FromAscii(source.ToUTF8()));
		wxString srcURL = wxString::Format(
			wxT("%s?v=1.0&q=%s&langpair=%s%%7C%s"),
			wxT("http://ajax.googleapis.com/ajax/services/language/translate"),
			urlEncodedSource.GetData(),
			sourceLanguageCode.GetData(),
			resultLanguageCode.GetData());
		wxURL url = srcURL;
		if(url.GetError() != wxURL_NOERR) break;
		wxInputStream * in = url.GetInputStream();
		if(!in) break;
		wxString response;
		wxStringOutputStream out(&response);
		in->Read(out);
		wxDELETE(in);
		if(response.IsEmpty()) break;
		if(!wxGoogleTranslate::ParseJSONResponse(response, result, 
			translationDetails, errorCode)) break;
		return true;
	}
	while(false);
	return false;
}

Результат запроса приходит в формате JSON. В стандартной поставке wxWidgets библиотеки для парсинга JSON нет, зато есть сторонняя библиотека wxJSON, которую мы и будем использовать.
Формат ответа от сервиса Google Translate:

{"responseData": {"translatedText":"sometext"}, "responseDetails": "sometext", "responseStatus": 200}

Где

  • translatedText – переведенный текст
  • responseDetails – дополнительная информация от сервиса (сообщение об ошибке)
  • responseStatus – код ошибки

Метод для парсинга ответа сервиса:

bool wxGoogleTranslate::ParseJSONResponse(const wxString & response,
		wxString & translatedText,
		wxString & translateionDetails,
		int & translationStatus)
{
	do
	{
		wxJSONValue  root;
		wxJSONReader reader;
		if(reader.Parse(response, &root) > 0) break;
		translatedText = 
			root[wxT("responseData")][wxT("translatedText")].AsString();
		translateionDetails = 
			root[wxT("responseDetails")].AsString();
		translationStatus = 
			root[wxT("responseStatus")].AsInt();
		return true;
	}
	while(false);
	return false;
}

Ну вот, работу над классом переводчика закончили. Теперь посмотрим как его использовать:

void wxGoogleTranslateClientMainFrame::OnTRANSLATEClick( wxCommandEvent& event )
{
	do
	{
		wxString result;
		wxString details;
		int errorCode(0);
		int sourceLangselection = m_SourceLanguageChoice->GetSelection();
		int resultLangselection = m_ResultLanguageChoice->GetSelection();
		if((sourceLangselection < 0) || (resultLangselection < 0)) break;
		if(wxGoogleTranslate::Translate(m_SourceTextCtrl->GetValue(), 
			result, 
			wxGoogleTranslate::GetLanguageCode(
				m_SourceLanguageChoice->GetString(sourceLangselection)), 
			wxGoogleTranslate::GetLanguageCode(
			m_ResultLanguageChoice->GetString(resultLangselection)), 
				details, errorCode))
		{
			m_ResultTextCtrl->SetValue(result);
		}
		else
		{
			wxMessageBox(wxString::Format(_("Erorr occured: %s"), details.GetData()));
		}
	}
	while(false);
}

Хотелось бы отметить вот что: для загрузки ответа от сервиса используется класс wxURL. Используется синхронно, поэтому работа вызывающего потока приложения блокируется до тех пор пока загрузка не будет завершена.
Использование же класса переводчика заключается в вызове метода Translate(), никаких дополнительных действий по инициализации или деинициализации не требуется.

Исходный код библиотеки wxGoogleTranslate, а также исходный код и исполняемые файлы примера для Windows NT/2000/XP/Vista и для Windows Mobile 2003/5/6 можно загрузить здесь.

У.

Учимся скачивать файлы программно в Windows Mobile

Разработка приложений, использующих в своей работе сетевое взаимодействие или доступ к ресурсам Internet – это довольно популярная штука в наши дни. И в этот раз мы рассмотрим такую часто используемую задачу как загрузка файлов из Internet.

Для того чтобы скачать файл в C++ приложении с wxWinCE надо совсем немного кода. В простейшем случае для реализации однопоточной загрузки файла мы можем использовать класс wxURL, скормив ему адрес загружаемого ресурса.

void MobileDownloaderMainFrame::OnDOWNLOADClick( wxCommandEvent& event )
{
	do
	{
		wxString address = wxGetTextFromUser(_("Input URL"), 
			wxGetTextFromUserPromptStr, 
			wxT("http://wxwidgets.info"));
		if(address.IsEmpty()) break;
		wxURL url(address);
		if(!url.IsOk()) break;
		wxInputStream * stream = url.GetInputStream();
		if(!stream) break;
		wxString result;
		wxStringOutputStream out(&result);
		out.Write(*stream);
		delete stream;
		m_SingleThreadedResultTextCtrl->SetValue(result);
	}
	while(false);
}

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

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

Наш следующий пример демонстрирует как можно реализовать многопоточную загрузку файлов с минимальными усилиями.

Для начала создадим класс, который будет содержать информацию о загрузке:

#ifndef _DOWNLOAD_INFO_H
#define _DOWNLOAD_INFO_H

#include <wx/wx.h>
#include <DownloadFile.h>
#include <DownloadEvent.h>

class DownloadInfo
{
private:
	wxInt64 m_DownloadedSize;
	wxString m_URL;
	wxDownloadEvent::DownloadSTATUS m_Status;
	wxDownloadFile * m_Downloader;
public:
	DownloadInfo(const wxString & url)
		: m_DownloadedSize(0), m_URL(url), 
		m_Status(wxDownloadEvent::DOWNLOAD_NONE), m_Downloader(NULL) {}

	const wxString & GetURL() {return m_URL;}

	wxInt64 GetDownloadedSize() {return m_DownloadedSize;}
	void SetDownloadedSize(wxInt64 value) {m_DownloadedSize = value;}

	wxDownloadEvent::DownloadSTATUS GetStatus() {return m_Status;}
	void SetStatus(wxDownloadEvent::DownloadSTATUS value) {m_Status = value;}

	wxDownloadFile * GetDownloader() {return m_Downloader;}
	void SetDownloader(wxDownloadFile * value) {m_Downloader = value;}
};

WX_DECLARE_STRING_HASH_MAP(DownloadInfo *, DownloadsHash);

#endif

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

Для отображения информации о загрузках мы будем использовать компонент wxSimpleHtmlListBox. Компонент будет содержать указатель на хеш-таблицу с загрузками.

Чтобы в списке загрузок отображалась актуальная информация, нам необходимо переопределить метод OnGetItem().

#include "DownloadInfo.h"
...
class wxDownloadListBox: public wxSimpleHtmlListBox
{
...
    DownloadsHash * GetDownloads() const { return m_Downloads ; }
    void SetDownloads(DownloadsHash * value) { m_Downloads = value ; }

    virtual wxString OnGetItem(size_t n) const;

    void AddNew() {SetItemCount(GetItemCount()+1);}

    DownloadsHash * m_Downloads;
};

wxString wxDownloadListBox::OnGetItem(size_t n) const
{
	wxString value;
	do 
	{
		DownloadsHash::iterator i = m_Downloads->begin();
		for(size_t j = 0; (j < n) && (i != m_Downloads->end()); j++)
		{
			i++;
		}
		if(i == m_Downloads->end()) break;
		value = wxString::Format(wxT("<b>%s</b>"), i->first.GetData());
		DownloadInfo * download = i->second;
		if(!download) break;
		switch(download->GetStatus())
		{
		case wxDownloadEvent::DOWNLOAD_INPROGRESS:
			value += wxString::Format(
				_(" - <i>downloaded %d bytes</i>"), 
				download->GetDownloadedSize());
			break;
		case wxDownloadEvent::DOWNLOAD_COMPLETE:
			value += _(" (finished)");
			break;
		case wxDownloadEvent::DOWNLOAD_FAIL:
			value += _(" (failed)");
			break;
		}
	}
	while (false);
	return value;
}

Метод AddNew() указывает компоненту, что у него добавился новый элемент.

Теперь рассмотрим код, создающий новую загрузку и добавляющий ее в список:

void MobileDownloaderMainFrame::OnADDClick( wxCommandEvent& event )
{
	do 
	{
		DownloadParametersDialog * dlg = new DownloadParametersDialog(this);
		int result = dlg->ShowModal();
		wxString url = dlg->m_URLTextCtrl->GetValue();
		wxString fileName = dlg->m_FileNamePicker->GetPath();
		dlg->Destroy();
		if(result != wxID_OK) break;
		DownloadInfo * info = m_Downloads[url];
		bool needAddNew(true);
		if(info != NULL)
		{
			info->GetDownloader()->CancelDownload();
			needAddNew = false;
		}
		else
		{
			info = new DownloadInfo(url);
		}
		wxDownloadFile * download = new wxDownloadFile(this, url, fileName, true);
		
		info->SetDownloader(download);
		m_Downloads[url] = info;

		download->Run();
		if(needAddNew)m_DownloadsListBox->AddNew();

		m_DownloadsListBox->RefreshLines(
			m_DownloadsListBox->GetFirstVisibleLine(),
			m_DownloadsListBox->GetLastVisibleLine());
	} 
	while (false);
}

Собственно, что у нас здесь происходит:

  • отображается диалог создания новой загрузки. В нем необходимо ввести URL и путь к результирующему файлу
  • В случае если диалог отработал успешно, мы проверяем наличие загрузки с указанным URL в хеш-таблице
  • Если загрузка присутствует, то она останавливается
  • Если загрузки с указанным URL в таблице нет, то создается новый объект DownloadInfo
  • Затем создается объект wxDownloadFile и запускается
  • После этого происходит обновление списка загрузок

Как уже было сказано ранее, класс wxDownloadFile позволяет получать уведомления о состоянии загрузки. Для этого используется обработчик события EVT_DOWNLOAD():

BEGIN_EVENT_TABLE( MobileDownloaderMainFrame, wxFrame )
...
EVT_DOWNLOAD(MobileDownloaderMainFrame::OnDownloadStatus)
END_EVENT_TABLE()

void MobileDownloaderMainFrame::OnDownloadStatus(wxDownloadEvent & event)
{
	do
	{
		wxString url = event.GetDownLoadURL();
		DownloadInfo * downloadInfo = m_Downloads[url];
		wxDownloadFile * download = downloadInfo->GetDownloader();
		if(!download) break;
		downloadInfo->SetStatus((wxDownloadEvent::DownloadSTATUS)event.GetDownLoadStatus());
		switch(event.GetDownLoadStatus())
		{
		case wxDownloadEvent::DOWNLOAD_FAIL:
			wxLogDebug(wxT("DOWNLOAD_FAIL"));
			downloadInfo->SetDownloader(NULL);
			break;
		case wxDownloadEvent::DOWNLOAD_COMPLETE:
			wxLogDebug(wxT("DOWNLOAD_COMPLETE"));
			downloadInfo->SetDownloader(NULL);
			break;
		case wxDownloadEvent::DOWNLOAD_INPROGRESS:
			wxLogDebug(wxT("DOWNLOAD_INPROGRESS"));
			downloadInfo->SetDownloadedSize(event.GetDownLoadedBytesCount());
			break;
		default:
			break;
		}
		m_DownloadsListBox->RefreshLines(
			m_DownloadsListBox->GetFirstVisibleLine(),
			m_DownloadsListBox->GetLastVisibleLine());
	}
	while(false);
}

В обработчике события мы получаем состояние загрузки из объекта wxDownloadEvent и, в зависимости от этого значения, выполняем обновление объекта DownloadInfo в хеш-таблице загрузок.

О чем еще важно помнить? Приложение остается висеть в памяти пока не будут завершены все его потоки. wxDownloadFile создает поток на каждую загрузку и если мы попытаемся закрыть приложение во время скачивания файлов, то приложение будет выгружено только по завершению всех потоков. Чтобы такой ситуации у нас не было, нам необходимо принудительно завершить все потоки при закрытии главной формы приложения. Для этого мы будем использовать обработчик EVT_CLOSE():

void MobileDownloaderMainFrame::OnCloseWindow( wxCloseEvent& event )
{
	for(DownloadsHash::iterator i = m_Downloads.begin(); i != m_Downloads.end(); i++)
	{
		DownloadInfo * download = i->second;
		if(!download) continue;
		if(download->GetDownloader()) download->GetDownloader()->CancelDownload();
		wxDELETE(download);
		i->second = NULL;
	}
    event.Skip();
}

Вот теперь все.
wxMobileDownloader - Пример использования wxDownloadFile
Скачать исходный код приложения и проекты для Win32 и Windows Mobile.