Windows98/2000驱动程序编写方法 (下) 杨全胜.

Slides:



Advertisements
Similar presentations
7.1 内置对象概述及分类 JSP 视频教学课程. JSP2.2 目录 1. 内置对象简介 1. 内置对象简介 2. 内置对象分类 2. 内置对象分类 3. 内置对象按功能区分 3. 内置对象按功能区分 4. 内置对象作用范围 4. 内置对象作用范围.
Advertisements

6 Copyright © Oracle Corporation, All rights reserved. 维护控制文件.
Windows XP驱动程序编写方法 ——Step by Step
Adam Shapiro Senior Program Manager US-Networking Core PM
第8章 机床操作 主讲:臧红彬 博士.
Oracle数据库 Oracle 子程序.
第二章 JAVA语言基础.
C++中的声音处理 在传统Turbo C环境中,如果想用C语言控制电脑发声,可以用Sound函数。在VC6.6环境中如果想控制电脑发声则采用Beep函数。原型为: Beep(频率,持续时间) , 单位毫秒 暂停程序执行使用Sleep函数 Sleep(持续时间), 单位毫秒 引用这两个函数时,必须包含头文件
在PHP和MYSQL中实现完美的中文显示
第九章 字符串.
J2EE与中间件技术 ——Lab.
Using C++ The Weird Way Something about c++11 & OOP tricks
Kvm异步缺页中断 浙江大学计算机体系结构实验室 徐浩.
Hadoop I/O By ShiChaojie.
一个端口访问器的编写 — Windows XP驱动程序举例 VS.NET+WIN XP DDK+DriverStudio3.2开发环境版
第二讲 搭建Java Web开发环境 主讲人:孙娜
学习前的准备工作 讲师:burning.
第八章 菜单设计 §8.1 Visual FoxPro 系统菜单 §8.2 为自己的程序添加菜单 §8.3 创建快捷菜单.
把COM口设置到没有使用的 COM1 – COM4
大学计算机基础 典型案例之一 构建FPT服务器.
走进编程 程序的顺序结构(二).
辅导课程六.
MFC WinSock类的编程 为简化套接字网络编程,更方便地利用Windows的消息驱动机制,微软的基础类库(Microsoft Foundation Class Libary,简称MFC),提供了两个套接字类,在不同的层次上对Windows Socket API函数进行了封装,为编写Windows.
SPI驱动 广州创龙电子科技有限公司 Guangzhou Tronlong Electronic Technology Co., Ltd.
Zhao4zhong1 (赵中) C语言指针与汇编语言地址.
Zhao4zhong1 (赵中) C语言指针与汇编语言地址.
第一单元 初识C程序与C程序开发平台搭建 ---观其大略
I2C驱动 广州创龙电子科技有限公司 Guangzhou Tronlong Electronic Technology Co., Ltd.
文件读写实践 广州创龙电子科技有限公司 01 广州创龙电子科技有限公司
第十章 IDL访问数据库 10.1 数据库与数据库访问 1、数据库 数据库中数据的组织由低到高分为四级:字段、记录、表、数据库四种。
本节内容 模拟线程切换 视频提供:昆山滴水信息技术有限公司 官网地址: 论坛地址: QQ交流 :
逆向工程-汇编语言
如何生成设备节点 广州创龙电子科技有限公司
China’s Software Industry August 2006 Instructor: Hengming Zou, Ph.D.
C++语言程序设计 C++语言程序设计 第七章 类与对象 第十一组 C++语言程序设计.
Windows 7 的系统设置.
用event class 从input的root文件中,由DmpDataBuffer::ReadObject读取数据的问题
第七章 操作符重载 胡昊 南京大学计算机系软件所.
Java语言程序设计 清华大学出版社 第8章 输入输出流(1).
程序设计工具实习 Software Program Tool
C++语言程序设计 C++语言程序设计 第七章 类与对象 第十一组 C++语言程序设计.
程式結構&語法.
Web安全基础教程
本节内容 随机读取 视频提供:昆山爱达人信息技术有限公司.
Platform Builder使用介绍 WINCE系统应用开发流程说明 ACTION RDC 杨 涛 2005.Dec.3th
VB与Access数据库的连接.
姚金宇 MIT SCHEME 使用说明 姚金宇
实验七 安全FTP服务器实验 2019/4/28.
本节内容 Win32 API中的宽字符 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
第4章 Excel电子表格制作软件 4.4 函数(一).
iSIGHT 基本培训 使用 Excel的栅栏问题
_13简单的GDI绘图操作 本节课讲师——void* 视频提供:昆山爱达人信息技术有限公司 官网地址:
LOGIX500软件入门 西安华光信息技术有限公司 2008年7月11日.
本节内容 文件系统 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
多层循环 Private Sub Command1_Click() Dim i As Integer, j As Integer
本节内容 C语言的汇编表示 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
C++语言程序设计 C++语言程序设计 第十一章 异常处理 C++语言程序设计.
Python 环境搭建 基于Anaconda和VSCode.
C++语言程序设计 C++语言程序设计 第一章 C++语言概述 第十一组 C++语言程序设计.
本节内容 动态链接库 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
第8章 创建与使用图块 将一个或多个单一的实体对象整合为一个对象,这个对象就是图块。图块中的各实体可以具有各自的图层、线性、颜色等特征。在应用时,图块作为一个独立的、完整的对象进行操作,可以根据需要按一定比例和角度将图块插入到需要的位置。 2019/6/30.
本节内容 如何调试驱动程序? 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
本节内容 进程 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
使用ADO访问数据库 李宝智 BonizLee 课程 10564A
FVX1100介绍 法视特(上海)图像科技有限公司 施 俊.
创建、启动和关闭Activity 本讲大纲: 1、创建Activity 2、配置Activity 3、启动和关闭Activity
使用Fragment 本讲大纲: 1、创建Fragment 2、在Activity中添加Fragment
本节内容 this指针 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
Presentation transcript:

