[ главная ]   [ рейтинг статей ]   [ справочник радиолюбителя ]   [ новости мира ИТ ]



Ответов: 0
25-02-12 07:01







   Web - программирование
PHP


ASP






XML



CSS

SSI





   Программирование под ОС











   Web - технологии








   Базы Данных









   Графика






Данные




Программирование под ОС / Assembler /

Разработка dll-библиотеки для взаимодействия с драйвером

dll-библиотека (Dynamic Link Library) - программный модуль, который может быть динамически подключен к выполняющемуся процессу. Dll - библиотека может содержать функции и данные. При подключении dll к процессу она отображается на адресное пространство этого процесса.

Если говорить по-русски, то это означает: в любой момент времени программа может загрузить dll-библиотеку, получить указатели на функции и данные этой библиотеки. Потом приложение как-то использует функции и данные библиотеки, и когда они больше не нужны - выгружает библиотеку.

Dll-библиотека содержит два вида функций: внешние (External) и внутренние (Internal). Внутренние функции могут вызываться только самой dll, а внешние может также вызывать приложение, подключившее библиотеку. В этом случае говорят, что dll-библиотека экспортирует функции и данные.

Как было упомянуть выше, в настоящее время для связи с драйвером используется схема Приложение -> Библиотека dll -> Драйвер. При использовании такой архитектуры запрос приложения на операцию ввода-вывода поступает в dll-библиотеку, проходит там предварительную обработку и передается драйверу. Результат, возвращенный драйвером библиотеке dll, также обрабатывается и передается приложению. Преимущества такого подхода очевидны:

  • Выпускается огромное количество различных периферийных устройств, и, соответственно, для каждого устройства разрабатывается свой драйвер. Программисту будет тяжело разбираться во всех тонкостях работы драйвера устройства: формат данных для чтения/записи, запоминать непонятные IOCTL-коды. Гораздо лучше - предоставить для него понятный интерфейс API-функций для работы с устройством. Еще лучше, если такой интерфейс будет унифицированным для всех устройств данного типа. Задача dll-библиотеки, поставляемой с драйвером - связать стандартные интерфейсы, предоставляемые прикладной программе, со специфическими алгоритмами работы драйвера.
  • если в будущем измениться алгоритм взаимодействия приложения с драйвером, то пользователю для работы с новым драйвером будет необходимо обновить только библиотеку dll. Все ранее разработанные программы остануться прежними.
Естественно, такой подход имеет свои минусы. В данном случае за счет большего числа вызовов, через которые проходит запрос на ввод-вывод, снижается быстродействие работы системы.

В нашем случае нам необходимо разработать dll-библиотеку, которая будет предоставлять приложению три функции: чтение памяти, запись в память и получение общего количества памяти устройства. Естественно, dll - библиотеку мы также будем проектировать в среде Visual C++.

Запустите среду VC++ и создайте новый проект с названием XDSPInter. В качестве типа проекта выберите Win32 Dynamic-Link Library. Далее в качестве типа проекта выберите A Simple DLL (простая dll-библиотека). Среда VC++ создаст для Вас пустой проект с одной- единственной функцией DllMain().

Функция DllMain() вызывается при подключении и отключении dll процессом. DllMain() имеет возвращаемое значение BOOL APIENTRY (фактически, она возвращает значение типа BOOL) и три параметра - HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved.

Параметры:

  • HANDLE hModule - дескриптор (хэндл) нашей dll;
  • DWORD ul_reason_for_call - флаг, показывающий, почему была вызвана функция. Может принимать значения:
    • DLL_PROCESS_ATTACH или DLL_THREAD_ATTACH - библиотека подключается к процессу;
    • DLL_PROCESS_DETACH или DLL_THREAD_DETACH - библиотека отключается от процесса.
  • LPVOID lpReserved - зарезервировано.

Функция DllMain() - единственная функция, которая обязательно должна присутствовать в библиотеке. Остальные функции и переменные добавляет программист в соответствии с решаемой задачей.

