Выбрать главу

Так как из библиотеки импортируется не само тело функции, а ее адрес, то вызов такой функции превращается в непростое дело. Прежде всего, в программе объявляется не сама функция, а переменная, содержащая указатель на нее. Естественно, работа с таким указателем сильно отличается от работы с указателем на число или строку. Ведь функция в отличие от просто переменной возвращает значение и принимает некоторые параметры, поэтому указатель на нее должен быть объявлен специальным образом.

Указатель на функцию, ипортируемую из dll-библиотеки должен также быть скомпилирован со специальным объявлением типа — __declspec(dllimport). Эту строку также удобно представить в виде директивы #define.

#define XDSPINTER_API __declspec(dllimport).

Мы импортируем из библиотеки четыре функции, поэтому необходимо определить их типы: параметры, передаваемые в функцию, возвращаемое значение. Это можно сделать при помощи директивы typedef:

//Объявить тип - указатель на функцию, возвращающую значение типа int и принимающую два

//параметра – массив типа char и число int. В библиотеке ей будет соответствовать функция

// EXPORT int ReadMem(char *data, int len)

typedef XDSPINTER_API int (*MemReadFun)(char *data, int len);

// EXPORT int WriteMem(char *data, int len)

typedef XDSPINTER_API int (*MemWrtFun)(char *data, int len);

// EXPORT int GetMemSize(void)

typedef XDSPINTER_API int (*MemSizeFun)();

//EXPORT bool IsDriverPresent(void)

typedef XDSPINTER_API bool (*IsDrivFun)();

Теперь пришло время создать сами указатели на функции:

MemReadFun ReadMem;

MemWrtFun WriteMem;

MemSizeFun GetMemSize;

IsDrivFun IsDriverPresent;

Теперь рассмотрим функцию, подключающую dll-библиотеку к приложению. Она будет подключать dll-библиотеку к приложению и пытаться установить связь с драйвером. Функция вернет true в случае успеха и false при неудаче. Т.к. VC++ — объектно-ориентированная среда, то эта функция будет методом одного из классов приложения (в нашем случае — класса представления).

bool CXDSPView::ConnectToDriver() {

 //Переменная, в которой будет храниться возвращаемое значение.

 success=true;

 //HMODULE InterDll – переменная экземпляра, где хранится хэндл библиотеки.

 InterDll=::LoadLibrary("XDSPInter");

 if (InterDll==NULL) {

  //Не удалось подключиться к библиотеке

  AfxMessageBox("Couldn't load a library XDSPInter.dll",MB_ICONERROR | MB_OK);

  //Вернем неудачу.

  success=false;

 } else {

  //Библиотека подключена успешно. Импортируем функции.

  ReadMem=(MemReadFun)::GetProcAddress(InterDll,"ReadMem");

  if (ReadMem==NULL) {

   //Не удалось импортировать функцию

   AfxMessageBox("Couldn't get adress for ReadMem function from library XDSPInter.dll", MB_ICONERROR | MB_OK);

   success=false;

  }

  WriteMem=(MemReadFun)::GetProcAddress(InterDll,"WriteMem");

  if (WriteMem==NULL) {

   //Не удалось импортировать функцию

   AfxMessageBox("Couldn't get an adress for WriteMem function from library XDSPInter.dll", MB_ICONERROR | MB_OK);

   success=false;

  }

  GetMemSize=(MemSizeFun)::GetProcAddress(InterDll,"GetMemSize");

  if (GetMemSize==NULL) {

   //Не удалось импортировать функцию AfxMessageBox("Couldn't get an adress for GetMemSize function from library XDSPInter.dll", MB_ICONERROR | MB_OK);

   success=false;

  }

  IsDriverPresent=(IsDrivFun)::GetProcAddress(InterDll,"IsDriverPresent");

  if (IsDriverPresent==NULL) {

   //Не удалось импортировать функцию

   AfxMessageBox("Couldn't get an adress for IsDriverPresent function from library XDSPInter.dll", MB_ICONERROR | MB_OK);

   success=false;

  }

 }

 return(success);

}

Вызов метода ConnectToDriver() целесообразно сделать в конструкторе класса. Там же надо реализовать и проверку, присутствует ли в системе драйвер. Тогда вся необходимая инициализация будет проведена еще при запуске приложения.

CXDSPView::CXDSPView() : CFormView(CXDSPView::IDD) {

 //{{AFX_DATA_INIT(CXDSPView)

 //}}AFX_DATA_INIT

 //Здесь мы добавляем свой код. Success – переменная экземпляра. Если она

 //равна true – то ошибок нет, иначе произошла какая-то ошибка.

 success=true;

 //Пробуем подключить dlclass="underline"

 if (ConnectToDriver()) {

  //Удалось подключить библиотеку. Теперь пытаемся установить связь с

  //драйвером – вызываем функцию в dlclass="underline"

  if (!IsDrvPresent()) {

   //Неудача

   success=false;

   AfxMessageBox("Necessary driver isn't present in the system",MB_ICONERROR | MB_OK);

  }

 } else

  //Не удалось подключиться к dll.

  success=false;

}

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

void CXDSPView::OnRead() {

 int res; //Количество слов, прочитанных из памяти

res=(*ReadMem)(dt,256); //Пытаемся читать 256 слов.

 m_buff.SetWindowText(dt); //Выводим данные на экран

 //Код, характерный для VC++.

 CXDSPDoc *m_doc; //Подключаем документ, связанный с представлением

 m_doc=GetDocument();

 //копируем туда данные.

 strcpy((char*)m_doc->m_buffer,dt);

 //Примечание: оба буфера должны иметь достаточный объем – минимум

 //256*4+1 байт.

}

Аналогично может выглядеть метод записи в память устройство:

void CXDSPView::OnWrite() {

 //Получили данные, введенный пользователем

 m_buff.GetWindowText(dt,32767);

 int res;

 //Записываем его в память устройства. Заметим, что в качестве длины данных

 //мы передаем не длину в байтах, а в 4-байтых словах.

 res=(*WriteMem)(dt,strlen(dt)%4+1);

}

Метод, возвращающий длину памяти устройства, совсем прост и, думаю, в комментариях не нуждается.

int CXDSPView::GetTotalLen() {

 int res=(*GetMemSize)();

 return(res);

}

Также введем еще один метод, который может быть полезным. Он будет очищать память устройства.

void CXDSPView::OnClear() {

 //Получили документ

 CXDSPDoc *m_doc;

 m_doc=GetDocument();

 //Забиваем буфер нулями

 for (int i=0;i<1025;i++) dt[i]=0;

 //Обнуляем буфер в классе документа