Сейчас использование баз данных, в то числе и удаленных стало обычной и повседневной практикой. Очень часто используется и СУБД MySQL – свободной распространяемая система управления базами данных. В основном она используется для малых и средних предприятий, где успешно решает многие задачи. Ее бесплатность, доступность, стабильность в работе и прочие характеристики позволяет говорить об это СУБД как о массовой альтернативе таких баз как InterBase или SyBase. Последние версии этой программы, существенно расширяющие ее возможности предлагают решение многих проблем, с которым сталкиваются как администратор баз данных, так и обычный пользователь.
Однако, существуют так же и проблемы при работе с Windows, как обязательное наличие драйверов ODBC для MySQL, если СУБД работает в этой среде. Стандартный клиент для MySQL не является удобным в настоящее время, так как является консольной программой. Опять же, требуется как минимум наличие установленной копии программы MySQL сервер на компьютере пользователя. Просмотр данных и простое редактирование также в стандартном клиенте не отвечает современным требованиям к интерфейсу. Решение целого ряда повседневных задач, предполагает стандартизацию пользовательского интерфейса и создание удобного юзабилити.
Поэтому мы пришли к необходимости создания собственного клиентского приложения Целью данного проекта является создание программы, которая бы позволяла выполнять наиболее общие операции с СУБД MySQL в операционной системе Windows, и при это не требовала наличия и настройки ODBC драйвера. Обычно это не умеет делать средний пользователь, и следовательно здесь требуется помощь администратора, что создает дополнительные трудности и самое главное, потерю рабочего времени. Кроме того, эта программа должна уметь соединяться и работать с удаленным MySQL сервером. Сам проект на данном этапе не является окончательной версией программы, поэтому реализуется с наиболее общими возможностями.
Далее будет описано шаг за шагом процесс создания проекта и с примерами исходного кода.
В начале мы создаем шаблон проекта. Для этого мы в Visual Studio выбираем «MFC APPWizard» и вводим название проекта «Myslqlone» . Далее, «Шаге1» выбираем «Single Document». В «Шаге2» и в «Шаге3» не меняем ничего,
в «Шаге 4» отключаем «Printing and Print Preview» и переключаем радиобокс на «Internet Explorer Rebars”. В «Шаге 5» выбираем из 2 радиобоксов «Windows Explorer». На конец, в «Шаге 6» нажимаем кнопку «Finish». Выбранный нами тип проекта приложения наиболее полно отвечает решению поставленной задачи. В нем находятся изначально 2 удобных класса, «CleftView”, который
является потомком класса «CtreeCtrl» в нашем случае, «CmysqloneView», который в свою очередь наследует от «ClistView», что очень удобно и ускоряет процесс разработки проекта. Оба эти класса могут использовать возможности
контролов ClistCtrl и CtreeCTrl, от которых они порождены. Данные обстоятельства в последствии будут нами постоянно использоваться в этом проекте.Все дальнейшие действия разбиты на этапы и описываются здесь ниже.
1. Копируем 2 файла в папку проекта: «libmysql.dll» и «libmysql.lib» из папки MySQL Server 4.1/lib/. Затем подключаем к проекту файл «libmysql.lib». Нам потребуется этий файлы для обеспечения работы программы и доступа к MySQL API функциям. Мы будем использовать MySQL C API функции,
как наиболее стабильно работающие и обеспечивающие полный сервис.
2. Затем копируем все заголовочные файлы из директории MySQL Server 4.1/include/ все заголовочные файлы в директориюVC /include/ Visual Studio.
Это также необходимо для создания и компиляции проекта.
3. Подключаем в файл “mysql.h” к файлу «stdafx.h» :
#include "mysql.h"
4. Создаем переменную класса CImageList m_TreeImages в классе
«CleftView.cpp» Она будет использована для создания списка картинок, которые будут в свою очередь использованы в создаваемом объекте типа CtreeCtrl.
5. Создаем в файле ресурсов новый ресурс.
6. Создаем в классе «CleftView.cpp» новый метод void FillTree():
void CLeftView::FillTree()
{
CTreeCtrl & m_tree = GetTreeCtrl();
m_tree.DeleteAllItems();
m_tree.SetImageList(&m_TreeImages, TVSIL_NORMAL);
HTREEITEM hRoot;
CMysqloneDoc* pDoc = GetDocument();
for (int i = 0; i < pDoc->m_available_bases.GetSize(); i++)
{
hRoot = m_tree.InsertItem(pDoc->m_available_bases[i], 0, 1);
}
}
7. Создаем в методе класса «CleftView.cpp» :OnInitialUpdate()
объект класса CimageList:
m_TreeImages.Create(IDB_BITMAP1, 16, 1, RGB(255, 255, 255));
Это создает список пиктограмм для CtreeCtrl
8. Добавляем в этот же класс метод OnSelchanged(NMHDR* pNMHDR, LRESULT* pResult) для обработки события смены элементов списка.
9. Вставляемвэтотметодтакойкод:
void CLeftView::OnSelchanged(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
CTreeCtrl & m_tree = GetTreeCtrl();
CMysqloneDoc* pDoc = GetDocument();
if (!pDoc->connected) {return;}
pDoc->current_table = "";
HTREEITEM nodSelected = m_tree.GetSelectedItem();
if (nodSelected>=0) {
CString strSelected=m_tree.GetItemText(nodSelected);
GetDocument()->SetTitle(strSelected);
}
HTREEITEM parent;
parent = m_tree.GetParentItem (nodSelected);
if (parent) {
pDoc->current_table = m_tree.GetItemText (nodSelected);
pDoc->UpdateAllViews (this);
return;
}
HTREEITEM child;
while (child = m_tree.GetChildItem (nodSelected)) {
m_tree.DeleteItem (child);
}
CString base_name = m_tree.GetItemText (nodSelected);
pDoc->current_base = base_name;
MYSQL* mysql = &(((CMysqloneApp*)AfxGetApp())->mysql);
MYSQL_RES * my_res;
MYSQL_ROW row;
CString sql;
mysql_select_db (mysql, base_name.GetBuffer(125));
if (mysql_query (mysql, "SHOW TABLES")) {
AfxMessageBox ("Query SHOW databases failed");
return;
}
my_res = mysql_store_result(mysql);
while (row = mysql_fetch_row (my_res)) {
char buffer[255];
strcpy (buffer, row[0]);
m_tree.InsertItem (_T(buffer), nodSelected);
}
mysql_free_result (my_res);
*pResult = 0;
}
10. Добавляем новый ресурс – диалоговое окно. Туда вставляем 3 поля редактирования, одному из них в стилях проставляем стиль: «password» . Далее мы заходи в Class Wizard и создаем новый класс для данного диалога. Назовем его «CLoginDlg». Он будет наследоваться от класса CDialog. Далее к каждому из полей редактирования создаем переменные типа Cstring. Это будут переменные этого класса для ввода данных по соединению с MySQL сервером.
11. Затем мы создаем переменную типа MYSQL mysql для класса «CmysqloneApp.cpp», это класс приложения. Эта переменная будет использоваться нами далее везде в программе для доступа к функциям MySQL.
Затем создаем в этом же классе новый метод для соединения с сервером баз данных типа BOOL ConnectToDb(). Вот его код:
BOOL CMysqloneApp::ConnectToDb()
{
CLoginDlg dlg;
while (dlg.DoModal()== IDOK) {
if(!mysql_init(&mysql)){AfxMessageBox ("Can't make initialization to mysql server!");}
if(mysql_real_connect(&mysql,dlg.m_host, dlg.m_login,dlg.m_password,NULL,0,NULL,0)){
return TRUE;
}
}
return FALSE;
}
В этом методе вызывается диалоговое окно CloginDlg, чтобы считать введенные пользователем данные и выполнить соединение с MySQL сервером. Данные пользователя хранятся в специальном файле, с расширением «.lgn», который предоставляет администратор. Нижеприводитсякодметодаподключенияксерверубазданных:
void CLoginDlg::OnBnClickedLogin()
{
UpdateData();
char login[35];
char password[25];
char host[255];
FILE *file;
bool valid_login = false;
if( m_login =="")
{
AfxMessageBox("You must provide a username and password or click Cancel!");
return;
}
if( m_password =="")
{
AfxMessageBox("Invalid login entered");
return;
}
if( m_host =="")
{
AfxMessageBox("Enter host name, please");
return;
}
try {
file = fopen("database.lgn", "r");
while( !feof(file) )
{
fscanf(file, "%s", login);
if( strcmp((LPCTSTR)m_login, login) == 0 )
{
fscanf(file, "%s", password);
if( strcmp((LPCTSTR)m_password, password) == 0 )
{
valid_login = true;
}
else
valid_login = false;
}
}
if( valid_login == true )
OnOK();
else
{
AfxMessageBox("Invalid entry data entered! Please try again");
}
fclose(file);
}
catch(...)
{
AfxMessageBox("Could not validate entered information to connect with MySQL database");
}
UpdateData(FALSE);
}
12. Подключаемзаголовочныйфайлкласса «CloginDlg.cpp» – «LoginDlg.h» к
кфайлукласса «CMysqloneApp»-«mysqlone.cpp»
#include "LoginDlg.h"
13. Создаем еще один метод для этого же класса типа void ExecuteSQL(CString sql). Он будет использоваться для выполнения запросов к MySQL серверу.
Вот его код:
void CMysqloneApp::ExecuteSQL(CString sql)
{
mysql_query (&mysql, sql);
}
Он также будет использоваться повсеместно в работе программы.
14. Затем мы создаем новые переменные для класса «CmysqloneDoc.cpp»
CStringArray m_available_bases; //текстовой массив списка доступных .//баз.
CString current_base; //переменная строкового типа для имени текущей //базы
CString current_table; //строковая переменная для имени текущей таблицы
bool connected;// переменная булевого типа для состояния соединения с //MySQL сервером.
15. На конец, вставляем следующий код вызова метода ConnectToDb() в
«CMysqloneApp»-«mysqlone.cpp» в метод InitInstance():
SetRegistryKey(_T("MySQLOne- MySQL Database Browser"));
LoadStdProfileSettings(); // Load standard INI file options (including MRU)
//После этих строк.
if (!ConnectToDb()) {
AfxMessageBox ("Could not connect to base\nQuitting");
return FALSE;
}
Метод ConnectToDb() будет вызываться при запуске программы, а поскольку он булевого типа, то про возращении этим методом FALSE программа не будет работать.
Теперь добавим еще один метод, который будет выбирать базу данных для дальнейшего использования.
void CMysqloneApp::ChangeCurrentBase(CString newBaseName)
{
mysql_select_db (&mysql, newBaseName);
}
16. Далее мы переходим в класс «CleftView.cpp» и через Class Wizard добавляем туда метод OnUpdate. Это один из поддерживаемых представлением методов, который нам нужно переопределить таким образом:
void CLeftView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint)
{
CTreeCtrl & m_tree = GetTreeCtrl();
CMysqloneDoc* pDoc = GetDocument();
if (!pDoc->connected) {
m_tree.DeleteAllItems();
return;
}
FeelTree();
}
17. Затеммыпереходимсноваккласс «CmysqloneDoc.cpp» ипереопределяемметод OnNewDocument():
BOOL CMysqloneDoc::OnNewDocument()
{
if (!CDocument::OnNewDocument())
return FALSE;
current_table = "";
MYSQL* mysql = &(((CMysqloneApp*)AfxGetApp())->mysql);
MYSQL_RES * my_res;
MYSQL_ROW row;
if (mysql_query (mysql, "SHOW databases")) {
AfxMessageBox ("Query SHOW databases failed");
return TRUE;
}
my_res = mysql_store_result(mysql);
int num = mysql_num_rows (my_res);
m_available_bases.RemoveAll();
while (row = mysql_fetch_row (my_res)) {
m_available_bases.Add (row[0]);
}
mysql_free_result (my_res);
current_base = "";
return TRUE;
}
18. Теперь переходим в класс «CmysqloneView.cpp», где добавляем в метод этого класса OnInitialUpdate() следующий код для создания объекта типа ClistCTrl и задания его стилей отображения.
void CMysqloneView::OnInitialUpdate()
{
CListView::OnInitialUpdate();
CListCtrl &m_list = GetListCtrl();
m_list.ModifyStyle(NULL, LVS_REPORT);
m_list.SetExtendedStyle (LVS_EX_GRIDLINES );
}
19. Далеемыидемсновав Class Wizard итамдобавляемвкласс «CmysqloneView.cpp» метод OnUpdate ипомещаемтудатакойкод:
void CMysqloneView::OnUpdate(CView* /*pSender*/, LPARAM /*lHint*/, CObject* /*pHint*/)
{
CListCtrl &m_list = GetListCtrl();
CMysqloneDoc* pDoc = GetDocument();
if (!pDoc->connected) {
m_list.DeleteAllItems ();
while(m_list.DeleteColumn(0));
return;
}
if (pDoc->current_table == "") return;
m_list.DeleteAllItems();
while(m_list.DeleteColumn(0));
MYSQL* mysql = &(((CMysqloneApp*)AfxGetApp())->mysql);
MYSQL_RES * my_res;
MYSQL_ROW row;
CString sql;
sql="SHOW COLUMNS IN ";
sql += pDoc->current_table;
mysql_query (mysql, sql);
my_res = mysql_store_result (mysql);
int i = 0;
int counter = 0;
while (row = mysql_fetch_row (my_res)) {
m_list.InsertColumn (i, row[0], LVCFMT_LEFT, 100);
i++;
}
counter = i;
mysql_free_result (my_res);
sql = "SELECT * FROM ";
sql += pDoc->current_table;
mysql_query (mysql, sql);
my_res = mysql_store_result (mysql);
i = 0;
LVITEM item;
item.mask = LVIF_TEXT;
while (row = mysql_fetch_row (my_res)) {
item.iItem = i;
item.iSubItem = 0;
item.pszText = row[0];
m_list.InsertItem (&item);
for (int z = 1; z < counter; z++) {
item.iSubItem = z;
item.pszText = row[z];
m_list.SetItem (&item);
}
i++;
}
}
Этотметодбудетиспользоватьсядляотображениявправойчастиокнаструктурыданных, полученныхврезультатезапросекбазеданных.
Фактически, это и будет главное просмотровое окно программы, отображающие данные и структуру таблиц баз данных.
20. Теперь мы снова идем во вкладку «Resources» и добавляем новый ресурс – диалоговое окно. Это окно будет использоваться для создания новой базы данных. Мы вводим туда новое текстовое поле типа CEdit и СStatic, для создания текстового заголовка: «New Database Name». Создаем в Class Wizarde новый класс «CNewDatabaseDlg». К текстовому полю CEdit подключаем переменную типа CString - «m_newdatabase». Эта переменная для задания нового имени вновь создаваемой базы данных.
21. Переопределяем метод этого класса OnOK() для исполнения запроса к MySQL серверу по созданию новой базы.
void CNewDatabase::OnOK()
{
UpdateData(TRUE);
CString sql="CREATE DATABASE ";
sql +=m_newdatabase;
((CMysqloneApp*)AfxGetApp())->ExecuteSQL (sql);
CDialog::OnOK();
}
22. Подключаем заголовочный файл нового диалогового «CreateNewTableDlg.h» к классу «CleftView.срр» для последующей обработки командой меню.
23. Теперь переходим опять во вкладку «Resources» и добавляем новое диалоговое окно. На этот раз в нем будет окно для исполнения запросов к базе данных. Мы добавляем туда следующие контролы: ССombox – сюда мы будем вводить SQL запрос, CListBox - это будет форма для отображения списка доступных нам баз данных и CListCtrl - в нем будут отображаться результаты SQL запросов. Итак, мы создаем 2 переменных класса:
CListBox m_listbox и CListCtrl m_list.
24. Затем мы добавляем новый метод к этому классу диалога- void AddStr(). Этот метод будет получать строковую переменную, введенную в CComboBox . Далее код этого метода:
void CSqlQueryDlg::AddStr()
{
CComboBox *Box;
Box = (CComboBox *)(this->GetDlgItem(IDC_COMBO1));
Box->AddString(m_sql);
}
25. Теперь нам необходимо заполнить список базами данных, которыей находятся в данный момент на сервере MySQL. Для этого мы подключаем и переопределяем метод OnInitDialog(). В нем мы заполняем список CListBox, который буджет показываться при запуске этого окна.
BOOL CSqlQueryDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// TODO: Add extra initialization here
MYSQL* mysql = &(((CMysqloneApp*)AfxGetApp())->mysql);
MYSQL_RES * my_res;
MYSQL_ROW row;
CString data_sql="SHOW DATABASES";
((CMysqloneApp*)AfxGetApp())->ExecuteSQL (data_sql);
my_res = mysql_store_result(mysql);
while (row = mysql_fetch_row (my_res)) {
char buffer[255];
strcpy (buffer, row[0]);
m_listbox.AddString(_T(buffer));
}
mysql_free_result (my_res);
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
26. Затем, мы переопределяем метод OnOK() у этого класса, чтобы выполнить SQL запрос.
void CSqlQueryDlg::OnOK()
{
UpdateData();
MYSQL* mysql = &(((CMysqloneApp*)AfxGetApp())->mysql);
CString basename;
m_listbox.GetText (m_listbox.GetCurSel(), basename);
((CMysqloneApp*)AfxGetApp())->ChangeCurrentBase (basename);
((CMysqloneApp*)AfxGetApp())->ExecuteSQL (m_sql);
m_list.DeleteAllItems ();
while(m_list.DeleteColumn(0));
MYSQL_RES * my_res;
MYSQL_ROW row;
mysql_query (mysql, m_sql);
my_res = mysql_store_result (mysql);
int cols = mysql_num_fields (my_res);
int counter ;
for (counter = 0; counter < cols; counter++) {
m_list.InsertColumn (counter, "Data", LVCFMT_LEFT, 50);
}
counter = cols;
LVITEM item;
item.mask = LVIF_TEXT;
int i = 0;
while (row = mysql_fetch_row (my_res)) {
item.iItem = i;
item.iSubItem = 0;
item.pszText = row[0];
m_list.InsertItem (&item);
for (int z = 1; z < counter; z++) {
item.iSubItem = z;
item.pszText = row[z];
m_list.SetItem (&item);
}
i++;
}
mysql_free_result (my_res);
//CDialog::OnOK();
}
Заметим, что последняя строка кода закомментирована, чтобы OnOk() не закрывал это окно по завершению работы.
27. Теперь добавим новую кнопку в это диалоговое окно и переименуем ее
заголовок в «Clear» и затем создадим для нее обработчик. Этот метод будет
очищать переменную CListCtrl m_list после исполнения запроса к базе данных.
Код метода ниже по тексту.
void CSqlQueryDlg::OnClear()
{
m_list.DeleteAllItems ();
UpdateData(FALSE);
}
28. На конец, мы снова подключаем заголовочный файл данного класса диалогового окна «CListCtrl m_list.h» к классу «CleftView.срр» для последующей обработки командой меню.
29. Снова переходим во вкладку «Resources» и добавляем новое диалоговое окно. В этом случае это будет окно для удаления базе данных, которые доступны нам . Мы добавляем сюда 2 контрола: CStatic, в который вводим следующий текст: «Database Name» и CListBox m_listbox, в котором список баз данных будет отображаться. Затем мы добавляем и переопределяем метод класса OnInitDialog, в котором список баз будет заполняться.
BOOL CDeleteDatabaseDlg::OnInitDialog()
{
CDialog::OnInitDialog();
MYSQL* mysql = &(((CMysqloneApp*)AfxGetApp())->mysql);
MYSQL_RES * my_res;
MYSQL_ROW row;
CString data_sql="SHOW DATABASES";
((CMysqloneApp*)AfxGetApp())->ExecuteSQL (data_sql);
my_res = mysql_store_result(mysql);
while (row = mysql_fetch_row (my_res)) {
char buffer[255];
strcpy (buffer, row[0]);
m_listbox.AddString(_T(buffer));
}
mysql_free_result (my_res);
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
Строка запроса будет отображаться в MessageBox, чтобы видеть совершаемое действие.
30. Затем мы переопределяем метод класса OnOk() для исполнения
собственно запроса к базе данных. Вот его код:
void CDeleteDatabaseDlg::OnOK()
{
UpdateData(TRUE);
CString item;
int index=m_listbox.GetCurSel();
m_listbox.GetText(index,item);
CString sql="DROP DATABASE ";
sql +=item;
m_delete=sql;
AfxMessageBox(m_delete);
((CMysqloneApp*)AfxGetApp())->ExecuteSQL (sql);
CDialog::OnOK();
}
31. Опятьже, подключаем «DeleteDatabaseDlg.h» файлзаголовкакклассу «CLeftView.cpp» дляиспользованиявобработчикеменю.
32. Теперь мы идем опять во вкладку «Resources» и там находим в папке «Menu» ресурс меню проекта - «IDR_MAINFRAME». Мы удаляем все стандартные опции меню, за исключением «Exit» и создаем свои пункты меню и идентификаторы для них. Получаются такие команды меню и идентификаторы:
«Сreate New Table» (ID_NEW_DATABASE), «MySQL Query»( ID_MYSQL_QUERY), «Drop Database»( ID_DATA_DROPDATABASE) и
«See Last Insert/Alter SQL Query»( ID_DATA_SEELASTSQLQUERY). Эта опция меню будет описана позднее. Затем мы создаем для них обработчики в классе «CLeftView.cpp». Далее их полный код:
void CLeftView::OnNewDatabase()
{
CNewDatabase dlg;
if (dlg.DoModal() == IDOK )
{
CTreeCtrl & m_tree = GetTreeCtrl();
HTREEITEM hitem = m_tree.InsertItem(dlg.m_newdatabase, TVI_ROOT);
m_tree.SelectItem(hitem);
}
}
void CLeftView::OnDataDropdatabase()
{
CDeleteDatabaseDlg dlg;
if (dlg.DoModal() == IDOK )
{
CTreeCtrl & m_tree = GetTreeCtrl();
HTREEITEM hitem = m_tree.GetSelectedItem();
CString selected=m_tree.GetItemText(hitem);
m_tree.DeleteItem(hitem);
}
}
void CLeftView::OnNewTable()
{
CCreateNewTableDlg dlg;
if (dlg.DoModal() == IDOK )
{
CTreeCtrl & m_tree = GetTreeCtrl();
HTREEITEM hitem = m_tree.GetSelectedItem();
HTREEITEM childitem=m_tree.GetChildItem(hitem);
childitem = m_tree.InsertItem(dlg.m_newtable, TVI_FIRST);
m_tree.SelectItem(childitem);
}
}
void CLeftView::OnMysqlQuery()
{
CSqlQueryDlg dlg;
if (dlg.DoModal() == IDOK ){
dlg.OnOK();
}
}
void CLeftView::OnDataSeelastsqlquery()
{
MYSQL* mysql = &(((CMysqloneApp*)AfxGetApp())->mysql);
const char* last_query;
CString noresult;
CString temp;
last_query=mysql_info(mysql);
temp=(CString)last_query;
if (temp=="NULL") {
noresult="No any SQL request was done till now";
AfxMessageBox(noresult);
}
else {
AfxMessageBox(temp);
}
}
На последнем методе остановимся подробнее. Остальные обработчики команд меню используют описанные выше диалоговые классы. А этот метод служит для получения информации о последнем запросе типа INSERT/ALTER к базе данных. Такая информация полезна при коллективной работе с сервером баз данных, так как наиболее быстро позволяет видеть последние изменения данных без необходимости исполнения запросов к таблице.
33. Теперь перейдем во вкладку «Resources» и выбираем «IDD_ABOUTBOX». Там мы добавляем 4 новых контрола типа Cstatic и распологаем их горизонтально, один над другим. Далее мы вводим в качестве заголовков «MySQL Host Name» и «MySQL Protocol Version» в оба верхних контрола. Первый нижний контрол мы переименовываем в
«IDC_INFO» и удаляем текст из него. Затем мы подключаем к нему переменную типа CString mysql_info. Во втором нижнем котроле мы убираем также весь текст в заголовке и подключаем к нему переменную типа int mysql_version. Обе эти переменные буду использоваться для
отображения информации в окне диалога «About».
34. Затем мы переопределяем метод OnAppAbout() этого класса для вызова 2 методов MySQL С API, которые в свою очередь выдадут ифнормацию о типе MySQL cсервера и его версии.
void CMysqloneApp::OnAppAbout()
{
CAboutDlg aboutDlg;
MYSQL* mysql = &(((CMysqloneApp*)AfxGetApp())->mysql);
const char* host_info="";
int ver;
host_info=mysql_get_host_info(mysql);
ver=mysql_get_proto_info(mysql);
aboutDlg.mysql_info=(CString)host_info;
aboutDlg.mysql_version=ver;
aboutDlg.DoModal();
}
35. В меню “Help” добавляем новый пункт – “MySQL Info”
Здесь будет появляется модальное диалоговое окно, в котором
будет отображаться статус MySQL сервера. Для этого мы добавим туда еще в ресурсах новое диалоговое окно и назовем его «IDD_MYSQLINFODLG». Туда введем 5 новых элементов управления типа CStatic. Одно поле назовем «MySQL Server Status», а другие поля будут связаны с переменными типа CString и в последствии будут использоваться для отображения данных.
Далее переопределяем метод OnInitDialog() этого диалогового окна и вводим туда такой код:
BOOL CMySQLInfoDlg::OnInitDialog()
{
CDialog::OnInitDialog();
const char* result="";
MYSQL* mysql = &(((CMysqloneApp*)AfxGetApp())->mysql);
result=mysql_stat(mysql);
CString temp=(CString)result;
m_mysqlinfo=temp;
UpdateData(FALSE);
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
После добавляем обработчик в меню класса CMainFraime:
void CMainFrame::OnHelpMysqlinfo()
{
CMySQLInfoDlg dlg;
if (dlg.DoModal() == IDOK )
{
dlg.OnBnClickedExit();
}
}
36. Далее мы переходим снова редактор ресурсов, находим главное меню окна и добавляем туда новый пункт «Send E-Mail»
Затем подключаем его обработчик к классу CMysqloneDoc, редактируя его карту сообщений таким образом:
BEGIN_MESSAGE_MAP(CMysqloneDoc, CDocument)
//{{AFX_MSG_MAP(CMysqloneDoc)
// NOTE - the ClassWizard will add and remove mapping macros here.
// DO NOT EDIT what you see in these blocks of generated code!
//}}AFX_MSG_MAP
ON_COMMAND(ID_FILE_SEND_MAIL, OnFileSendMail)
ON_UPDATE_COMMAND_UI(ID_FILE_SEND_MAIL, OnUpdateFileSendMail)
END_MESSAGE_MAP()
Это позволит нам слать сообщения по электронной почте прямо из программы.
37. Снова возвращаемся в редактор ресурсов, к главному меню и вставляем туда такой пункт «Data Optimization». Обработчик для него ставим в классе CLeftView.
void CLeftView::OnDataDataoptimization()
{
CTreeCtrl & m_tree = GetTreeCtrl();
HTREEITEM hitem = m_tree.GetSelectedItem();
HTREEITEM childitem=m_tree.GetChildItem(hitem);
MYSQL* mysql = &(((CMysqloneApp*)AfxGetApp())->mysql);
CMysqloneDoc* pDoc = GetDocument();
CString base_name=m_tree.GetItemText(hitem);
CString strSelected=m_tree.GetItemText(childitem);
pDoc->current_base=base_name;
CString sql="OPTIMIZE TABLE ";
mysql_select_db(mysql,base_name.GetBuffer(255));
sql+=strSelected;
((CMysqloneApp*)AfxGetApp())->ExecuteSQL (sql);
pDoc->UpdateAllViews (NULL);
}
Здесь мы сможем легко производить оптимизацию выбранной таблицы базы.
38. . Снова возвращаемся в редактор ресурсов, к главному меню и вставляем туда такой пункт «Empty All Data». Обработчик для него ставим в классе также CLeftView.
void CLeftView::OnDataCreatenewtable()
{
CCreateNewTableDlg dlg;
if (dlg.DoModal() == IDOK )
{
CTreeCtrl & m_tree = GetTreeCtrl();
HTREEITEM hitem = m_tree.GetSelectedItem();
HTREEITEM childitem=m_tree.GetChildItem(hitem);
// childitem = m_tree.InsertItem(dlg.m_newtable, TVI_FIRST);
m_tree.SelectItem(childitem);
}
}
void CLeftView::OnDataEmptyalldata()
{
MYSQL* mysql = &(((CMysqloneApp*)AfxGetApp())->mysql);
CTreeCtrl & m_tree = GetTreeCtrl();
CString sql="DELETE FROM ";
HTREEITEM nodSelected = m_tree.GetSelectedItem();
if (nodSelected>=0) {
CString strSelected=m_tree.GetItemText(nodSelected);
sql +=strSelected;
AfxMessageBox("Are you sure to wish to delete ALL data from "+ strSelected,MB_OKCANCEL|MB_ICONQUESTION );
((CMysqloneApp*)AfxGetApp())->ExecuteSQL (sql);
m_tree.DeleteItem(nodSelected);
}
}
Мы очищаем таблицу от данных при помощи этой команды меню.
На конец, запускаем программу и послу успешной компиляции мы получим диалоговое окно для ввода информации. Затем мы увидим список
баз в виде дерева и таблицы, которые можно просмотреть структуру и сами данные в таблицах баз данных. С помощью
команд меню можно создать и удалить базу, выполнить любой SQL запрос к любой таблице (при наличии у пользователя необходимых полномочий ), послать сообщение электронной почты, посмотреть последние обновления.
Таким образом, мы получили программу, с помощью которой можно выполнять базовый набор операций сервером MySQL и при этом не требуется поддержка и настройка ODBC драйвера. В дальнейшем проект может быть значительно расширен и улучшен.
Исходный код программы.
#include "afxwin.h"
#if !defined(AFX_DELETEDATABASEDLG_H__16ACDEC0_DE9D_11D9_A8EF_929CCA0FC15A__INCLUDED_)
#define AFX_DELETEDATABASEDLG_H__16ACDEC0_DE9D_11D9_A8EF_929CCA0FC15A__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// DeleteDatabaseDlg.h : header file
//
/////////////////////////////////////////////////////////////////////////////
// CDeleteDatabaseDlg dialog
class CDeleteDatabaseDlg : public CDialog
{
// Construction
public:
CDeleteDatabaseDlg(CWnd* pParent = NULL); // standard constructor
// Dialog Data
//{{AFX_DATA(CDeleteDatabaseDlg)
enum { IDD = IDD_DIALOG4 };
//}}AFX_DATA
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CDeleteDatabaseDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
// Generated message map functions
//{{AFX_MSG(CDeleteDatabaseDlg)
virtual void OnOK();
virtual void OnCancel();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
public:
virtual BOOL OnInitDialog();
CListBox m_listbox;
CString m_delete;
};
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_DELETEDATABASEDLG_H__16ACDEC0_DE9D_11D9_A8EF_929CCA0FC15A__INCLUDED_)
// DeleteDatabaseDlg.cpp : implementation file
//
#include "stdafx.h"
#include "mysqlone.h"
#include "DeleteDatabaseDlg.h"
#include ".\deletedatabasedlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CDeleteDatabaseDlg dialog
CDeleteDatabaseDlg::CDeleteDatabaseDlg(CWnd* pParent /*=NULL*/)
: CDialog(CDeleteDatabaseDlg::IDD, pParent)
, m_delete(_T(""))
{
//{{AFX_DATA_INIT(CDeleteDatabaseDlg)
m_delete = _T("");
//}}AFX_DATA_INIT
}
void CDeleteDatabaseDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CDeleteDatabaseDlg)
//}}AFX_DATA_MAP
DDX_Control(pDX, IDC_LIST1, m_listbox);
}
BEGIN_MESSAGE_MAP(CDeleteDatabaseDlg, CDialog)
//{{AFX_MSG_MAP(CDeleteDatabaseDlg)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CDeleteDatabaseDlg message handlers
BOOL CDeleteDatabaseDlg::OnInitDialog()
{
CDialog::OnInitDialog();
MYSQL* mysql = &(((CMysqloneApp*)AfxGetApp())->mysql);
MYSQL_RES * my_res;
MYSQL_ROW row;
CString data_sql="SHOW DATABASES";
((CMysqloneApp*)AfxGetApp())->ExecuteSQL (data_sql);
my_res = mysql_store_result(mysql);
while (row = mysql_fetch_row (my_res)) {
char buffer[255];
strcpy (buffer, row[0]);
m_listbox.AddString(_T(buffer));
}
mysql_free_result (my_res);
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
void CDeleteDatabaseDlg::OnOK()
{
UpdateData(TRUE);
CString item;
int index=m_listbox.GetCurSel();
m_listbox.GetText(index,item);
CString sql="DROP DATABASE ";
sql +=item;
m_delete=sql;
AfxMessageBox(m_delete,MB_ICONWARNING);
((CMysqloneApp*)AfxGetApp())->ExecuteSQL (sql);
CDialog::OnOK();
}
void CDeleteDatabaseDlg::OnCancel()
{
// TODO: Add extra cleanup here
CDialog::OnCancel();
}
// LeftView.h : interface of the CLeftView class
//
/////////////////////////////////////////////////////////////////////////////
#if !defined(AFX_LEFTVIEW_H__58E6318E_DD0B_11D9_A8EF_BCC8AEF81D60__INCLUDED_)
#define AFX_LEFTVIEW_H__58E6318E_DD0B_11D9_A8EF_BCC8AEF81D60__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
class CMysqloneDoc;
class CLeftView : public CTreeView
{
protected: // create from serialization only
CLeftView();
DECLARE_DYNCREATE(CLeftView)
// Attributes
public:
CMysqloneDoc* GetDocument();
// Operations
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CLeftView)
public:
virtual void OnDraw(CDC* pDC); // overridden to draw this view
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
protected:
virtual void OnInitialUpdate(); // called first time after construct
virtual void OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint);
//}}AFX_VIRTUAL
// Implementation
public:
CImageList m_TreeImages;
void FillTree();
virtual ~CLeftView();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
protected:
// Generated message map functions
protected:
//{{AFX_MSG(CLeftView)
afx_msg void OnSelchanged(NMHDR* pNMHDR, LRESULT* pResult);
afx_msg void OnDataDropdatabase();
afx_msg void OnNewTable();
afx_msg void OnMysqlQuery();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnNewDatabase();
afx_msg void OnDataSeelastsqlquery();
afx_msg void OnDataCreatenewtable();
afx_msg void OnDataEmptyalldata();
afx_msg void OnDataDataoptimization();
afx_msg void OnDataSearchdatain();
};
#ifndef _DEBUG // debug version in LeftView.cpp
inline CMysqloneDoc* CLeftView::GetDocument()
{ return (CMysqloneDoc*)m_pDocument; }
#endif
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_LEFTVIEW_H__58E6318E_DD0B_11D9_A8EF_BCC8AEF81D60__INCLUDED_)
// LeftView.cpp : implementation of the CLeftView class
//
#include "stdafx.h"
#include "mysqlone.h"
#include "NewDatabase.h"
#include "CreateNewTableDlg.h"
#include "DeleteDatabaseDlg.h"
#include "SqlQueryDlg.h"
#include "mysqloneDoc.h"
#include "LeftView.h"
#include "mysqloneView.h"
#include ".\leftview.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CLeftView
IMPLEMENT_DYNCREATE(CLeftView, CTreeView)
BEGIN_MESSAGE_MAP(CLeftView, CTreeView)
//{{AFX_MSG_MAP(CLeftView)
ON_NOTIFY_REFLECT(TVN_SELCHANGED, OnSelchanged)
ON_COMMAND(ID_DATA_DROPDATABASE, OnDataDropdatabase)
ON_COMMAND(ID_NEW_TABLE, OnNewTable)
ON_COMMAND(ID_MYSQL_QUERY, OnMysqlQuery)
//}}AFX_MSG_MAP
ON_COMMAND(ID_NEW_DATABASE, OnNewDatabase)
ON_COMMAND(ID_DATA_SEELASTSQLQUERY, OnDataSeelastsqlquery)
ON_COMMAND(ID_DATA_CREATENEWTABLE, OnDataCreatenewtable)
ON_COMMAND(ID_DATA_EMPTYALLDATA, OnDataEmptyalldata)
ON_COMMAND(ID_DATA_DATAOPTIMIZATION, OnDataDataoptimization)
ON_COMMAND(ID_DATA_SEARCHDATAIN, OnDataSearchdatain)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CLeftView construction/destruction
CLeftView::CLeftView()
{
// TODO: add construction code here
}
CLeftView::~CLeftView()
{
}
BOOL CLeftView::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
return CTreeView::PreCreateWindow(cs);
}
/////////////////////////////////////////////////////////////////////////////
// CLeftView drawing
void CLeftView::OnDraw(CDC* pDC)
{
CMysqloneDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
}
void CLeftView::OnInitialUpdate()
{
CTreeView::OnInitialUpdate();
//FillTree();
m_TreeImages.Create(IDB_BITMAP1, 16, 1, RGB(255, 255, 255));
}
/////////////////////////////////////////////////////////////////////////////
// CLeftView diagnostics
#ifdef _DEBUG
void CLeftView::AssertValid() const
{
CTreeView::AssertValid();
}
void CLeftView::Dump(CDumpContext& dc) const
{
CTreeView::Dump(dc);
}
CMysqloneDoc* CLeftView::GetDocument() // non-debug version is inline
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CMysqloneDoc)));
return (CMysqloneDoc*)m_pDocument;
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CLeftView message handlers
void CLeftView::FillTree()
{
CTreeCtrl & m_tree = GetTreeCtrl();
m_tree.DeleteAllItems();
m_tree.SetImageList(&m_TreeImages, TVSIL_NORMAL);
HTREEITEM hRoot;
CMysqloneDoc* pDoc = GetDocument();
for (int i = 0; i < pDoc->m_available_bases.GetSize(); i++)
{
hRoot = m_tree.InsertItem(pDoc->m_available_bases[i], 0, 1);
}
}
void CLeftView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint)
{
// TODO: Add your specialized code here and/or call the base class
CTreeCtrl & m_tree = GetTreeCtrl();
CMysqloneDoc* pDoc = GetDocument();
if (!pDoc->connected) {
m_tree.DeleteAllItems();
return;
}
FillTree();
}
void CLeftView::OnSelchanged(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
CTreeCtrl & m_tree = GetTreeCtrl();
CMysqloneDoc* pDoc = GetDocument();
if (!pDoc->connected) {return;}
pDoc->current_table = "";
HTREEITEM nodSelected = m_tree.GetSelectedItem();
if (nodSelected>=0) {
CString strSelected=m_tree.GetItemText(nodSelected);
GetDocument()->SetTitle(strSelected);
}
HTREEITEM parent;
parent = m_tree.GetParentItem (nodSelected);
if (parent) {
pDoc->current_table = m_tree.GetItemText (nodSelected);
pDoc->UpdateAllViews (this);
return;
}
HTREEITEM child;
while (child = m_tree.GetChildItem (nodSelected)) {
m_tree.DeleteItem (child);
}
CString base_name = m_tree.GetItemText (nodSelected);
pDoc->current_base = base_name;
MYSQL* mysql = &(((CMysqloneApp*)AfxGetApp())->mysql);
MYSQL_RES * my_res;
MYSQL_ROW row;
CString sql;
mysql_select_db (mysql, base_name.GetBuffer(255));
if (mysql_query (mysql, "SHOW TABLES")) {
AfxMessageBox ("Query SHOW databases failed");
return;
}
my_res = mysql_store_result(mysql);
while (row = mysql_fetch_row (my_res)) {
char buffer[255];
strcpy (buffer, row[0]);
m_tree.InsertItem (_T(buffer), nodSelected);
}
mysql_free_result (my_res);
*pResult = 0;
}
void CLeftView::OnNewDatabase()
{
CNewDatabase dlg;
if (dlg.DoModal() == IDOK )
{
CTreeCtrl & m_tree = GetTreeCtrl();
HTREEITEM hitem = m_tree.InsertItem(dlg.m_newdatabase, TVI_ROOT);
m_tree.SelectItem(hitem);
}
}
void CLeftView::OnDataDropdatabase()
{
CDeleteDatabaseDlg dlg;
if (dlg.DoModal() == IDOK )
{
CTreeCtrl & m_tree = GetTreeCtrl();
HTREEITEM hitem = m_tree.GetSelectedItem();
CString selected=m_tree.GetItemText(hitem);
m_tree.DeleteItem(hitem);
}
}
void CLeftView::OnNewTable()
{
CCreateNewTableDlg dlg;
if (dlg.DoModal() == IDOK )
{
CTreeCtrl & m_tree = GetTreeCtrl();
HTREEITEM hitem = m_tree.GetSelectedItem();
HTREEITEM childitem=m_tree.GetChildItem(hitem);
// childitem = m_tree.InsertItem(dlg.m_newtable, TVI_FIRST);
m_tree.SelectItem(childitem);
}
}
void CLeftView::OnMysqlQuery()
{
CSqlQueryDlg dlg;
if (dlg.DoModal() == IDOK ){
dlg.OnOK();
}
}
void CLeftView::OnDataSeelastsqlquery()
{
MYSQL* mysql = &(((CMysqloneApp*)AfxGetApp())->mysql);
const char* last_query;
CString noresult;
CString temp;
last_query=mysql_info(mysql);
temp=(CString)last_query;
if (temp=="NULL") {
noresult="No any SQL request was done till now";
AfxMessageBox(noresult,MB_ICONINFORMATION);
}
else {
AfxMessageBox(temp,MB_ICONINFORMATION);
}
}
void CLeftView::OnDataCreatenewtable()
{
CCreateNewTableDlg dlg;
if (dlg.DoModal() == IDOK )
{
CTreeCtrl & m_tree = GetTreeCtrl();
HTREEITEM hitem = m_tree.GetSelectedItem();
HTREEITEM childitem=m_tree.GetChildItem(hitem);
// childitem = m_tree.InsertItem(dlg.m_newtable, TVI_FIRST);
m_tree.SelectItem(childitem);
}
}
void CLeftView::OnDataEmptyalldata()
{
MYSQL* mysql = &(((CMysqloneApp*)AfxGetApp())->mysql);
CTreeCtrl & m_tree = GetTreeCtrl();
CString sql="DELETE FROM ";
HTREEITEM nodSelected = m_tree.GetSelectedItem();
if (nodSelected>=0) {
CString strSelected=m_tree.GetItemText(nodSelected);
sql +=strSelected;
AfxMessageBox("Are you sure to wish to delete ALL data from "+ strSelected,MB_OKCANCEL|MB_ICONQUESTION );
((CMysqloneApp*)AfxGetApp())->ExecuteSQL (sql);
m_tree.DeleteItem(nodSelected);
}
}
void CLeftView::OnDataDataoptimization()
{
CTreeCtrl & m_tree = GetTreeCtrl();
HTREEITEM hitem = m_tree.GetSelectedItem();
HTREEITEM childitem=m_tree.GetChildItem(hitem);
MYSQL* mysql = &(((CMysqloneApp*)AfxGetApp())->mysql);
CMysqloneDoc* pDoc = GetDocument();
CString base_name=m_tree.GetItemText(hitem);
CString strSelected=m_tree.GetItemText(childitem);
pDoc->current_base=base_name;
CString sql="OPTIMIZE TABLE ";
mysql_select_db(mysql,base_name.GetBuffer(255));
sql+=strSelected;
((CMysqloneApp*)AfxGetApp())->ExecuteSQL (sql);
pDoc->UpdateAllViews (NULL);
}
void CLeftView::OnDataSearchdatain()
{
CMysqloneDoc* pDoc = GetDocument();
pDoc->current_table = "";
MYSQL* mysql = &(((CMysqloneApp*)AfxGetApp())->mysql);
MYSQL_RES * my_res;
MYSQL_ROW row;
CTreeCtrl & m_tree = GetTreeCtrl();
HTREEITEM hitem = m_tree.GetSelectedItem();
HTREEITEM childitem=m_tree.GetChildItem(hitem);
CString base_name=m_tree.GetItemText(hitem);
CString strSelected=m_tree.GetItemText(childitem);
pDoc->current_base=base_name;
CString sql="SELECT * FROM ";
sql+=base_name;
mysql_select_db (mysql, base_name.GetBuffer(255));
if (mysql_query (mysql, sql)) {
CString error=mysql_error(mysql);
AfxMessageBox (error);
return;
}
my_res = mysql_store_result(mysql);
}
#if !defined(AFX_LOGINDLG_H__58E63196_DD0B_11D9_A8EF_BCC8AEF81D60__INCLUDED_)
#define AFX_LOGINDLG_H__58E63196_DD0B_11D9_A8EF_BCC8AEF81D60__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// LoginDlg.h : header file
//
/////////////////////////////////////////////////////////////////////////////
// CLoginDlg dialog
class CLoginDlg : public CDialog
{
// Construction
public:
CLoginDlg(CWnd* pParent = NULL); // standard constructor
// Dialog Data
//{{AFX_DATA(CLoginDlg)
enum { IDD = IDD_LOGINDLG };
CString m_login;
CString m_password;
CString m_host;
//}}AFX_DATA
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CLoginDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
// Generated message map functions
//{{AFX_MSG(CLoginDlg)
// NOTE: the ClassWizard will add member functions here
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnBnClickedLogin();
};
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_LOGINDLG_H__58E63196_DD0B_11D9_A8EF_BCC8AEF81D60__INCLUDED_)
// LoginDlg.cpp : implementation file
//
#include "stdafx.h"
#include "mysqlone.h"
#include "LoginDlg.h"
#include ".\logindlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CLoginDlg dialog
CLoginDlg::CLoginDlg(CWnd* pParent /*=NULL*/)
: CDialog(CLoginDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CLoginDlg)
m_login = _T("");
m_password = _T("");
m_host = _T("");
//}}AFX_DATA_INIT
}
void CLoginDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CLoginDlg)
DDX_Text(pDX, IDC_EDIT1, m_login);
DDX_Text(pDX, IDC_EDIT2, m_password);
DDX_Text(pDX, IDC_EDIT3, m_host);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CLoginDlg, CDialog)
//{{AFX_MSG_MAP(CLoginDlg)
// NOTE: the ClassWizard will add message map macros here
//}}AFX_MSG_MAP
ON_BN_CLICKED(IDC_LOGIN, OnBnClickedLogin)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CLoginDlg message handlers
void CLoginDlg::OnBnClickedLogin()
{
UpdateData();
char login[35];
char password[25];
char host[255];
FILE *file;
bool valid_login = false;
if( m_login =="")
{
AfxMessageBox("You must provide a username and password or click Cancel!");
return;
}
if( m_password =="")
{
AfxMessageBox("Invalid login entered");
return;
}
if( m_host =="")
{
AfxMessageBox("Enter host name, please");
return;
}
try {
file = fopen("database.lgn", "r");
while( !feof(file) )
{
fscanf(file, "%s", login);
if( strcmp((LPCTSTR)m_login, login) == 0 )
{
fscanf(file, "%s", password);
if( strcmp((LPCTSTR)m_password, password) == 0 )
{
valid_login = true;
}
else
valid_login = false;
}
}
if( valid_login == true )
OnOK();
else
{
AfxMessageBox("Invalid entry data entered! Please try again");
}
fclose(file);
}
catch(...)
{
AfxMessageBox("Could not validate entered information to connect with MySQL database");
}
UpdateData(FALSE);
}
// MainFrm.h : interface of the CMainFrame class
//
/////////////////////////////////////////////////////////////////////////////
#if !defined(AFX_MAINFRM_H__58E63188_DD0B_11D9_A8EF_BCC8AEF81D60__INCLUDED_)
#define AFX_MAINFRM_H__58E63188_DD0B_11D9_A8EF_BCC8AEF81D60__INCLUDED_
#if _MSC_VER > 1000
#pragma once
class CLeftView;
#endif // _MSC_VER > 1000
class CMysqloneView;
class CMainFrame : public CFrameWnd
{
protected: // create from serialization only
CMainFrame();
DECLARE_DYNCREATE(CMainFrame)
// Attributes
protected:
CSplitterWnd m_wndSplitter;
public:
// Operations
public:
CStatusBar m_wndStatusBar;
CToolBar m_wndToolBar;
CReBar m_rebar;
CDialogBar m_wndDlgBar;
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CMainFrame)
public:
virtual BOOL OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext);
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
//}}AFX_VIRTUAL
// Implementation
public:
virtual ~CMainFrame();
CMysqloneView* GetRightPane();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
protected: // control bar embedded members
// Generated message map functions
protected:
//{{AFX_MSG(CMainFrame)
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
//}}AFX_MSG
afx_msg void OnUpdateViewStyles(CCmdUI* pCmdUI);
afx_msg void OnViewStyle(UINT nCommandID);
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnHelpGotomysqlsite();
afx_msg void OnNewConnection();
afx_msg void OnCloseConnection();
afx_msg void OnHelpMysqlinfo();
};
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_MAINFRM_H__58E63188_DD0B_11D9_A8EF_BCC8AEF81D60__INCLUDED_)
// MainFrm.cpp : implementation of the CMainFrame class
//
#include "stdafx.h"
#include "mysqlone.h"
#include "MainFrm.h"
#include "LeftView.h"
#include "mysqloneView.h"
#include "SqlQueryDlg.h"
#include "NewDatabase.h"
#include "MySQLInfoDlg.h"
#include ".\mainfrm.h"
#include "mysqlonedoc.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CMainFrame
IMPLEMENT_DYNCREATE(CMainFrame, CFrameWnd)
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
//{{AFX_MSG_MAP(CMainFrame)
ON_WM_CREATE()
ON_COMMAND(ID_NEW_CONNECTION, OnNewConnection)
ON_COMMAND(ID_CLOSE_CONNECTION, OnCloseConnection)
ON_COMMAND(ID_HELP_GOTOMYSQLSITE, OnHelpGotomysqlsite)
//}}AFX_MSG_MAP
ON_UPDATE_COMMAND_UI_RANGE(AFX_ID_VIEW_MINIMUM, AFX_ID_VIEW_MAXIMUM, OnUpdateViewStyles)
ON_COMMAND_RANGE(AFX_ID_VIEW_MINIMUM, AFX_ID_VIEW_MAXIMUM, OnViewStyle)
ON_COMMAND(ID_HELP_MYSQLINFO, OnHelpMysqlinfo)
END_MESSAGE_MAP()
static UINT indicators[] =
{
ID_SEPARATOR, // status line indicator
ID_INDICATOR_CAPS,
ID_INDICATOR_NUM,
ID_INDICATOR_SCRL,
};
/////////////////////////////////////////////////////////////////////////////
// CMainFrame construction/destruction
CMainFrame::CMainFrame()
{
// TODO: add member initialization code here
}
CMainFrame::~CMainFrame()
{
}
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP
| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
!m_wndToolBar.LoadToolBar(IDR_TOOLBAR2))
{
TRACE0("Failed to create toolbar\n");
return -1; // fail to create
}
if (!m_wndStatusBar.Create(this) ||
!m_wndStatusBar.SetIndicators(indicators,
sizeof(indicators)/sizeof(UINT)))
{
TRACE0("Failed to create status bar\n");
return -1; // fail to create
}
// TODO: Delete these three lines if you don't want the toolbar to be dockable
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(&m_wndToolBar);
return 0;
}
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT /*lpcs*/,
CCreateContext* pContext)
{
// create splitter window
if (!m_wndSplitter.CreateStatic(this, 1, 2))
return FALSE;
if (!m_wndSplitter.CreateView(0, 0, RUNTIME_CLASS(CLeftView), CSize(200, 100), pContext) ||
!m_wndSplitter.CreateView(0, 1, RUNTIME_CLASS(CMysqloneView), CSize(100, 100), pContext))
{
m_wndSplitter.DestroyWindow();
return FALSE;
}
return TRUE;
}
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
if( !CFrameWnd::PreCreateWindow(cs) )
return FALSE;
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// CMainFrame diagnostics
#ifdef _DEBUG
void CMainFrame::AssertValid() const
{
CFrameWnd::AssertValid();
}
void CMainFrame::Dump(CDumpContext& dc) const
{
CFrameWnd::Dump(dc);
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CMainFrame message handlers
CMysqloneView* CMainFrame::GetRightPane()
{
CWnd* pWnd = m_wndSplitter.GetPane(0, 1);
CMysqloneView* pView = DYNAMIC_DOWNCAST(CMysqloneView, pWnd);
return pView;
}
void CMainFrame::OnUpdateViewStyles(CCmdUI* pCmdUI)
{
// TODO: customize or extend this code to handle choices on the
// View menu.
CMysqloneView* pView = GetRightPane();
// if the right-hand pane hasn't been created or isn't a view,
// disable commands in our range
if (pView == NULL)
pCmdUI->Enable(FALSE);
else
{
DWORD dwStyle = pView->GetStyle() & LVS_TYPEMASK;
// if the command is ID_VIEW_LINEUP, only enable command
// when we're in LVS_ICON or LVS_SMALLICON mode
if (pCmdUI->m_nID == ID_VIEW_LINEUP)
{
if (dwStyle == LVS_ICON || dwStyle == LVS_SMALLICON)
pCmdUI->Enable();
else
pCmdUI->Enable(FALSE);
}
else
{
// otherwise, use dots to reflect the style of the view
pCmdUI->Enable();
BOOL bChecked = FALSE;
switch (pCmdUI->m_nID)
{
case ID_VIEW_DETAILS:
bChecked = (dwStyle == LVS_REPORT);
break;
case ID_VIEW_SMALLICON:
bChecked = (dwStyle == LVS_SMALLICON);
break;
case ID_VIEW_LARGEICON:
bChecked = (dwStyle == LVS_ICON);
break;
case ID_VIEW_LIST:
bChecked = (dwStyle == LVS_LIST);
break;
default:
bChecked = FALSE;
break;
}
pCmdUI->SetRadio(bChecked ? 1 : 0);
}
}
}
void CMainFrame::OnViewStyle(UINT nCommandID)
{
// TODO: customize or extend this code to handle choices on the
// View menu.
CMysqloneView* pView = GetRightPane();
// if the right-hand pane has been created and is a CMysqloneView,
// process the menu commands...
if (pView != NULL)
{
DWORD dwStyle = -1;
switch (nCommandID)
{
case ID_VIEW_LINEUP:
{
// ask the list control to snap to grid
CListCtrl& refListCtrl = pView->GetListCtrl();
refListCtrl.Arrange(LVA_SNAPTOGRID);
}
break;
// other commands change the style on the list control
case ID_VIEW_DETAILS:
dwStyle = LVS_REPORT;
break;
case ID_VIEW_SMALLICON:
dwStyle = LVS_SMALLICON;
break;
case ID_VIEW_LARGEICON:
dwStyle = LVS_ICON;
break;
case ID_VIEW_LIST:
dwStyle = LVS_LIST;
break;
}
// change the style; window will repaint automatically
if (dwStyle != -1)
pView->ModifyStyle(LVS_TYPEMASK, dwStyle);
}
}
void CMainFrame::OnNewConnection()
{
MYSQL* mysql = &(((CMysqloneApp*)AfxGetApp())->mysql);
CMysqloneApp* MyApp=((CMysqloneApp*)AfxGetApp());
MyApp->ConnectToDb();
CMysqloneDoc* pDoc=(CMysqloneDoc*)GetActiveDocument();
pDoc->connected = true;
pDoc->UpdateAllViews (NULL);
}
void CMainFrame::OnCloseConnection()
{
CMysqloneApp* MyApp=((CMysqloneApp*)AfxGetApp());
MyApp->CloseConnectionDb();
CMysqloneDoc* pDoc=(CMysqloneDoc*)GetActiveDocument();
pDoc->connected = false;
pDoc->UpdateAllViews(NULL);
}
void CMainFrame::OnHelpGotomysqlsite()
{
ShellExecute(NULL,"open", "http://www.mysql.com", "", "c:\\", SW_SHOWNORMAL);
}
void CMainFrame::OnHelpMysqlinfo()
{
CMySQLInfoDlg dlg;
if (dlg.DoModal() == IDOK )
{
dlg.OnBnClickedExit();
}
}
// mysqlone.h : main header file for the MYSQLONE application
//
#if !defined(AFX_MYSQLONE_H__58E63184_DD0B_11D9_A8EF_