В нашем случае dll - библиотека будет экспортировать следующие функции: bool IsDriverPresent(void). Функция будет определять, присутствует ли в системе необходимый драйвер и попытаться подключиться к нему. Если это удастся - функция вернет true, в противном случае - false.

int ReadMem(char data, int len) - чтение данных из памяти устройства. Char* data - буфер для данных, int len - число 32-битных слов для чтения. Функция вернет число прочитанных слов.

int WriteMem(char *data, int len) - аналогична предыдущей; запись данных в память.
int GetMemSize(void) - получить объем доступной памяти устройства. Для того, чтобы функция стала экспортируемой, она должна быть скомпилирована со специальным объявлением типа:

extern "C" __declspec (dllexport) 
Для того, чтобы при каждом объявлении функции не писать эту длинную малопонятную строку, определим ее, как директиву препроцессора:
#define EXPORT extern "C" __declspec (dllexport)
Теперь перед каждым объявлением функции просто следует писать слово EXPORT. Создадим заголовочный файл нашей dll-библиотеки, в котором перечислим все экспортируемые функции и директивы препроцессора:
#define EXPORT extern "C" __declspec (dllexport)
EXPORT int ReadMem(char *data, int len);
EXPORT int WriteMem(char *data, int len);
EXPORT int GetMemSize(void);
EXPORT bool IsDriverPresent(void);
Теперь рассмотрим текст исходного срр - файла библиотеки.
//В начале идут включения заголовочных файлов:
#include "stdafx.h" // Основной заголовочный файл MFC
#include "XDSPInter.h" //Наш заголовочный файл

//Определим IOCTL-код для нашего драйвера:
#define XDSPDRV_IOCTL_GETMEMSIZE 0x800

//Введем переменную, которая будет содержать HANDLE драйвера, возвращаемый
//вызовом API CreateFile.
HANDLE hDevice = INVALID_HANDLE_VALUE;

//Также введем строку со значением символической ссылки на наше устройство:
char *sLinkName = "\\.\XDSPdrvDevice0";
//И зарезервируем переменную для хранения объема памяти карточки
UINT dwSize;

//Вспомогательная внутренняя функция OpenByName будет пытаться связаться с
//драйвером.

HANDLE OpenByName(void)
{
// вызов API.
return CreateFile(sLinkName,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
0,
NULL);
//Функция возвращает NULL, если не удалось подключится к драйверу и хэндл
//на него в противном случае.
}

//Далее - функция DllMain:
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
//Определяем, почему была вызвана функция:
switch (ul_reason_for_call)
{
//Приложение подключает библиотеку. Ничего не делаем.
case DLL_PROCESS_ATTACH:
{
break;
}
case DLL_THREAD_ATTACH:
{
break;
}
//Приложение отключает библиотеку.
case DLL_THREAD_DETACH:
{
//Закрыть хэндл драйвера
if (hDevice != INVALID_HANDLE_VALUE)
CloseHandle(hDevice);
hDevice = INVALID_HANDLE_VALUE;
break;
}
case DLL_PROCESS_DETACH:
{
//Закрыть хэндл драйвера
if (hDevice != INVALID_HANDLE_VALUE)
CloseHandle(hDevice);
hDevice = INVALID_HANDLE_VALUE;
break;
}
}
//Все операции завершились успешно. Вернем true.
return TRUE;
}

//Эта внешняя функция будет вызываться приложением, которое захочет установить
//связь с драйвером. Функция вернет true в случае успеха и false при неудаче.
EXPORT bool IsDriverPresent(void)
{
//Попытаемся открыть хэндл драйвера
hDevice=OpenByName();
if (hDevice == INVALID_HANDLE_VALUE)
//неудача
return(false);
else
//Успех.
return(true);
};

//Внешняя функция, производящая чтение памяти устройства. Char* data - буфер для
//данных, int len - число 32-битных слов для чтения. Функция вернет число
//прочитанных слов.
EXPORT int ReadMem(char *data, int len)
{
unsigned long rd=0; //Количество прочитанных слов
//Системный вызов чтения данных из
//файла. В данном случае - из нашего устройства
//len - количество запрашиваемых слов
//rd - количество прочитанных слов.
ReadFile(hDevice, data, len, &rd, NULL);
//Установить последний байт в 0 - признак конца строки.
data[len*4+1]=0;
//Вернуть количество прочитанных слов.
return(rd);
}

