DB ( Data Base ) - база данных, представляющая собой совокупность взаимосвязанных таблиц, каждая из которых, как правило, хранится в отдельном файле. Имя базы данных обычно совпадает с именем каталога, где хранятся данныеODBC ( Open Database Connectivity ) - открытое соединение с базами данныхDBMS ( Database Management System ) - система управления базами данныхSDK ( Software Development Kit ) - комплект разработки программного обеспеченияAPI ( Application Programming Interface ) - интерфейс прикладных программ. Функции API ODBC обеспечивают взаимодействие при помощи синтаксиса SQL с любыми форматами данных, для которых существует соответствующий драйвер ODBCSQL ( Structured Query Language ) - язык структурированных запросовODBC Driver - драйвер взаимодействия с данными определенной структуры. Среда разработки Visual C++ .NET предоставляет готовые к употреблению драйвера ODBC, предназначенные для работы с такими СУБД, какSQL Server Microsoft AccessMicrosoft FoxPro Microsoft Excel dBASE Paradox ODBC Driver Manager - диспетчер драйверов ODBC (файл ODBC32.DLL )ODBC Cursor Library - библиотека курсоров ODBC (файл ODBCCR32.DLL )Data Source - источник данных, означает логическое представление в виде таблицы конкретного файла с даннымиDSN ( Data Source Name ) - имя (алиас, псевдоним) источника данных, зарегистрированное диспетчером драйверов, под которым ODBC будет обеспечивать подключение к данным нужного драйвера и в котором будет указан путь размещения таблиц базы данныхResult Set - результирующий набор данных, полученный после выполнения SQL -запроса к базе данныхConnection - подключение к базе данныхODBC Data Source Administrator - специальная утилита (вспомогательная, служебная программа) корпорации Microsoft для регистрации источника данныхДля обеспечения определенного уровня программной абстракции ODBC обеспечивает взаимодействие с конкретным форматом данных через драйвер ODBC, поставляемый разработчиком соответствующего формата DB. Чтобы ODBC поддерживало соответствующий формат данных, разработан перечень требований, который должен обеспечить разработчик драйвера (поставщик соответствующих данных). Этот перечень требований называется уровнем согласования.
Драйвер может поддерживать и большее число функций, но базовый уровень согласования должен быть выдержан, если разработчик драйвера хочет, чтобы его данные поддерживались приложениями на основе ODBC.
Когда приложение использует функции базового уровня согласования, то в проверке возможностей драйвера нет необходимости. Но если приложение базы данных хочет обратиться к функции ODBC, не принадлежащей базовому уровню согласования, то оно должно предварительно удостовериться, что драйвер эту функцию поддерживает. Для выяснения возможности драйвера поддерживать какую-то функцию в ODBC существует специальная тестовая функция SQLGetFunctions(). Аналогичные требования согласования существуют и для синтаксиса SQL.
Все функции ODBC можно разделить на логические группы, соответствующие порядку, в котором их применяют при создании приложений:
ODBCODBCSQL -запросовSQL -запросы на получение выборки данныхНастройка ODBC включает в себя действия, которые нужно выполнить для нормальной работы приложения. Прежде всего нужно запустить ODBC Data Source Administrator. Она запускается из командной строки Пуск/Выполнить операционной системы командой odbcad32

В результате появится окно администратора

Окно администратора имеет несколько вкладок, в том числе соответствующие типу , поддерживаемому ODBC
User DSN - пользовательский источник данных. Является локальным для того компьютера, на котором он был создан, и может применяться только создавшим его пользователемSystem DSN - системный источник данных. Принадлежит тому компьютеру, на котором создан. Любой обладающий достаточными правами пользователь может обращаться к этому источнику данныхFile DSN - файловый источник данных. Обеспечивает доступ к конкретному файлу базы данныхКаждая вкладка делает свою запись в системном реестре, например

