Где воздух гор - там тишина снегов, молчание камней и дремлет сила

Программирование Windows

Создание программы - MySQL DatabaseBrowser

2018-03-09 08:21:18







Сейчас использование баз данных, в то числе и удаленных стало обычной и повседневной практикой. Очень часто используется и СУБД 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_

Здесь нет комментариев


Новый комментарий:
























Яндекс.Метрика