//Внешняя функция, производящая запись в память. Практически аналогична
//предыдущей.
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)
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;
//Пробуем подключить dll:
if (ConnectToDriver())
{
//Удалось подключить библиотеку. Теперь пытаемся установить связь с
//драйвером - вызываем функцию в dll:
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;
//Обнуляем буфер в классе документа
m_doc->m_buffer[0]=0;
int res;
//Записывем в память устройства нули
res=(*WriteMem)(dt,256);
//Обновляем данные в окне приложения.
m_buff.SetWindowText(dt);
}
Конечно, написанные нами приложение и dll-библиотека весьма несовершенны. Например, сбои будут происходить, если будут заущены несколько приложений. Тогда они будут одновременно обращаться к одной и той же dll и обновременно работать с устройством. Это может породить множество сбоев. В лучшем случае данные, получаемые каждым из них будут неадекватными. В худшем - система зависнет. Впрочем, этот недостаток можно устранить, модифицировав драйвер способом, описанным выше. Также в нашем приложении производится работа только с первыми 1024 байтами памяти устройства.

Конечно, коммерческая ценность такой системы равна нулю. Но она может быть хорошим учебным примером для ознакомления с программированием WDM - драйверов в Windows и DriverStudio.

 

2.6 Отладка драйверов

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

Если, например, разрабатывать драйвер под ОС Linux, то ситуация там может быть немного хуже: в этой ОС вообще нет какой-либо возможности отлаживать драйвера, кроме как воспользоваться отладчиком gdb. Но в таком случае надо перекомпилировать ядро системы специальным образом и станцевать еще несколько подобных танцев с бубном. Поэтому зачастую отладка сводится к вызову функций printk, которые в великом множестве раскиданы по всему ядру системы.

К счастью, хоть в этом Windows имеет преимущества. Для того, чтобы можно было отлаживать драйвера, отладчик должен сам работать в нулевом кольце защиты. Естественно, разработка такой программы является чрезвычайно сложной задачей, поэтому таких отладчиков на сегодняшний день известно всего два: WinDbg (поставляется с пакетом DDK) и SoftIce (входит в состав NuMega DriverStudio). SoftIce считается одним из лучших отладчиков для Windows всех типов. Это надежный, мощный и довольно удобный в использовании инструмент. SoftIce может применяться для различных целей: для отладки драйверов и приложений пользователя, для просмотра информации о системе и т.п. Мы рассмотрим, как применять SoftIce для отладки драйверов устройств.

Будучи установленным в Win98, SoftIce прописывает в Autoexec.bat строку вида: c:Progra~1\numegadriver~1softicewinice

Т.е. SoftIce загружается после загрузки DOS и сам грузит Windows. При работе Windows SoftIce активизируется лишь при каком-нибудь системном исключении или в точке останова, заданной программистом в драйвере. Также вызвать SoftIce можно, нажав Ctrl+D. На экране появляется окно отладчика.

Пока окно SoftIce активно, вся деятельность ОС замирает; именно сейчас можно безболезненно отлаживать драйвера.

Окно SoftIce разбито на несколько окон. Обычно в центре видно окно кода, над ним - окно регистров процессора и в самом низу - окно сообщений. Перемещаться в пределах окна можно, используя клавиши управления курсором или мышь.

В самом низу окна SoftIce расположена командная строка. SoftIce не имеет графического интерфейса, и все команды управления отладчиком вводятся в командной строке. SoftIce имеет довольно неплохую систему помощи. Перечень команд выдается по команде help. Наверное, самая важная команда - это команда выхода из SoftIce. Для этого нужно нажать клавишу F5 или дать команду Х (регистр не имеет значения).

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

Но, естественно, программисту мало простого чтения сообщений, посланных драйвером. Для эффективной отладки любой программы надо установить точку останова (breakpoint), просмотреть значения регистров. К счастью, SoftIce предоставляет такую возможность.