Windows98/2000驱动程序编写方法 (下) 杨全胜

4.Driver Works的使用 1)生成简单框架

工程文件名 工程文件目录

选择驱动类型

创建功能驱动程序 创建过滤器驱动程序

本例不驱动硬件 选择相应总线

驱动类名称 驱动类文件名

选择需要处理的消息句柄

添加和应用程序之间通信的控制代码

测试用应用程序名称

驱动类 设备类

驱动类文件 设备类文件 驱动安装指导文件 测试用的控制台程序文件

此时已经具备了一个驱动程序以及做测试用的应用程序的基本框架,我们可以在VC集成环境下修改有关程序,增加相关的具体操作代码,然后就可以编译和调试了。

该驱动程序框架包含了几个最基本的类,这些类是: class Sample : public KDriver // 驱动程序类,用于初始化驱动程序 { SAFE_DESTRUCTORS public: // 以下成员函数注意和WDM中有关例程联系起来看 virtual NTSTATUS DriverEntry(PUNICODE_STRING RegistryPath); virtual NTSTATUS AddDevice(PDEVICE_OBJECT Pdo); void LoadRegistryParameters(KRegistryKey &Params); int m_Unit; // The following data members are loaded from the registry during DriverEntry ULONG m_bBreakOnEntry; };

class SampleDevice : public KPnpDevice // 是设备类KDvice的派生类,用于在WDM环境下支持即插即用设备 { // Constructors public: SAFE_DESTRUCTORS; SampleDevice(PDEVICE_OBJECT Pdo, ULONG Unit); ~SampleDevice(); // Member Functions 注意和PNP的次功能代码联系起来看 DEVMEMBER_DISPATCHERS virtual NTSTATUS OnStartDevice(KIrp I); virtual NTSTATUS OnStopDevice(KIrp I); virtual NTSTATUS OnRemoveDevice(KIrp I); virtual NTSTATUS DefaultPnp(KIrp I); virtual NTSTATUS DefaultPower(KIrp I); virtual NTSTATUS OnDevicePowerUp(KIrp I); virtual NTSTATUS OnDeviceSleep(KIrp I); void SerialRead(KIrp I); void SerialWrite(KIrp I);