Чтобы создать для источника данных, поддерживаемого драйвером ODBC, следует указать всю информацию, необходимую для его работы. Большинство драйверов ODBC требуют, как минимум, имени физического файла с данными и путем доступа к файлу.
Иными словами, с помощью утилиты ODBC Data Source Administrator мы устанавливаем ассоциативную связь между файлом с данными конкретной структуры и соответствующим драйвером, понимающим такой формат данных. Этой связи мы присваиваем имя ( ), которое затем должны использовать в своем приложении для работы с этими данными, но уже с помощью стандартных функций ODBC. Таким образом достигается отделение (абстракция) функций обработки данных от конкретной структуры данных. Кроме этого, в содержится информация местонахождения файлов-таблиц с данными. Перенеся приложение и данные в другое место или компьютер, достаточно установить настройки соответствующего и приложение будет нормально работать!!!
После настройки с помощью утилиты ODBC Data Source Administrator теперь вместо конкретного файла с данными у нас есть именованная абстракция данные-драйвер, зарегистрированная в операционной системе и поэтому готовая к поддержке ее механизмом ODBC. Все готово для того, чтобы к базе данных можно было обратиться с помощью функций API ODBC как к абстрактным данным, которые теперь можно назвать данными ODBC.
Первым этапом программного доступа к данным ODBC является подключение к источнику данных. Для этого механизм ODBC требует выполнить последовательность действий, часть из которых является подготовительной:
ODBC и получить уникальный дескриптор среды ( unique environment handle ) henv. Этот дескриптор уникально идентифицирует в операционной системе поток, который будет использовать механизм ODBC. Следующий фрагмент кода резервирует в системе поток для ODBCSQLHENV henv;
SQLRETURN rc = SQLAllocHandle(SQL_HANDLE_ENV,
SQL_NULL_HANDLE,
henv);
ODBC, с которой совместимо приложениеSQLSetEnvAttr(henv,
SQL_ATTR_ODBC_VERSION,
(SQLPOINTER) SQL_OV_ODBC3,
SQL_IS_INTEGER);
ODBC версии 3.0ODBC дескриптор подключения к базе данных ( data connection handle ) hdbcSQLHDBC hdbc;
SQLRETURN rc = SQLAllocHandle(SQL_HANDLE_DBC,
henv,
hdbc);
hdbc, можно, наконец, подключиться к источнику данных, использовав любую из трех функций ODBC:SQLConnect () - самый простой способ подключения к источнику данных. Ей достаточно передать DSN , идентификатор пользователя и пароль для подключения к источнику данных ODBCSQLDriverConnect() - альтернативный вариант для драйверов ODBC. Она требует передачи более подробной информации, чем функция SQLConnect ()SQLBrowseConnect() - это средство подключения к источнику данных, обладающее наибольшими возможностями. При помощи одного или нескольких обращений к этой функции можно запросить и получить всю информацию, необходимую для подключения к источнику данных. Для обеспечения такого подхода функция возвращает значение SQL_NEEDS_DATA до тех пор, пока приложение не представит всю требуемую информацию, и только после этого она возвратит значение SQL_SUCCESSВот первый, наиболее простой, вариант использования функции подключения
SQLRETURN rc = SQLConnect(hdbc, // Дескриптор подключения
(SQLCHAR*) "MyBase", SQL_NTS, // DSN
(SQLCHAR*) "", SQL_NTS, // Идентификатор пользователя
(SQLCHAR*) "", SQL_NTS); // Пароль для подключения
bool bIsConnected = TRUE; // Подняли флаг, что соединение существует
Аргумент SQL_NTS сообщает ODBC о том, что предыдущий переданный аргумент представляет собой строку с завершающим нулевым символом.
Одной из наиболее существенных особенностей ODBC является то, что он позволяет запросить информацию о возможностях драйвера ODBC. Для этого используются API ODBC -функции SQLGetFunctions(), SQLGetInfo(), SQLGetTypeInfo(). Рассмотрим их...
SQLGetFunctions() - позволяет запросить драйвер ODBC о том, поддерживает ли он определенные функции или группы функций. В качестве аргументов необходимо передать дескриптор hdbc и числовое значение, идентифицирующее определенную функцию или группу функций API ODBC. Эти значения определены в sqlext.h, который устанавливается вместе с Microsoft SQL Server, SDK ODBC или Visual Studio .NET. Приведенный ниже фрагмент кода выясняет, поддерживает ли драйвер, ассоциированный с указанным DSN , API ODBC -функции SQLTables() и SQLColumns()SQLUSMALLINT bSQLTablesFunctionExists; // Объявили логическую величину
SQLUSMALLINT bSQLColumnsFunctionExists; // Объявили логическую величину
SQLGetFunctions(hdbc,
SQL_API_SQLTABLES,
bSQLTablesFunctionExists);
SQLGetFunctions(hdbc,
SQL_API_SQLCOLUMNS,
bSQLColumnsFunctionExists);
if(bSQLTablesFunctionExists
bSQLColumnsFunctionExists){
// Обе функции существуют
}
Если проверяемый драйвер поддерживает базовый уровень согласования, то необходимости в приведенной проверке функциональности драйвера нет. Если только мы не используем самопальный или экзотический формат данных, а придерживаемся структуры данных наиболее распространенных типов, то можно быть уверенным, что разработчики этих форматов обеспечили базовый уровень согласования.
SQLGetInfo() - возвращает информацию о драйвере ODBC и его возможностях. Например, с ее помощью можно выяснить версию драйвера ODBC, его название, а также уровни согласования API и SQLSQLGetTypeInfo() - возвращает информацию о том, какие типы данных поддерживаются применяемым источником данных. Драйвер возвращает информацию в формате результирующего набора данных ( result set )Последнее, что приложение должно сделать после подключения к источнику данных, но прежде, чем оно будет способно осуществлять запросы SQL, - это получить дескриптор оператора ( statement handle ) или hstmt. Чтобы получить дескриптор hstmt, достаточно выполнить такой код
SQLSTMT hstmt;
SQLRETURN rc = SQLAllocHandle(SQL_HANDLE_STMT,
hdbc,
hstmt);
Как только приложение получит дескриптор hstmt, оно сможет передавать источнику данных операторы SQL.
Существуют два разных способа организации выполнения источником данных запроса SQL.
LPCSTR szSQL = "INSERT INTO MyTable "
"VALUES('UserID', 'USER NAME', 0)";
SQLRETURN rc;
rc = ::SQLExecDirect(hstmt, (unsigned char*)szSQL, SQL_NTS);
Данная функция добавит в таблицу MyTable базы данных MyBase новую строку данных со значениями полей ("
Здесь подразумевается предварительная подготовка SQL -запроса при помощи функции SQLPrepare() и последующее его выполнение при помощи функции SQLExecute().
LPCSTR szSQL = "INSERT INTO MyTable "
"VALUES('UserID', 'USER NAME', 0)";
SQLRETURN rc;
rc = ::SQLPrepare(hstmt, (unsigned char*)szSQL, SQL_NTS);
if(rc != SQL_SUCCESS){
// Плохо! Сообщить пользователю или принять решение!
// Дальше не идти!
}
rc = ::SQLExecute(hstmt);
if(rc != SQL_SUCCESS){
// Плохо! Сообщить пользователю или принять решение!
// Дальше не идти!
}
Второй способ иногда может быть эффективней потому, что выражение SQL будет откомпилировано один раз, а затем может многократно использоваться для выполнения одного и того же запроса.
При выполнении SQL -запроса на получение данных приложению возвращается результирующий набор данных ( result set ), из которого приложение должно выбирать данные и передавать их в переменные для обработки и представления пользователю. Для решения этой задачи предусмотрен ряд API ODBC -функций, таких как
SQLNumResultCols() - определяет количество и тип полей возвращенных данных в результирующем набореSQLGetData() - извлекает значение определенного поляSQLBindCol() - ассоциирует переменные приложения со столбцами базы данныхSQLFetch() - передает данные из набора в переменные и передвигает курсор результирующего набора данных на следующую записьЭти функции позволяют разработчику создавать приложения баз данных, не заботясь заранее о том, сколько полей и какого типа будет возвращать источник данных в составе результирующего набора данных.
В результате SQL-запроса источник данных возвращает приложению дескриптор результирующего набора данных. Результирующий набор данных представляет собой таблицу, столбцы которой являются полями возвращенных данных, а строки - записями, т.е. значениями этих полей.
Как только подключение к источнику данных станет ненужным, от него необходимо отключиться при помощи функции SQLDisconnect(), а также освободить все дескрипторы, которые были для этого созданы. Освобождение дескрипторов должно выполняться в порядке, обратном их созданию. Соответствующий код может выглядеть так
if(henv){
if(hdbc){
if(bIsConnected){
if(hstmt){
::SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
}
::SQLDisconnect(hdbc);
bIsConnected = FALSE;
}
::SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
hdbc = NULL;
}
::SQLFreeHandle(SQL_HANDLE_ENV, henv);
henv = NULL;
}
Правильная настройка мастера создания приложений с поддержкой ODBC позволяет сгенерировать значительное количество кода автоматически. Кратко рассмотрим некоторые параметры мастера.
Нужно создать новый проект на основе

Установить тип документа или


None (Отсутствует) - мастер не будет создавать никакого кода, имеющего отношение к базам данных.
(Только ODBC приведет к включению мастером в состав проекта заголовка AFXDB.H и добавит в проект все необходимые подключаемые баблиотеки. Выбор параметра OLE DB приведет к подключению таких файлов заголовка, как ATLBASE.H, AFXOLEDB.H, ATLPLUS.H.
Database view without file support (Представление базы данных без файловой поддержки) - приведет к включению в состав приложения соответствующих заголовочных файлов, подключаемых библиотек, представления записей и класса набора записей. Через кнопку Data Source (Источник данных) можно выбрать ODBC или OLEDB Provider, а также используемую таблицу или представление. Параметры Dynaset (Динамический набор) или Snapshot (Моментальная выборка) позволяют выбирать тип логического курсора для результирующего набора данных. Параметр Bind all columns (Связать все поля) - включает поддержку механизма обмена данными RFX ( - обмен данными с полями записи) между переменными представления и полями базы. Это аналог DDX для баз данных.
Database view with file support (Представление базы данных с файловой поддержкой) - обеспечивает способность полученному коду сохранять документ.
Если выбрать тип диалогового приложения, то мастер делает все настройки поддержки ODBC недоступными. Однако можно включить эти поддержки в приложение вручную, что мы и сделаем ниже, выбрав тип диалогового приложения для лабораторной работы.
Скопируйте из каталога Pictures данной лабораторной работы файл MyTable.dbf в свой каталог
Запустите ODBC Data Source Administrator. Она запускается из командной строки Пуск/Выполнить операционной системы командой odbcad32
Установите вкладку User DSN и нажмите кнопку Add
Выберите драйвер как показано на рисунке
Нажмите кнопку Готово и в появившемся окне

заполните имя источника данных своим именем, например, MyBase. Установите версию dBase IV
Нажмите кнопку Выбор каталога и через диалоговое окно выберите каталог, где будут размещены файлы с таблицами данныхВ нашем случае используется одна таблица с данными MyTable.dbf, которую можно найти в каталоге размещения этого описания.
Предполагая, что Вы уже скопировали или еще скопируете файл MyTable.dbf в свой каталог, установите в качестве размещения базы данных свой каталогОкно выбора каталога размещения базы данных с примерными настройками показано на рисунке.

Нажимайте кнопку OK вплоть до закрытия окна администратора
Создайте новый проект на основе
Настройте вкладки мастера так


Нажмите кнопку Finish и мастер сгенерирует диалоговое приложениеОболочка Studio .NET при создании диалогового приложения не поддерживает установки мастера на обеспечение ODBC. Поэтому поддержку ODBC необходимо включить вручную. Чтобы приложение могло воспользоваться SDK ODBC, в него необходимо включить соответствующие
В сгенерированный мастером файл API_ODBCDlg.cpp ( в начало ) или в файл stdafx.h ( в конец ) неоходимо включить заголовочные файлы
#include <sql.h> #include <sqlext.h> #include <sqltypes.h>
В проект приложения необходимо добавить библиотеку импорта ODBC (odbc32.lib) . Для этого в меню Project нужно выбрать пункт меню Add Existing Item (Добавить существующий элемент) и найти необходимую библиотеку импорта odbc32.lib. В конфигурации Visual Studio .NET этот файл находится в каталоге Lib, как показано на рисунке

Если выбрать этот файл, то он автоматически будет добавлен в проект и появится во вкладке Solution Explorer данного проекта
В сгенерированный мастером файл API_ODBCDlg.cpp ( в начало ) или в файл stdafx.h ( в конец ) необходимо включить заголовочный файл
#include <afxdb.h>
Этот файл подключает необходимые Windows и содержит директиву #pragma comment, что обеспечивает включение необходимых библиотек импорта ODBC в состав приложения.
Включите в конец файла stdafx.h директиву, приведенную во втором способе такВключение директивы поддержки ODBC в файл stdafx.h // stdafx.h : include file for standard system include files, // or project specific include files that are used frequently, // but are changed infrequently #pragma once ..................................................... #include <afxdb.h>
Раскройте вкладку Resource View и русифицируйте ресурсыIDD_ABOUTBOX
Откройте ресурс IDD_API_ODBC_DIALOG в режиме дизайна, удалите все элементы управления и добавьте следующие элементы управления из панели ToolboxList Box - 1 шт.Static Text - 3 шт.Edit Control - 3 шт.
Включите панель инструментов
Измените идентификаторы списка и полей ввода и создайте для этих элементов управления переменные-члены
IDC_LISTBOXControlCListBoxm_ListBoxpublicIDC_NUMEDITValueintm_NumEditpublicIDC_NAMEEDITValueCString m_NameEditpublicIDC_YEAREDITValueintm_YearEditpublicНастройки мастера приведены на рисунках




Мастер внесет добавления в объявление класса
Добавления в файл API_ODBCDlg.h
// CAPI_ODBCDlg dialog
class CAPI_ODBCDlg : public CDialog
{
..................................................
public:
// Переменная управления списком
CListBox m_ListBox;
// Переменная поля ввода № п/п
int m_NumEdit;
// Переменная поля ввода ФИО
CString m_NameEdit;
// Переменная поля ввода Год
int m_YearEdit;
};
Мастер внесет добавления в определение класса
Добавления в файл API_ODBCDlg.cpp
// CAPI_ODBCDlg dialog
CAPI_ODBCDlg::CAPI_ODBCDlg(CWnd* pParent /*=NULL*/)
: CDialog(CAPI_ODBCDlg::IDD, pParent)
, m_NumEdit(0)
, m_NameEdit(_T(""))
, m_YearEdit(0)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CAPI_ODBCDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
DDX_Control(pDX, IDC_LISTBOX, m_ListBox);
DDX_Text(pDX, IDC_NUMEDIT, m_NumEdit);
DDX_Text(pDX, IDC_NAMEEDIT, m_NameEdit);
DDX_Text(pDX, IDC_YEAREDIT, m_YearEdit);
}
BEGIN_MESSAGE_MAP(CAPI_ODBCDlg, CDialog)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
........................................................
Разработаем код, который получает данные из базы данных и заполняет ими список. Код упакуем в функцию FillDbToListBox().

Добавьте в класс CAPI_ODBCDlg объявление функцииДобавление в файл API_ODBCDlg.h
class CAPI_ODBCDlg : public CDialog
{
................................................
public:
// Переменная управления списком
CListBox m_ListBox;
// Переменная поля ввода № п/п
int m_NumEdit;
// Переменная поля ввода ФИО
CString m_NameEdit;
// Переменная поля ввода Год
int m_YearEdit;
// Функция заполнения списка данными DB
void FillDbToListBox(void);
};
Добавление в файл API_ODBCDlg.cpp
// Функция заполнения списка данными DB
void CAPI_ODBCDlg::FillDbToListBox(void)
{
}
Добавьте в начало файла API_ODBCDlg.cpp следующее определение структурыДобавление структуры в файл API_ODBCDlg.cpp
// API_ODBCDlg.cpp : implementation file
//
#include "stdafx.h"
#include "API_ODBC.h"
#include "API_ODBCDlg.h"
#include ".\api_odbcdlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
struct RECORD
{
int recNumEdit;// Переменная поля ввода № п/п
CString recNameEdit;// Переменная поля ввода ФИО
int recYearEdit;// Переменная поля ввода Год
};
.......................................................
Добавьте после определения структуры RECORD следующую директиву препроцессораДобавление директивы препроцессора в файл API_ODBCDlg.cpp
......................................................
struct RECORD
{
int recNumEdit;// Переменная поля ввода № п/п
CString recNameEdit;// Переменная поля ввода ФИО
int recYearEdit;// Переменная поля ввода Год
};
#define LEN_BUF 31 // Длина буфера
.......................................................
Найдите функцию OnInitDialog(), сгенерированную мастером, и непосредственно перед оператором return добавьте вызов функции FillDbToListBox(). Эта функция заполнит список на последнем этапе инициализации диалогового окнаДобавление вызова в файл API_ODBCDlg.cpp
BOOL CAPI_ODBCDlg::OnInitDialog()
{
CDialog::OnInitDialog();
.............................................................
// TODO: Add extra initialization here
FillDbToListBox();
return TRUE; // return TRUE unless you set the focus to a control
}
Наполните функцию FillDbToListBox() следующим кодом, реализующим то, о чем было сказано вышеФункция FillDbToListBox() в файле API_ODBCDlg.cpp
// Функция заполнения списка данными DB
void CAPI_ODBCDlg::FillDbToListBox(void)
{
// Объявления дескрипторов и вспомогательных переменных
SQLHENV henv = NULL;
SQLHDBC hdbc = NULL;
SQLHSTMT hstmt = NULL;
bool bIsConnected = false;
SQLRETURN rc;
// Инициализация механизма ODBC среды
rc = SQLAllocHandle(SQL_HANDLE_ENV,
SQL_NULL_HANDLE,
henv);
if(rc != SQL_SUCCESS){
MessageBox("Не могу инициализировать ODBC",
"", MB_OK | MB_ICONSTOP);
return;
}
// Выбор версии ODBC-3
rc = SQLSetEnvAttr(henv,
SQL_ATTR_ODBC_VERSION,
(SQLPOINTER) SQL_OV_ODBC3,
SQL_IS_INTEGER);
if(rc != SQL_SUCCESS){
MessageBox("Не могу установить версию ODBC",
"", MB_OK | MB_ICONSTOP);
return;
}
// Получить от ODBC дескриптор подключения к базе данных
rc = SQLAllocHandle(SQL_HANDLE_DBC, henv, hdbc);
if(rc != SQL_SUCCESS){
MessageBox("Не могу получить дескриптор подключения к БД",
"", MB_OK | MB_ICONSTOP);
return;
}
// Подключить приложение к источнику данных
rc = SQLConnect(hdbc, // Дескриптор подключения
(SQLCHAR*) "MyBase", SQL_NTS, // DSN
(SQLCHAR*) "", SQL_NTS, // Идентификатор пользователя
(SQLCHAR*) "", SQL_NTS); // Пароль для подключения
if(rc != SQL_SUCCESS rc != SQL_SUCCESS_WITH_INFO){
MessageBox("Не могу подключиться к источнику данных",
"", MB_OK | MB_ICONSTOP);
return;
}
bIsConnected = true; // Подняли флаг, что соединение существует
// Получить дескриптор оператора (statement handle)
// для возможности передачи SQL-запросов
rc = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, hstmt);
if(rc != SQL_SUCCESS){
MessageBox("Не могу получить дескриптор оператора",
"", MB_OK | MB_ICONSTOP);
return;
}
// Подготовить и выполнить SQL-запрос (имя таблицы можно без расширения)
LPCSTR szSQL = "SELECT number, name, birth FROM MyTable.dbf";
rc = SQLExecDirect(hstmt, (unsigned char*)szSQL, SQL_NTS);
if(rc != SQL_SUCCESS){
MessageBox("Не могу выполнить SQL-запрос к БД",
"", MB_OK | MB_ICONSTOP);
return;
}
// Связывание полей с переменными приложения
long int cb; // Вспомогательная типа SDWORD
int iNumber;
char strName[LEN_BUF];
int iBirth;
SQLBindCol(hstmt, 1, SQL_INTEGER, iNumber, 0, cb);// Field1
SQLBindCol(hstmt, 2, SQL_CHAR, strName, LEN_BUF, cb);// Field2
SQLBindCol(hstmt, 3, SQL_INTEGER, iBirth, 0, cb);// Field3
// Заполнение списка
rc = SQLFetch(hstmt);
while(rc == SQL_SUCCESS){
RECORD* pRecord = new RECORD;
pRecord->recNumEdit = iNumber;
pRecord->recNameEdit = strName;
pRecord->recYearEdit = iBirth;
CString strTerm;
strTerm.Format("%d %s %d", iNumber, strName, iBirth);
int iIndex = m_ListBox.AddString(strTerm);// Добавить в список
// Сохранить указатель на неименованный экземпляр структуры в списке
m_ListBox.SetItemData(iIndex, (DWORD_PTR)pRecord);
rc = SQLFetch(hstmt); // Дать следующую запись
}
// Освободить все ресурсы ODBC
if(henv){
if(hdbc){
if(bIsConnected){
if(hstmt){
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
}
SQLDisconnect(hdbc);
bIsConnected = false;
}
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
hdbc = NULL;
}
SQLFreeHandle(SQL_HANDLE_ENV, henv);
henv = NULL;
}
}
После завершения работы приложения необходимо вернуть системе память, выделенную динамически под хранение экземпляров структуры RECORD.
В классе CAPI_ODBCDlg переопределите виртуальную функцию DestroyWindow() базового класса CDialog