Универсальной точкой останова является использование прерывания INT 3. Как и в ОС MS-DOS, в Windows INT 3 также является прерыванием отладки. Для этого в тексте драйвера, где необходимо установить breakpoint, необходимо вставить следующий код:

    _asm
{
int 3
}
При этом присходит вызов прерывания INT 3.

Но по умолчанию SoftIce не реагирует на INT 3. Для того, чтобы по этому прерыванию активизировался отладчик, необходимо вызвать SoftIce и дать команду:

SET I3HERE ON

Теперь при вызове INT 3 произойдет <всплывание> этого кода в отладчике. Для отключения режима отладки по INT 3 следует дать команду SET I3HERE OFF.

После того, как наш драйвер <всплыл> в SoftIce, мы можем контролировать выполнение программы при помощи команд:

HERE (F7)
шаг на следующую строку в окне кода;
T F8
выполнить одну инструкцию процессора (трассировка);
HBOOT
перезагрузка системы;
G
перейти на указанный адрес;
GENINT
сгенерировать прерывание;
X  F5
продолжить выполнение программы (выход из SoftIce).
Если драйвер был скомпилирован в отладочной конфигурации, то на экране будет виден текст драйвера, написанный на С++.

SoftIce также может просматривать значения переменных пользователя. Для того, чтобы открыть/закрыть окно просмотра переменных (Watch), надо дать команду WW или нажать Alt+F4. Добавить/убрать переменную для просмотра можно при по- мощи команды WATCH.

Это основные команды, применяемые для отладки драйверов устройств в SoftIce. А в общем, этот отладчик имеет огромное количество функциональных возможностей и его пол- ное описание пославляется с программой и занимает порядка двухсот страниц. Надеюсь, это руководство было для Вас интересно. Если даже не интересно - то, надеюсь, Вы узнали что-то новое для себя.




Комментарии

 Ваш комментарий к данному материалу будет интересен нам и нашим читателям!



Последние статьи: Программирование под ОС / Assembler /

Первая программа на linux
23-05-2010   

Ассемблер, который я буду использовать - NASM (Netwide Assembler, nasm.2y.net). Этот выбор объясняется тем, что: Во первых, он мультиплатформенный, т.е. для портирования программы на разные ОС достаточно только изменить код взаимодействия с системой, а всю программу переписывать не нужно... подробнее

Кол. просмотров: общее - 3504 сегодня - 3

Использование пакета NuMega Driver Studio для написания WDM - драйверов устройств
17-05-2010   

Разработка WDM - драйвера с использованием только DDK является сложной и трудоемкой задачей. При этом приходится выполнять много однотипных операций: создание скелета драйвера, написание inf - файла для его установки, создание приложения для тестирования и т.п... подробнее

Кол. просмотров: общее - 3053 сегодня - 4

Система классов DriverWorks
17-05-2010   

Возможно, идея писать драйвера объектно-ориентированными и кажется на первый взгляд нелогичной. Но при более близком знакомстве с DriverStudio и с драйверами в общем, оказывается, что это не так уж страшно и довольно удобно... подробнее

Кол. просмотров: общее - 3154 сегодня - 3

Объект устройства device object
17-05-2010   

Объекты устройств являются экземплярами класса KDevice или KPnpDevice. Эти классы являются краеугольными камнями архитектуры DriverWorks: они представляют собой как бы программный образ тех устройств, которые присутствуют в системе... подробнее

Кол. просмотров: общее - 3175 сегодня - 4

Объекты для управления оборудованием
17-05-2010   

Как было упомянуто выше, объект устройства управляет работой устройства при помощи специальных объектов, управляющих работой оборудования - портами В/В, прерываниями, памятью, контроллерами ПДП. Драйвер создает эти объекты для представления физических параметров устройства... подробнее

Кол. просмотров: общее - 3367 сегодня - 3



  WWW.COMPROG.RU - 2009-2012 | Designed and Powered by Zaipov Renat | Projects