NTSTATUS SAMPLE_IOCTL_Read_Handler(KIrp I); NTSTATUS SAMPLE_IOCTL_Write_Handler(KIrp I); NTSTATUS SAMPLE_IOCTL_ReadWrite_Handler(KIrp I); #ifdef _COMMENT_ONLY virtual NTSTATUS Create(KIrp I); virtual NTSTATUS Close(KIrp I); virtual NTSTATUS DeviceControl(KIrp I); virtual NTSTATUS SystemControl(KIrp I); virtual NTSTATUS Read(KIrp I); virtual NTSTATUS Write(KIrp I); #endif // Member Data protected: // Unit number for this device (0-9) ULONG m_Unit; KPnpLowerDevice m_Lower; SampleDevice_DriverManagedQueue m_DriverManagedQueue; // TODO: Create additional driver managed queues. These might be // of the same class (SampleDevice_DriverManagedQueue), // or you might choose to derive another class. };

下面我们讲解编译、执行和调试这个驱动程序。 先编译驱动程序工程 在VC的集成环境中

再编译测试应用程序工程

驱动程序监视,可实时看到驱动程序发出的调试输出语句 下面使用DriverStudio带的工具加载驱动程序和查看调试信息。 驱动程序监视,可实时看到驱动程序发出的调试输出语句 驱动程序装载器,可动态调用驱动程序

驱动程序监视器界面

驱动程序装载器界面

2)完成应用程序和驱动程序之间的信息交换 下面我们来修改有关代码,以便增加驱动程序和应用程序之间相互通信的内容。需要增加的内容包括: 使用Read和Write方式分别从驱动程序读入字符和 向驱动程序写字符。 使用IO控制代码方式分别从驱动程序读入字符和 向驱动程序写字符。 使用IO控制代码方式向驱动程序写字符串再从驱动程序中读出该字符串,并返回反馈串信息。 注意:程序中暗红色显示的部分是我们添加或修改过的语句,其他是DriverWorks自动生成的。语句中“t<< xxxxx”这样的语句是向调试软件输出信息,该信息可以再DriverMonitor或其他调试监视器中看到。

