Очень часто вижу на форумах темы, связанные с организацией доступа к базам данных для приложений на C++. Тема, сама по себе, довольно актуальная и очень интересная, хотя у новичков зачастую вызывает трудности. И в этот раз я хочу рассказать о том, что написание кросс-платформенных приложений на C++, использующих для своей работы базы данных, не является чем-то непосильным, а также о том, что написание кросс-платформенных приложений может оказаться довольно увлекательным занятием.
Итак, эта статья о разработке приложений, использующих для своей работы базы данных SQLite.
Для работы нам понадобится:
Для начала, создадим новый проект (Win32 Project) в Visual Studio 2005 и назовем его SQLiteTest
В мастере создания проекта выберем тип проекта Windows Application и в дополнительных свойствах укажем Empty project
Затем распакуем библиотеку DatabaseLayer в папку, в которой находится файл SQLiteTest.sln
В Solution Explorer жмём правой кнопкой на названии Solution’а, выбираем пункт Add -> Existing Project
И в окне выбора файла проекта, выбираем проект databaselayer/build/databaselayer_databaselayer_sqlite.dsp (или .vcproj).
Теперь нам необходимо указать зависимости проектов. Наше приложение должно быть собрано после сборки библиотеки Databaselayer, поэтому в Solution Explorer жмем правой кнопкой на названии проекта SQLiteTest и выбираем пункт меню Project Dependencies…
В списке проектов ставим маркер на названии проекта databaselayer_sqlite и жмем OK
Далее, выбираем пункт меню Build -> Configuration Manager и указываем конфигурации сборки каждого проекта для каждой конфигурации сборки Solution’а. Я использую статическую раздельную Unicode-сборку wxWidgets, поэтому для Debug-конфигурации сборки Solution’а я выбираю конфигурацию Static Unicode Debug Multilib проекта databaselayer_sqlite и конфигурацию Debug проекта SQLiteTest. Такие же действия необходимо проделать и для Release-конфигурации сборки Solution’а, все вхождения слова Debug в названиях конфигураций на Release
После этого, распаковываем архив sqlite-source-x_y_z.zip в папку databaselayer/sqlite/include и архив sqlitedll-x_y_z.zip в папку databaselayer/sqlite/lib
В каталоге databaselayer/sqlite/lib должны появиться файлы sqlite3.dll и sqlite3.def
Всё это очень хорошо, но для использования динамической библиотеки в нашем проекте, неплохо было бы иметь .lib файл, которого у нас сейчас нет. Для того, чтобы он у нас был, создаем два batch-скрипта:
setupvars.bat
"C:/Program Files/Microsoft Visual Studio 8/VC/bin/vcvars32.bat"
export.bat
lib.exe /def:sqlite3.def /machine:x86 /out:sqlite3.lib
Запускаем командную строку, переходим в папку databaselayer/sqlite/lib и по очереди запускаем эти два batch-файла
setupvars
export
После выполнения этих нехитрых действий, у нас должны появиться два файла: sqlite3.exp и sqlite3.lib
Копируем файл sqlite3.dll в папку SQLiteTest/bin
Отлично, теперь создаем в нашем проекте SQLiteTest четыре новых файла:
Теперь открываем свойства проекта, переходим в раздел C/C++ и в настройках Additional Include Directories добавляем две новые записи:
Переходим в раздел Linker и в настройках Additional Library Directories добавляем две новые записи:
В разделе Linker -> Input в настройках Additional Dependencies добавляем записи:
Не забываем, что суффикс d в названиях библиотек wxWidgets указывает на то, что используется отладочная версия библиотеки. Release-версии библиотек не имеют в названии этого суффикса.
Далее, в разделе Linker -> General для всех конфигураций указываем параметр Output File равным ../bin/$(ProjectName).exe и в разделе Debugging параметр Working Directory равным ../bin. Это позволит генерировать исполняемый файл в отдельную папку.
Итак, предварительная настройка завершена, можно приступать к написанию кода.
SQLiteTestMainFrame.h
#ifndef _SQLITE_TEST_MAINFRAME_H
#define _SQLITE_TEST_MAINFRAME_H
#include <wx/wx.h>
class SQLiteTestMainFrame : public wxFrame
{
void CreateControls();
public:
SQLiteTestMainFrame();
bool Create(wxWindow * parent, wxWindowID id, const wxString & title);
DECLARE_EVENT_TABLE()
void OnExit(wxCommandEvent & event);
};
#endif
SQLiteTestMainFrame.cpp
#include "SQLiteTestMainFrame.h"
#include "SQLiteTestApp.h"
BEGIN_EVENT_TABLE(SQLiteTestMainFrame, wxFrame)
EVT_MENU(wxID_EXIT, SQLiteTestMainFrame::OnExit)
END_EVENT_TABLE()
SQLiteTestMainFrame::SQLiteTestMainFrame()
{
Create(NULL, wxID_ANY, _("SQLite Addressbook"));
}
bool SQLiteTestMainFrame::Create(wxWindow * parent, wxWindowID id, const wxString & title)
{
bool res = wxFrame::Create(parent, id, title, wxDefaultPosition, wxSize(700, 500));
if(res)
{
CreateControls();
}
return res;
}
void SQLiteTestMainFrame::CreateControls()
{
wxMenuBar * menuBar = new wxMenuBar;
SetMenuBar(menuBar);
wxMenu * fileMenu = new wxMenu;
fileMenu->Append(wxID_EXIT, _("ExittAlt+F4"));
menuBar->Append(fileMenu, _("File"));
CreateStatusBar(2);
Centre();
}
void SQLiteTestMainFrame::OnExit(wxCommandEvent & event)
{
wxUnusedVar(event);
Close();
}
SQLiteTestApp.h
#ifndef _SQLITE_TEST_APP_H
#define _SQLITE_TEST_APP_H
#include <wx/wx.h>
#include <databaselayer.h>
#include <sqliteDatabaseLayer.h>
class SQLiteTestApp : public wxApp
{
DatabaseLayer * m_Database;
public:
virtual bool OnInit();
virtual int OnExit();
bool ConnectToDatabase();
DatabaseLayer * GetDatabase();
};
DECLARE_APP(SQLiteTestApp)
#endif
SQLiteTestApp.cpp
#include <wx/image.h>
#include <databaseLayerException.h>
#include "SQLiteTestApp.h"
#include "SQLiteTestMainFrame.h"
IMPLEMENT_APP(SQLiteTestApp)
bool SQLiteTestApp::OnInit()
{
if(!ConnectToDatabase())
{
wxFAIL_MSG(_("Error connecting to database!"));
return false;
}
wxImage::AddHandler(new wxPNGHandler);
wxImage::AddHandler(new wxJPEGHandler);
SQLiteTestMainFrame * frame = new SQLiteTestMainFrame;
SetTopWindow(frame);
frame->Show();
return true;
}
int SQLiteTestApp::OnExit()
{
if(m_Database)
{
if(m_Database->IsOpen())
{
m_Database->Close();
}
wxDELETE(m_Database);
}
return wxApp::OnExit();
}
bool SQLiteTestApp::ConnectToDatabase()
{
m_Database = new SqliteDatabaseLayer();
wxString db_filename(wxT("addressbook.db"));
PreparedStatement * pStatement(NULL);
bool bCreate = !wxFileExists(db_filename);
if(bCreate)
{
wxMessageBox(_("Database does not exist... recreating."));
}
try
{
m_Database->Open(db_filename);
// Try to recreate tables
try
{
m_Database->RunQuery(wxT("CREATE TABLE groups(id integer primary key,
name varchar(128) not null,
description varchar(512));"));
}
catch(DatabaseLayerException & e) {wxUnusedVar(e);}
try
{
m_Database->RunQuery(wxT("CREATE TABLE persons(
id integer primary key,
groupid integer not null,
first_name varchar(64) not null,
last_name varchar(64) not null,
gender boolean not null,
address varchar(128) not null,
city varchar(64) not null,
country varchar(32) not null,
phone varchar(32),
email varchar(128),
website varchar(260));"));
}
catch(DatabaseLayerException & e) {wxUnusedVar(e);}
if(bCreate)
{
m_Database->RunQuery(
wxT("INSERT INTO groups(name, description) VALUES ('Friends', 'My friends')"));
pStatement = m_Database->PrepareStatement(
wxT("INSERT INTO persons(groupid, first_name,last_name,gender,address,city,country,phone) VALUES
(?,?,?,?,?,?,?,?)"));
if (pStatement)
{
pStatement->SetParamInt(1, 1);
pStatement->SetParamString(2, _("John"));
pStatement->SetParamString(3, _("Doe"));
pStatement->SetParamBool(4, 1);
pStatement->SetParamString(5, _("SomeStreet st., 123/45"));
pStatement->SetParamString(6, _("Some City"));
pStatement->SetParamString(7, _("Some Country"));
pStatement->SetParamString(8, _("+000-00-000-00-00"));
pStatement->RunQuery();
m_Database->CloseStatement(pStatement);
pStatement = NULL;
}
}
}
catch(DatabaseLayerException & e)
{
if(pStatement)
{
m_Database->CloseStatement(pStatement);
pStatement = NULL;
}
wxFAIL_MSG(e.GetErrorMessage());
return false;
}
return true;
}
DatabaseLayer * SQLiteTestApp::GetDatabase()
{
return m_Database;
}
Итак, что же мы сделали: мы создали класс приложения SQLiteTestApp, содержащий указатель на объект класса DatabaseLayer, который и будет обеспечивать связь с нашей базой данных. При запуске приложения проверяется наличие файла addressbook.db и, в случае если файл не найден, он создается. Вместе с базой данных создаются две таблицы: groups и persons и заполняются тестовыми данными.
Главная форма приложения содержит строку меню и строку статуса и, пока, ничего не делает.
После успешной сборки приложения и его запуска, в папке bin должен появиться файл базы данных addressbook.db
Отлично, теперь можно приступать к работе с базой данных.
Введение Уже долгое время не пишу статьи о разработке, хотя сам процесс написания мне очень…
I can see that there is still a lot of topics at wxWidgets forums related…
I've just published the source code of wxToolBox component and a couple of sample apps at…
Microsoft released their Kinect SDK several days ago. So, for those wxWidgets developers who are…
JSON (JavaScript Object Notation) is a lightweight data-interchange format. It is easy for humans to…
Вдохновленнный читаемой нынче книгой My Job Went to India: 52 Ways to Save Your Job…
View Comments