и разместить в ней следующий код
Код функции DestroyWindow() в файл API_ODBCDlg.cpp
BOOL CAPI_ODBCDlg::DestroyWindow()
{
RECORD* pRecord;
int nCount = m_ListBox.GetCount();
for(int i = 0; i < nCount; i++){
pRecord = (RECORD*)m_ListBox.GetItemData(i);
if(pRecord)
delete pRecord;
}
return CDialog::DestroyWindow();
}
Установим связь между полями ввода Edit Control и списком , добавив обработчик в класс CAPI_ODBCDlg. Для этого:
В панели
Добавьте обработчик для сообщения LBN_SELCHANGE, который заполните таким кодомКод обработчика для списка в файле API_ODBCDlg.cpp
void CAPI_ODBCDlg::OnLbnSelchangeListbox()
{
int iIndex = m_ListBox.GetCurSel();
if(iIndex == LB_ERR) return;
RECORD* pRecord =
(RECORD*)m_ListBox.GetItemData(iIndex);
if(pRecord){
m_NumEdit = pRecord->recNumEdit;
m_NameEdit = pRecord->recNameEdit;
m_YearEdit = pRecord->recYearEdit;
UpdateData(FALSE);
}
}
Добавьте в функцию OnInitDialog() класса CAPI_ODBCDlg после вызова функции FillDbToListBox() заполнение полей ввода значениями первой записиИнициализация полей ввода в файле API_ODBCDlg.cpp
BOOL CAPI_ODBCDlg::OnInitDialog()
{
...............................................
// TODO: Add extra initialization here
FillDbToListBox();
m_ListBox.SetCurSel(0);
OnLbnSelchangeListbox();
return TRUE; // return TRUE unless you set the focus to a control
}
Оформите About со своими фамилиями и номером лабораторной работы
Постройте приложение и проверьте его работу. Результат должен быть примерно таким