使用Read和Write方式分别读写 SampleDevice.cpp void SampleDevice::SerialRead(KIrp I) { t << "Entering SampleDevice::SerialRead, " << I << EOL; NTSTATUS status = STATUS_SUCCESS; PUCHAR pBuffer = (PUCHAR) I.BufferedReadDest();//取得返回数据BUFF的指针 ULONG dwTotalSize = I.ReadSize(CURRENT); // Requested read size char buff[512]; int n =512, j = (n % 26); for (int i=0; i<n; i++, j=(j + 1)%26) { buff[i] = 'a' + j; } buff[dwTotalSize]=‘\0’; //指定串尾 strcpy((char *)pBuffer,buff); // 把给应用程序的数据拷贝给返回BUFF t << “The string you will read is \”“ << buff << ”\“” << EOL; // 输出调试信息 ULONG dwBytesRead = strlen(buff); // Count of bytes read I.Information() = dwBytesRead; // 返回给应用程序的信息的字节个数 I.Status() = status; m_DriverManagedQueue.PnpNextIrp(I); }

void SampleDevice::SerialWrite(KIrp I) { t << "Entering SampleDevice::SerialWrite, " << I << EOL; NTSTATUS status = STATUS_SUCCESS; PUCHAR pBuffer = (PUCHAR)I.BufferedWriteSource();//取得存放应用程序写给驱动程序的数据的BUFF的指针 ULONG dwTotalSize = I.WriteSize(CURRENT);// 获得应用程序写给驱动程序的信息的字节数。 ULONG dwBytesSent = dwTotalSize; char buff[512]; strcpy(buff, (char *)pBuffer); // 应用程序写给驱动程序的数据在I.BufferedWriteSource()返回的指针中。 buff[dwBytesSent] = '\0'; t << "Write to driver is \"" << buff << "\"" << EOL; I.Information() = dwBytesSent; // 返回用户实际写的字节数 I.Status() = status; m_DriverManagedQueue.PnpNextIrp(I); }

Test_Sample.cpp void doRead(int n) // 从驱动程序中读数据 { char *buf; ULONG nRead; int i, j; buf = (char *) malloc(n); if (buf == NULL) printf("Failed to allocate buffer for read"); Exit(1); } // Read data from driver printf("Reading from device - "); ReadFile(hDevice, buf, n, &nRead, NULL); // 参数分别是设备句柄、输入缓冲地址、缓冲大小(字节数)、实际读的数据字节数、覆盖结构指针。

printf("%d bytes read from device (%d requested).\n", nRead, nRead); // Print what was read while(i < nRead) { // j = min((i+26),n); // for(; i < j; i++) // { // printf("%c, ", buf[i]); // } // printf("\n"); printf("%c, ",buf[i++]); } printf("\n"); free(buf); 这几句删除

void doWrite(int n) // 向驱动程序中写数据 { char *buf; ULONG nWritten; int i, j; buf = (char *) malloc(n); if (buf == NULL) printf("Failed to allocate buffer for write"); Exit(1); } // start with the mod26 letter of the number of bytes to write j = (n % 26); // load buffer with dummy data (abcdefg...) for (i=0; i<n; i++, j=(j + 1)%26) buf[i] = 'a' + j;

// Write data to driver printf("Writing to device - "); WriteFile(hDevice, buf, n, &nWritten, NULL); // 写数据,参数的含义是驱动程序句柄、写缓冲、写缓冲大小、实际驱动程序得到的信息的字节数、覆盖结构指针。 printf("%d bytes written to device (%d attempted).\n", nWritten, n); i = 0; // Print what was written while(i < n) { j = min((i+26),n); for(; i < j; i++) { printf("%c, ", buf[i]); } printf("\n"); free(buf);

b. 使用IO控制代码方式分别读写 SampleDevice.cpp NTSTATUS SampleDevice::SAMPLE_IOCTL_Read_Handler(KIrp I) { // 对应用程序读驱动程序的请求作响应 NTSTATUS status = STATUS_SUCCESS; t << "Entering SampleDevice::SAMPLE_IOCTL_Read_Handler, " << I << EOL; char buff1[512]; ULONG fwLength=0; strcpy(buff1,"Welcome to driver!"); fwLength = strlen(buff1)+1; if (I.IoctlOutputBufferSize() >= fwLength) {// 如果读入缓冲够长 strcpy((PCHAR)I.IoctlBuffer(),buff1); // 将信息拷给应用程序读入缓冲 I.Information() = fwLength; // 返回信息长度 } else { I.Information() = 0; // 否则信息长度为0 t << "buff size too small" << EOL; return status;

NTSTATUS SampleDevice::SAMPLE_IOCTL_Write_Handler(KIrp I) { // 接受从应用程序中来的信息 NTSTATUS status = STATUS_SUCCESS; t << "Entering SampleDevice :: SAMPLE_IOCTL_Write_Handler , " << I << EOL; char buff[512]; ULONG fwLength=0; strcpy(buff,(PCHAR)I.IoctlBuffer()); // 拷贝从应用程序得到的命令串到驱动程序局部数据区 t << “InputPut Data is \”“ << buff << ”\“” <<EOL; // 显示从应用程序得到的命令串。 I.Information() = 0; return status; }

Test_Sample.cpp void Test_SAMPLE_IOCTL_Read(void) { CHAR bufInput[IOCTL_INBUF_SIZE]; // Input to device CHAR bufOutput[IOCTL_OUTBUF_SIZE]; // Output from device ULONG nOutput; // Count written to bufOutput // Call device IO Control interface (SAMPLE_IOCTL_Read) in driver printf("Issuing Ioctl to device - "); strcpy(bufInput,"This is a sample."); if (!DeviceIoControl(hDevice,SAMPLE_IOCTL_Read, NULL, 0, bufOutput, IOCTL_OUTBUF_SIZE, &nOutput, NULL)) printf("ERROR: DeviceIoControl returns %0x.", GetLastError()); Exit(1); } else printf("Return from driver is \"%s\"(%d)",bufOutput,nOutput);

void Test_SAMPLE_IOCTL_Write(void) { CHAR bufInput[IOCTL_INBUF_SIZE]; // Input to device CHAR bufOutput[IOCTL_OUTBUF_SIZE];// Output from device ULONG nOutput; // Count written to bufOutput // Call device IO Control interface (SAMPLE_IOCTL_Write) in driver printf("Issuing Ioctl to device - "); strcpy(bufInput,"Now let us write this string."); if (!DeviceIoControl(hDevice, SAMPLE_IOCTL_Write, bufInput, strlen(bufInput), NULL, 0, &nOutput, NULL)) // 该函数参数分别是设备句柄、IO控制命令、写缓冲、写缓冲大小、读缓冲、读缓冲大小、实际读的字节数、覆盖结构指针(注意,这里的bufInput是指Input到设备,所以对应用软件这是写缓冲, bufOutput是从设备output到应用程序,是读缓冲。 printf("ERROR: DeviceIoControl returns %0x.", GetLastError()); Exit(1); }

c. 使用IO控制代码方式写并且读 SampleDevice.cpp NTSTATUS SampleDevice::SAMPLE_IOCTL_ReadWrite_Handler(KIrp I) { NTSTATUS status = STATUS_SUCCESS; t << "Entering SampleDevice::SAMPLE_IOCTL_ReadWrite_Handler, " << I << EOL; char buff[512],buff1[512]; ULONG fwLength=0; strcpy(buff,(PCHAR)I.IoctlBuffer());// 拷贝应用程序来的信息 t << "InputPut Data is \"" << buff << "\"" <<EOL; strcpy(buff1,"this is feedback from driver! Application give me this string \""); strcat(buff1,buff); strcat(buff1,“\”“); // 以上是组织反馈的信息

fwLength = strlen(buff1)+1; if (I.IoctlOutputBufferSize() >= fwLength) { strcpy((PCHAR)I.IoctlBuffer(),buff1);// 拷贝反馈信息 I.Information() = fwLength; // 设置反馈信息字节数 } else I.Information() = 0; t << "buff size too small" << EOL; return status;

Test_Sample.cpp void Test_SAMPLE_IOCTL_ReadWrite(void) { bufOutput is written by the device to return data to this application CHAR bufInput[IOCTL_INBUF_SIZE]; // Input to device CHAR bufOutput[IOCTL_OUTBUF_SIZE]; // Output from device ULONG nOutput; // Count written to bufOutput // Call device IO Control interface (SAMPLE_IOCTL_ReadWrite) in driver printf("Issuing Ioctl to device - "); strcpy(bufInput,"This is a sample."); if (!DeviceIoControl(hDevice, SAMPLE_IOCTL_ReadWrite, bufInput, strlen(bufInput),bufOutput, IOCTL_OUTBUF_SIZE, &nOutput, NULL) ) printf("ERROR: DeviceIoControl returns %0x.", GetLastError()); Exit(1); } else printf("Feedback is \"%s\"(%d)",bufOutput,nOutput);

3)直接对端口寄存器读写 DriverStudio提供了KIoRange类来将外部总线的I/O地址空间范围映射到处理器总线的地址空间范围。 该类的成员函数主要有 KIoRange 构造函数 (4 种格式) Initialize 初始化和重新初始化一个实例 (3种格式) ~KIoRange 析构函数 Invalidate 从已初始化状态删除该对象 IsValid 测试该对象是否已经初始化 inb 读一个或多个字节 (2 种形式) Outb 写一个或多个字节 (2 种形式) Inw 读一个或多个字 (2 种形式) Outw 写一个或多个字 (2 种形式) ind 读一个或多个双字 (2 种形式) outd 写一个或多个双字 (2 种形式)

KIoRange::KIoRange(只介绍WDM形式) FORM 3 (WDM): KIoRange(    ULONGLONG CpuPhysicalAddress, //转换成外围设备地址的CPU总线上的物理地址    BOOLEAN InCpuIoSpace, //如果IO范围是在CPU总线的IO空间中为TRUE,否则为FALSE    ULONG Count, //以字节计的区域的大小    BOOLEAN MapToSystemVirtual =TRUE//指定是否需要构造函数创建一个非页系统空间的地址空间映射,如果驱动程序读写设备中的数据,就需要这种映射 ); FORM 4 (WDM): (注意: 这种形式不被 DriverStudio 2.0支持。) KIoRange(    PCM_RESOURCE_LIST pTranslatedResourceList, //指向转换资源表的指针    ULONG Ordinal=0, //指定pTranslatedResourceList指向的资源列表中的一个特殊端口资源    BOOLEAN MapToSystemVirtual =TRUE ); FORM 5 (WDM): KIoRange(    PCM_RESOURCE_LIST pTranslatedResourceList, //可通过KIrp::TranslatedResources获得    PCM_RESOURCE_LIST pRawResourceList, //指向原始资源表的指针    ULONG Ordinal=0,    BOOLEAN MapToSystemVirtual =TRUE );构造 KIoRange类。

KIoRange::Initialize (只介绍WDM形式) FORM 2 (WDM): NTSTATUS Initialize(    ULONGLONG CpuPhysicalAddress,    BOOLEAN InCpuIoSpace,    ULONG Count,    BOOLEAN MapToSystemVirtual=TRUE ); FORM 3 (WDM): (注意: 这种形式不被 DriverStudio 2.0支持。) NTSTATUS Initialize(    PCM_RESOURCE_LIST pTranslatedResourceList,    ULONG Ordinal=0,    BOOLEAN MapToSystemVirtual =TRUE ); FORM 4 (WDM): Initialize(    PCM_RESOURCE_LIST pTranslatedResourceList,    PCM_RESOURCE_LIST pRawResourceList,    ULONG Ordinal=0,    BOOLEAN MapToSystemVirtual =TRUE ); 初始化或重新初始化KIoRange的实例。

KIoRange::inb FORM 1: UCHAR inb( ULONG ByteOffset ); FORM 2: VOID inb(    ULONG ByteOffset,    PUCHAR Buffer,    ULONG Count ); 从映射空间读一个或多个字节。

KIoRange::outb FORM 1: VOID outb(    ULONG ByteOffset,//以字节为单位的目标位置到IO空间开始位置的偏移值   UCHAR Data //要写的一个字节数据 ); FORM 2: VOID outb(    ULONG ByteOffset,    PUCHAR Buffer,//指向包含要写数据的缓冲的指针   ULONG Count //缓冲中要写数据的字节数 写一个或多个字节到映射的IO空间。

下面我们来访问CMOS的数据。 首先定义类KIoRange的一个实例,以定义相关地址空间。 KIoRange m_ParPortIos; 初始化实例(指定CMOS的端口首地址,并映射) status = m_ParPortIos.Initialize( 0x70, // CMOS端口首地址是70H TRUE, //在CPU I/O空间内 8, // 设备读写数据的字节宽度 TRUE // 映射到系统空间 ); 写端口( 索引信息, 地址70H)m_ParPortIos.outb(0,0x02); // 准备读分钟信息 读端口(读分钟信息,地址71H) UCHAR data = m_ParPortIos.inb(1);

4)截获中断和挂接中断服务例程 DriverStudio提供了KInterrupt类来截获和挂接中断。 该类的成员函数主要有 KInterrupt 构造函数(3种格式) Initialize 在无效状态下初始化一个对象 (3种格式) Connect 绑定ISR(中断服务例程)到中断 InitializeAndConnect 一步完成初始化与绑定工作,要用资源列表作为输入。 ~KInterrupt 析构函数 Invalidate 在初始化状态下删除对象 IsValid 检查对象是否初始化 Disconnect 使中断和ISR与中断分离 Synchronize 当得到一个中断自旋锁时请求同步功能

KInterrupt::KInterrupt(只介绍WDM形式) FORM 3: (WDM) KInterrupt(    KIRQL irql, //即插即用设备提供的IRQL值    ULONG vector, //即插即用设备提供的向量值    KINTERRUPT_MODE Mode,//LevelSensitive 或 Latched中选一.    BOOLEAN bShareVector=FALSE, //该向量是否被几个设备共享    KAFFINITY affinity=1, //this is the processor affinity mask.    BOOLEAN bSaveFloat =FALSE //是否需要在中断到来使保存浮点处理器上下文,X86平台下必须使FALSE ); 构造类Kinterrupt的实例。

KInterrupt::Initialize(只介绍WDM形式) FORM 2: (WDM) VOID    Initialize(    KIRQL irql,    ULONG vector,    KINTERRUPT_MODE Mode,    BOOLEAN bShareVector=FALSE,    KAFFINITY affinity=1,    BOOLEAN bSaveFloat=FALSE ); 初始化对象。只在对象没有初始化的时候使用。

KInterrupt::Connect FORM 1: NTSTATUS Connect(    PKSERVICE_ROUTINE Isr, //作为ISR服务的函数的地址    PVOID Context //当系统调用ISR的时候传递给他的无类型的参数 ); FORM 2: NTSTATUS Connect(    PKSERVICE_ROUTINE Isr,    PVOID Context,    PKSPIN_LOCK pSpin,    KIRQL SynchIrql ); 绑定一个中断到ISR(中断处理程序)。

KInterrupt::InitializeAndConnect NTSTATUS InitializeAndConnect(    PCM_RESOURCE_LIST pResourceList, //指向资源列表的指针    PKSERVICE_ROUTINE Isr,    PVOID IsrContext,    ULONG Ordinal=0,    BOOLEAN bSaveFloat=FALSE ); 初始化一个中断并绑定到一个ISR上。 对于 WDM 驱动程序,pResourceList 必须是一个转换资源表,例如是KIrp::TranslatedResources的返回值。

下面我们来举例说明。 首先定义类KInterrupt的一个实例 KInterrupt m_TheInterrupt; 在设备类中声明一个成员函数TheIsr作为中断服务例程ISR。 class SampleDevice : public KPnpDevice { …… public: MEMBER_ISR (SampleDevice, TheIsr); …… #ifdef _COMMENT_ONLY BOOLEAN TheIsr(void){ return TRUE ; }; #endif …… }

在OnStartDevice例程中获取包括中断的设备资源并初始化中断和挂接ISR SampleDevice ::OnStartDevice(KIrp I) { …… PCM_RESOURCE_LIST pResList = I.TranslatedResources(); //获取设备资源 //初始化中断并挂接中断服务例程TheIsr status = m_TheInterrupt.InitializeAndConnect( pResList, LinkTo(TheIsr), this ); }

DriverStudio自动生成的驱动程序的测试程序是一个控制台程序,下面我们将利用该控制台程序来写一个Win32的程序。 第一步,在由DriverStudio自动生成一个驱动程序工作区(Workspace)中添加一个新的子工程,该子工程指定为一个MFC的EXE程序。 右键点击

第二步,手工在新的工程中添加几个文件 这几个程序需要手工添加进去,实际上这几个程序都在DriverStudio自动生成的原来的两个工程文件中(这个例子是MyIOPort和Test_MyIOPort工程)。将他们添加到新工程中,方法是右键点击新工程中的相关文件夹,在弹出菜单中选择Add Files to Folder…,然后找到要添加的文件并添加。

第三步,打开OpenByIntf.cpp文件,在开始第一行添加 #include "stdafx.h" 第四步, 1 3 4 5 2 C:\PROGRAM FILES\COMPUWARE\SOFTICE DRIVER SUITE\DRIVERWORKS\INCLUDE

第五步, 1 3 4 2 可以直接从自动生成的控制台工程的设置中拷贝这些库的名称 setupapi.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib 可以直接从自动生成的控制台工程的设置中拷贝这些库的名称

最后,在控制台程序的Test_XXXX.CPP程序基础上进行必要的修改。 注意要保留的是打开设备、关闭设备、读写设备有关的函数。界面部分应该全部换成Windows界面的代码,而不是保留控制台代码。