EXPORT int WriteMem(char *data, int len) {
unsigned long nWritten=0;
WriteFile(hDevice, data, len, &nWritten, NULL);
//len – количество запрашиваемых слов
//nWritten – количество прочитанных слов.
return nWritten;
}
//Эта функция возвращает количество памяти устройства, байт.
EXPORT int GetMemSize(void) {
CHAR bufInput[4]; // Это пустой входной буфер, который будет
//передан устройсву
unsigned long bufOutput; //Буфер, куда драйвер запишет результат.
ULONG nOutput; //Длина возвращенных драйвером данных, байт
// Вызвать функцию device IO Control с кодом XDSPDRV_IOCTL_GETMEMSIZE
if (!DeviceIoControl(hDevice, XDSPDRV_IOCTL_GETMEMSIZE, bufInput, 4, &bufOutput, 4, &nOutput, NULL)) return(0); //Неудача
else return(bufOutput); //Кол-во памяти
}
Таким образом, наша библиотека экпортирует всего четыре функции для работы с устройством. Все они имеют простой синтаксис и просты в использовании. Использование dll в нашем случае позволяет программисту не думать о сложных системных вызовах, необходимых для общения с драйвером, о формате передаваемых ему данных, а сосредоточится на решении прикладных задач.
2.5 Подключение dll-библиотеки к приложению.
После того, как написан драйвер и dll-библиотека для работы с ним, пришло время написать приложение пользоваеля, работающее с устройством. Оно будет взаимодействовать с драйвером через dll-библиотеку. Естественно, написано оно также будет в среде Visual C++. В принципе, его можно было бы реализовать в среде Visual Basic, Delphi или CВuilder, но это приведет к некоторым трудностям, прежде всего в использовании системных вызовов и структур данных. В данном разделе, в отличие от предыдущих, не рассматривается какое-либо конкретное приложение, а даются общие рекомендации по написанию такой программы.
Подключение библиотеки к приложению не требует особых усилий. Библиотека подключается при помощи системного вызова HMODULE LoadLibrary(char* LibraryName), где LibraryName — строка с именем файла dll-библиотеки. Возвращаемое значение — хендл (дескриптор) бибилиотеки. Если функция возвратила NULL, то произошла ошибка при подключении библиотеки.
После подключения библиотеки можно из нее импортировать функции. Импорт функции производится при помощи системного вызова
FARPROC GetProcAdress(HMODULE hModule, char * ProcName)
• hModule — хэндл библиотеки, возвращенный LoadLibrary;
• ProcName — строка с именем импортируемой функции. Вызов GetProcAdress возвращает адрес функции с заданным именем и NULL, если такой функции нет в библиотеке.
Так как из библиотеки импортируется не само тело функции, а ее адрес, то вызов такой функции превращается в непростое дело. Прежде всего, в программе объявляется не сама функция, а переменная, содержащая указатель на нее. Естественно, работа с таким указателем сильно отличается от работы с указателем на число или строку. Ведь функция в отличие от просто переменной возвращает значение и принимает некоторые параметры, поэтому указатель на нее должен быть объявлен специальным образом.
Указатель на функцию, ипортируемую из 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)