DB ( Data Base ) - база данных, представляющая собой совокупность взаимосвязанных таблиц, каждая из которых, как правило, хранится в отдельном файле. Имя базы данных обычно совпадает с именем каталога, где хранятся данныеODBC ( Open Database Connectivity ) - открытое соединение с базами данныхDBMS ( Database Management System ) - система управления базами данныхSDK ( Software Development Kit ) - комплект разработки программного обеспеченияAPI ( Application Programming Interface ) - интерфейс прикладных программ. Функции API ODBC обеспечивают взаимодействие при помощи синтаксиса SQL с любыми форматами данных, для которых существует соответствующий драйвер ODBCSQL ( Structured Query Language ) - язык структурированных запросовODBC Driver - драйвер взаимодействия с данными определенной структуры. Среда разработки Visual C++ .NET предоставляет готовые к употреблению драйвера ODBC, предназначенные для работы с такими СУБД, какSQL Server Microsoft AccessMicrosoft FoxPro Microsoft Excel dBASE Paradox ODBC Driver Manager - диспетчер драйверов ODBC (файл ODBC32.DLL )ODBC Cursor Library - библиотека курсоров ODBC (файл ODBCCR32.DLL )Data Source - источник данных, означает логическое представление в виде таблицы конкретного файла с даннымиDSN ( Data Source Name ) - имя (алиас, псевдоним) источника данных, зарегистрированное диспетчером драйверов, под которым ODBC будет обеспечивать подключение к данным нужного драйвера и в котором будет указан путь размещения таблиц базы данныхResult Set - результирующий набор данных, полученный после выполнения SQL -запроса к базе данныхConnection - подключение к базе данныхODBC Data Source Administrator - специальная утилита (вспомогательная, служебная программа) корпорации Microsoft для регистрации источника данныхДля обеспечения определенного уровня программной абстракции ODBC обеспечивает взаимодействие с конкретным форматом данных через драйвер ODBC, поставляемый разработчиком соответствующего формата DB. Чтобы ODBC поддерживало соответствующий формат данных, разработан перечень требований, который должен обеспечить разработчик драйвера (поставщик соответствующих данных). Этот перечень требований называется уровнем согласования.
Драйвер может поддерживать и большее число функций, но базовый уровень согласования должен быть выдержан, если разработчик драйвера хочет, чтобы его данные поддерживались приложениями на основе ODBC.
Когда приложение использует функции базового уровня согласования, то в проверке возможностей драйвера нет необходимости. Но если приложение базы данных хочет обратиться к функции ODBC, не принадлежащей базовому уровню согласования, то оно должно предварительно удостовериться, что драйвер эту функцию поддерживает. Для выяснения возможности драйвера поддерживать какую-то функцию в ODBC существует специальная тестовая функция SQLGetFunctions(). Аналогичные требования согласования существуют и для синтаксиса SQL.
Все функции ODBC можно разделить на логические группы, соответствующие порядку, в котором их применяют при создании приложений:
ODBCODBCSQL -запросовSQL -запросы на получение выборки данныхНастройка ODBC включает в себя действия, которые нужно выполнить для нормальной работы приложения. Прежде всего нужно запустить ODBC Data Source Administrator. Она запускается из командной строки Пуск/Выполнить операционной системы командой odbcad32

В результате появится окно администратора

Окно администратора имеет несколько вкладок, в том числе соответствующие типу , поддерживаемому ODBC
User DSN - пользовательский источник данных. Является локальным для того компьютера, на котором он был создан, и может применяться только создавшим его пользователемSystem DSN - системный источник данных. Принадлежит тому компьютеру, на котором создан. Любой обладающий достаточными правами пользователь может обращаться к этому источнику данныхFile DSN - файловый источник данных. Обеспечивает доступ к конкретному файлу базы данныхКаждая вкладка делает свою запись в системном реестре, например

Чтобы создать для источника данных, поддерживаемого драйвером ODBC, следует указать всю информацию, необходимую для его работы. Большинство драйверов ODBC требуют, как минимум, имени физического файла с данными и путем доступа к файлу.
Иными словами, с помощью утилиты ODBC Data Source Administrator мы устанавливаем ассоциативную связь между файлом с данными конкретной структуры и соответствующим драйвером, понимающим такой формат данных. Этой связи мы присваиваем имя ( ), которое затем должны использовать в своем приложении для работы с этими данными, но уже с помощью стандартных функций ODBC. Таким образом достигается отделение (абстракция) функций обработки данных от конкретной структуры данных. Кроме этого, в содержится информация местонахождения файлов-таблиц с данными. Перенеся приложение и данные в другое место или компьютер, достаточно установить настройки соответствующего и приложение будет нормально работать!!!
После настройки с помощью утилиты ODBC Data Source Administrator теперь вместо конкретного файла с данными у нас есть именованная абстракция данные-драйвер, зарегистрированная в операционной системе и поэтому готовая к поддержке ее механизмом ODBC. Все готово для того, чтобы к базе данных можно было обратиться с помощью функций API ODBC как к абстрактным данным, которые теперь можно назвать данными ODBC.
Первым этапом программного доступа к данным ODBC является подключение к источнику данных. Для этого механизм ODBC требует выполнить последовательность действий, часть из которых является подготовительной:
ODBC и получить уникальный дескриптор среды ( unique environment handle ) henv. Этот дескриптор уникально идентифицирует в операционной системе поток, который будет использовать механизм ODBC. Следующий фрагмент кода резервирует в системе поток для ODBCSQLHENV henv;
SQLRETURN rc = SQLAllocHandle(SQL_HANDLE_ENV,
SQL_NULL_HANDLE,
henv);
ODBC, с которой совместимо приложениеSQLSetEnvAttr(henv,
SQL_ATTR_ODBC_VERSION,
(SQLPOINTER) SQL_OV_ODBC3,
SQL_IS_INTEGER);
ODBC версии 3.0ODBC дескриптор подключения к базе данных ( data connection handle ) hdbcSQLHDBC hdbc;
SQLRETURN rc = SQLAllocHandle(SQL_HANDLE_DBC,
henv,
hdbc);
hdbc, можно, наконец, подключиться к источнику данных, использовав любую из трех функций ODBC:SQLConnect () - самый простой способ подключения к источнику данных. Ей достаточно передать DSN , идентификатор пользователя и пароль для подключения к источнику данных ODBCSQLDriverConnect() - альтернативный вариант для драйверов ODBC. Она требует передачи более подробной информации, чем функция SQLConnect ()SQLBrowseConnect() - это средство подключения к источнику данных, обладающее наибольшими возможностями. При помощи одного или нескольких обращений к этой функции можно запросить и получить всю информацию, необходимую для подключения к источнику данных. Для обеспечения такого подхода функция возвращает значение SQL_NEEDS_DATA до тех пор, пока приложение не представит всю требуемую информацию, и только после этого она возвратит значение SQL_SUCCESSВот первый, наиболее простой, вариант использования функции подключения
SQLRETURN rc = SQLConnect(hdbc, // Дескриптор подключения
(SQLCHAR*) "MyBase", SQL_NTS, // DSN
(SQLCHAR*) "", SQL_NTS, // Идентификатор пользователя
(SQLCHAR*) "", SQL_NTS); // Пароль для подключения
bool bIsConnected = TRUE; // Подняли флаг, что соединение существует
Аргумент SQL_NTS сообщает ODBC о том, что предыдущий переданный аргумент представляет собой строку с завершающим нулевым символом.
Одной из наиболее существенных особенностей ODBC является то, что он позволяет запросить информацию о возможностях драйвера ODBC. Для этого используются API ODBC -функции SQLGetFunctions(), SQLGetInfo(), SQLGetTypeInfo(). Рассмотрим их...
SQLGetFunctions() - позволяет запросить драйвер ODBC о том, поддерживает ли он определенные функции или группы функций. В качестве аргументов необходимо передать дескриптор hdbc и числовое значение, идентифицирующее определенную функцию или группу функций API ODBC. Эти значения определены в sqlext.h, который устанавливается вместе с Microsoft SQL Server, SDK ODBC или Visual Studio .NET. Приведенный ниже фрагмент кода выясняет, поддерживает ли драйвер, ассоциированный с указанным DSN , API ODBC -функции SQLTables() и SQLColumns()SQLUSMALLINT bSQLTablesFunctionExists; // Объявили логическую величину
SQLUSMALLINT bSQLColumnsFunctionExists; // Объявили логическую величину
SQLGetFunctions(hdbc,
SQL_API_SQLTABLES,
bSQLTablesFunctionExists);
SQLGetFunctions(hdbc,
SQL_API_SQLCOLUMNS,
bSQLColumnsFunctionExists);
if(bSQLTablesFunctionExists
bSQLColumnsFunctionExists){
// Обе функции существуют
}
Если проверяемый драйвер поддерживает базовый уровень согласования, то необходимости в приведенной проверке функциональности драйвера нет. Если только мы не используем самопальный или экзотический формат данных, а придерживаемся структуры данных наиболее распространенных типов, то можно быть уверенным, что разработчики этих форматов обеспечили базовый уровень согласования.
SQLGetInfo() - возвращает информацию о драйвере ODBC и его возможностях. Например, с ее помощью можно выяснить версию драйвера ODBC, его название, а также уровни согласования API и SQLSQLGetTypeInfo() - возвращает информацию о том, какие типы данных поддерживаются применяемым источником данных. Драйвер возвращает информацию в формате результирующего набора данных ( result set )Последнее, что приложение должно сделать после подключения к источнику данных, но прежде, чем оно будет способно осуществлять запросы SQL, - это получить дескриптор оператора ( statement handle ) или hstmt. Чтобы получить дескриптор hstmt, достаточно выполнить такой код
SQLSTMT hstmt;
SQLRETURN rc = SQLAllocHandle(SQL_HANDLE_STMT,
hdbc,
hstmt);
Как только приложение получит дескриптор hstmt, оно сможет передавать источнику данных операторы SQL.
Существуют два разных способа организации выполнения источником данных запроса SQL.
LPCSTR szSQL = "INSERT INTO MyTable "
"VALUES('UserID', 'USER NAME', 0)";
SQLRETURN rc;
rc = ::SQLExecDirect(hstmt, (unsigned char*)szSQL, SQL_NTS);
Данная функция добавит в таблицу MyTable базы данных MyBase новую строку данных со значениями полей ("
Здесь подразумевается предварительная подготовка SQL -запроса при помощи функции SQLPrepare() и последующее его выполнение при помощи функции SQLExecute().
LPCSTR szSQL = "INSERT INTO MyTable "
"VALUES('UserID', 'USER NAME', 0)";
SQLRETURN rc;
rc = ::SQLPrepare(hstmt, (unsigned char*)szSQL, SQL_NTS);
if(rc != SQL_SUCCESS){
// Плохо! Сообщить пользователю или принять решение!
// Дальше не идти!
}
rc = ::SQLExecute(hstmt);
if(rc != SQL_SUCCESS){
// Плохо! Сообщить пользователю или принять решение!
// Дальше не идти!
}
Второй способ иногда может быть эффективней потому, что выражение SQL будет откомпилировано один раз, а затем может многократно использоваться для выполнения одного и того же запроса.
При выполнении SQL -запроса на получение данных приложению возвращается результирующий набор данных ( result set ), из которого приложение должно выбирать данные и передавать их в переменные для обработки и представления пользователю. Для решения этой задачи предусмотрен ряд API ODBC -функций, таких как
SQLNumResultCols() - определяет количество и тип полей возвращенных данных в результирующем набореSQLGetData() - извлекает значение определенного поляSQLBindCol() - ассоциирует переменные приложения со столбцами базы данныхSQLFetch() - передает данные из набора в переменные и передвигает курсор результирующего набора данных на следующую записьЭти функции позволяют разработчику создавать приложения баз данных, не заботясь заранее о том, сколько полей и какого типа будет возвращать источник данных в составе результирующего набора данных.
В результате SQL-запроса источник данных возвращает приложению дескриптор результирующего набора данных. Результирующий набор данных представляет собой таблицу, столбцы которой являются полями возвращенных данных, а строки - записями, т.е. значениями этих полей.
Как только подключение к источнику данных станет ненужным, от него необходимо отключиться при помощи функции SQLDisconnect(), а также освободить все дескрипторы, которые были для этого созданы. Освобождение дескрипторов должно выполняться в порядке, обратном их созданию. Соответствующий код может выглядеть так
if(henv){
if(hdbc){
if(bIsConnected){
if(hstmt){
::SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
}
::SQLDisconnect(hdbc);
bIsConnected = FALSE;
}
::SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
hdbc = NULL;
}
::SQLFreeHandle(SQL_HANDLE_ENV, henv);
henv = NULL;
}
Правильная настройка мастера создания приложений с поддержкой ODBC позволяет сгенерировать значительное количество кода автоматически. Кратко рассмотрим некоторые параметры мастера.
Нужно создать новый проект на основе

Установить тип документа или


None (Отсутствует) - мастер не будет создавать никакого кода, имеющего отношение к базам данных.
(Только ODBC приведет к включению мастером в состав проекта заголовка AFXDB.H и добавит в проект все необходимые подключаемые баблиотеки. Выбор параметра OLE DB приведет к подключению таких файлов заголовка, как ATLBASE.H, AFXOLEDB.H, ATLPLUS.H.
Database view without file support (Представление базы данных без файловой поддержки) - приведет к включению в состав приложения соответствующих заголовочных файлов, подключаемых библиотек, представления записей и класса набора записей. Через кнопку Data Source (Источник данных) можно выбрать ODBC или OLEDB Provider, а также используемую таблицу или представление. Параметры Dynaset (Динамический набор) или Snapshot (Моментальная выборка) позволяют выбирать тип логического курсора для результирующего набора данных. Параметр Bind all columns (Связать все поля) - включает поддержку механизма обмена данными RFX ( - обмен данными с полями записи) между переменными представления и полями базы. Это аналог DDX для баз данных.
Database view with file support (Представление базы данных с файловой поддержкой) - обеспечивает способность полученному коду сохранять документ.
Если выбрать тип диалогового приложения, то мастер делает все настройки поддержки ODBC недоступными. Однако можно включить эти поддержки в приложение вручную, что мы и сделаем ниже, выбрав тип диалогового приложения для лабораторной работы.
Скопируйте из каталога Pictures данной лабораторной работы файл MyTable.dbf в свой каталог
Запустите ODBC Data Source Administrator. Она запускается из командной строки Пуск/Выполнить операционной системы командой odbcad32
Установите вкладку User DSN и нажмите кнопку Add
Выберите драйвер как показано на рисунке
Нажмите кнопку Готово и в появившемся окне

заполните имя источника данных своим именем, например, MyBase. Установите версию dBase IV
Нажмите кнопку Выбор каталога и через диалоговое окно выберите каталог, где будут размещены файлы с таблицами данныхВ нашем случае используется одна таблица с данными MyTable.dbf, которую можно найти в каталоге размещения этого описания.
Предполагая, что Вы уже скопировали или еще скопируете файл MyTable.dbf в свой каталог, установите в качестве размещения базы данных свой каталогОкно выбора каталога размещения базы данных с примерными настройками показано на рисунке.

Нажимайте кнопку OK вплоть до закрытия окна администратора
Создайте новый проект на основе
Настройте вкладки мастера так


Нажмите кнопку Finish и мастер сгенерирует диалоговое приложениеОболочка Studio .NET при создании диалогового приложения не поддерживает установки мастера на обеспечение ODBC. Поэтому поддержку ODBC необходимо включить вручную. Чтобы приложение могло воспользоваться SDK ODBC, в него необходимо включить соответствующие
В сгенерированный мастером файл API_ODBCDlg.cpp ( в начало ) или в файл stdafx.h ( в конец ) неоходимо включить заголовочные файлы
#include <sql.h> #include <sqlext.h> #include <sqltypes.h>
В проект приложения необходимо добавить библиотеку импорта ODBC (odbc32.lib) . Для этого в меню Project нужно выбрать пункт меню Add Existing Item (Добавить существующий элемент) и найти необходимую библиотеку импорта odbc32.lib. В конфигурации Visual Studio .NET этот файл находится в каталоге Lib, как показано на рисунке

Если выбрать этот файл, то он автоматически будет добавлен в проект и появится во вкладке Solution Explorer данного проекта
В сгенерированный мастером файл API_ODBCDlg.cpp ( в начало ) или в файл stdafx.h ( в конец ) необходимо включить заголовочный файл
#include <afxdb.h>
Этот файл подключает необходимые Windows и содержит директиву #pragma comment, что обеспечивает включение необходимых библиотек импорта ODBC в состав приложения.
Включите в конец файла stdafx.h директиву, приведенную во втором способе такВключение директивы поддержки ODBC в файл stdafx.h // stdafx.h : include file for standard system include files, // or project specific include files that are used frequently, // but are changed infrequently #pragma once ..................................................... #include <afxdb.h>
Раскройте вкладку Resource View и русифицируйте ресурсыIDD_ABOUTBOX
Откройте ресурс IDD_API_ODBC_DIALOG в режиме дизайна, удалите все элементы управления и добавьте следующие элементы управления из панели ToolboxList Box - 1 шт.Static Text - 3 шт.Edit Control - 3 шт.
Включите панель инструментов
Измените идентификаторы списка и полей ввода и создайте для этих элементов управления переменные-члены
IDC_LISTBOXControlCListBoxm_ListBoxpublicIDC_NUMEDITValueintm_NumEditpublicIDC_NAMEEDITValueCString m_NameEditpublicIDC_YEAREDITValueintm_YearEditpublicНастройки мастера приведены на рисунках




Мастер внесет добавления в объявление класса
Добавления в файл API_ODBCDlg.h
// CAPI_ODBCDlg dialog
class CAPI_ODBCDlg : public CDialog
{
..................................................
public:
// Переменная управления списком
CListBox m_ListBox;
// Переменная поля ввода № п/п
int m_NumEdit;
// Переменная поля ввода ФИО
CString m_NameEdit;
// Переменная поля ввода Год
int m_YearEdit;
};
Мастер внесет добавления в определение класса
Добавления в файл API_ODBCDlg.cpp
// CAPI_ODBCDlg dialog
CAPI_ODBCDlg::CAPI_ODBCDlg(CWnd* pParent /*=NULL*/)
: CDialog(CAPI_ODBCDlg::IDD, pParent)
, m_NumEdit(0)
, m_NameEdit(_T(""))
, m_YearEdit(0)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CAPI_ODBCDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
DDX_Control(pDX, IDC_LISTBOX, m_ListBox);
DDX_Text(pDX, IDC_NUMEDIT, m_NumEdit);
DDX_Text(pDX, IDC_NAMEEDIT, m_NameEdit);
DDX_Text(pDX, IDC_YEAREDIT, m_YearEdit);
}
BEGIN_MESSAGE_MAP(CAPI_ODBCDlg, CDialog)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
........................................................
Разработаем код, который получает данные из базы данных и заполняет ими список. Код упакуем в функцию FillDbToListBox().

Добавьте в класс CAPI_ODBCDlg объявление функцииДобавление в файл API_ODBCDlg.h
class CAPI_ODBCDlg : public CDialog
{
................................................
public:
// Переменная управления списком
CListBox m_ListBox;
// Переменная поля ввода № п/п
int m_NumEdit;
// Переменная поля ввода ФИО
CString m_NameEdit;
// Переменная поля ввода Год
int m_YearEdit;
// Функция заполнения списка данными DB
void FillDbToListBox(void);
};
Добавление в файл API_ODBCDlg.cpp
// Функция заполнения списка данными DB
void CAPI_ODBCDlg::FillDbToListBox(void)
{
}
Добавьте в начало файла API_ODBCDlg.cpp следующее определение структурыДобавление структуры в файл API_ODBCDlg.cpp
// API_ODBCDlg.cpp : implementation file
//
#include "stdafx.h"
#include "API_ODBC.h"
#include "API_ODBCDlg.h"
#include ".\api_odbcdlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
struct RECORD
{
int recNumEdit;// Переменная поля ввода № п/п
CString recNameEdit;// Переменная поля ввода ФИО
int recYearEdit;// Переменная поля ввода Год
};
.......................................................
Добавьте после определения структуры RECORD следующую директиву препроцессораДобавление директивы препроцессора в файл API_ODBCDlg.cpp
......................................................
struct RECORD
{
int recNumEdit;// Переменная поля ввода № п/п
CString recNameEdit;// Переменная поля ввода ФИО
int recYearEdit;// Переменная поля ввода Год
};
#define LEN_BUF 31 // Длина буфера
.......................................................
Найдите функцию OnInitDialog(), сгенерированную мастером, и непосредственно перед оператором return добавьте вызов функции FillDbToListBox(). Эта функция заполнит список на последнем этапе инициализации диалогового окнаДобавление вызова в файл API_ODBCDlg.cpp
BOOL CAPI_ODBCDlg::OnInitDialog()
{
CDialog::OnInitDialog();
.............................................................
// TODO: Add extra initialization here
FillDbToListBox();
return TRUE; // return TRUE unless you set the focus to a control
}
Наполните функцию FillDbToListBox() следующим кодом, реализующим то, о чем было сказано вышеФункция FillDbToListBox() в файле API_ODBCDlg.cpp
// Функция заполнения списка данными DB
void CAPI_ODBCDlg::FillDbToListBox(void)
{
// Объявления дескрипторов и вспомогательных переменных
SQLHENV henv = NULL;
SQLHDBC hdbc = NULL;
SQLHSTMT hstmt = NULL;
bool bIsConnected = false;
SQLRETURN rc;
// Инициализация механизма ODBC среды
rc = SQLAllocHandle(SQL_HANDLE_ENV,
SQL_NULL_HANDLE,
henv);
if(rc != SQL_SUCCESS){
MessageBox("Не могу инициализировать ODBC",
"", MB_OK | MB_ICONSTOP);
return;
}
// Выбор версии ODBC-3
rc = SQLSetEnvAttr(henv,
SQL_ATTR_ODBC_VERSION,
(SQLPOINTER) SQL_OV_ODBC3,
SQL_IS_INTEGER);
if(rc != SQL_SUCCESS){
MessageBox("Не могу установить версию ODBC",
"", MB_OK | MB_ICONSTOP);
return;
}
// Получить от ODBC дескриптор подключения к базе данных
rc = SQLAllocHandle(SQL_HANDLE_DBC, henv, hdbc);
if(rc != SQL_SUCCESS){
MessageBox("Не могу получить дескриптор подключения к БД",
"", MB_OK | MB_ICONSTOP);
return;
}
// Подключить приложение к источнику данных
rc = SQLConnect(hdbc, // Дескриптор подключения
(SQLCHAR*) "MyBase", SQL_NTS, // DSN
(SQLCHAR*) "", SQL_NTS, // Идентификатор пользователя
(SQLCHAR*) "", SQL_NTS); // Пароль для подключения
if(rc != SQL_SUCCESS rc != SQL_SUCCESS_WITH_INFO){
MessageBox("Не могу подключиться к источнику данных",
"", MB_OK | MB_ICONSTOP);
return;
}
bIsConnected = true; // Подняли флаг, что соединение существует
// Получить дескриптор оператора (statement handle)
// для возможности передачи SQL-запросов
rc = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, hstmt);
if(rc != SQL_SUCCESS){
MessageBox("Не могу получить дескриптор оператора",
"", MB_OK | MB_ICONSTOP);
return;
}
// Подготовить и выполнить SQL-запрос (имя таблицы можно без расширения)
LPCSTR szSQL = "SELECT number, name, birth FROM MyTable.dbf";
rc = SQLExecDirect(hstmt, (unsigned char*)szSQL, SQL_NTS);
if(rc != SQL_SUCCESS){
MessageBox("Не могу выполнить SQL-запрос к БД",
"", MB_OK | MB_ICONSTOP);
return;
}
// Связывание полей с переменными приложения
long int cb; // Вспомогательная типа SDWORD
int iNumber;
char strName[LEN_BUF];
int iBirth;
SQLBindCol(hstmt, 1, SQL_INTEGER, iNumber, 0, cb);// Field1
SQLBindCol(hstmt, 2, SQL_CHAR, strName, LEN_BUF, cb);// Field2
SQLBindCol(hstmt, 3, SQL_INTEGER, iBirth, 0, cb);// Field3
// Заполнение списка
rc = SQLFetch(hstmt);
while(rc == SQL_SUCCESS){
RECORD* pRecord = new RECORD;
pRecord->recNumEdit = iNumber;
pRecord->recNameEdit = strName;
pRecord->recYearEdit = iBirth;
CString strTerm;
strTerm.Format("%d %s %d", iNumber, strName, iBirth);
int iIndex = m_ListBox.AddString(strTerm);// Добавить в список
// Сохранить указатель на неименованный экземпляр структуры в списке
m_ListBox.SetItemData(iIndex, (DWORD_PTR)pRecord);
rc = SQLFetch(hstmt); // Дать следующую запись
}
// Освободить все ресурсы ODBC
if(henv){
if(hdbc){
if(bIsConnected){
if(hstmt){
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
}
SQLDisconnect(hdbc);
bIsConnected = false;
}
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
hdbc = NULL;
}
SQLFreeHandle(SQL_HANDLE_ENV, henv);
henv = NULL;
}
}
После завершения работы приложения необходимо вернуть системе память, выделенную динамически под хранение экземпляров структуры RECORD.
В классе CAPI_ODBCDlg переопределите виртуальную функцию DestroyWindow() базового класса CDialog

и разместить в ней следующий код
Код функции DestroyWindow() в файл API_ODBCDlg.cpp
BOOL CAPI_ODBCDlg::DestroyWindow()
{
RECORD* pRecord;
int nCount = m_ListBox.GetCount();
for(int i = 0; i < nCount; i++){
pRecord = (RECORD*)m_ListBox.GetItemData(i);
if(pRecord)
delete pRecord;
}
return CDialog::DestroyWindow();
}
Установим связь между полями ввода Edit Control и списком , добавив обработчик в класс CAPI_ODBCDlg. Для этого:
В панели
Добавьте обработчик для сообщения LBN_SELCHANGE, который заполните таким кодомКод обработчика для списка в файле API_ODBCDlg.cpp
void CAPI_ODBCDlg::OnLbnSelchangeListbox()
{
int iIndex = m_ListBox.GetCurSel();
if(iIndex == LB_ERR) return;
RECORD* pRecord =
(RECORD*)m_ListBox.GetItemData(iIndex);
if(pRecord){
m_NumEdit = pRecord->recNumEdit;
m_NameEdit = pRecord->recNameEdit;
m_YearEdit = pRecord->recYearEdit;
UpdateData(FALSE);
}
}
Добавьте в функцию OnInitDialog() класса CAPI_ODBCDlg после вызова функции FillDbToListBox() заполнение полей ввода значениями первой записиИнициализация полей ввода в файле API_ODBCDlg.cpp
BOOL CAPI_ODBCDlg::OnInitDialog()
{
...............................................
// TODO: Add extra initialization here
FillDbToListBox();
m_ListBox.SetCurSel(0);
OnLbnSelchangeListbox();
return TRUE; // return TRUE unless you set the focus to a control
}
Оформите About со своими фамилиями и номером лабораторной работы
Постройте приложение и проверьте его работу. Результат должен быть примерно таким

Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.