570 likes | 705 Views
Windows98/2000 驱动程序编写方法. (下). 杨全胜. 4.Driver Works 的使用. 1 )生成简单框架. 工程文件名. 工程文件目录. 选择驱动类型. 创建功能驱动程序. 创建过滤器驱动程序. 本例不驱动硬件. 选择相应总线. 驱动类名称. 驱动类文件名. 选择需要处理的消息句柄. 添加和应用程序之间通信的控制代码. 测试用应用程序名称. 驱动类. 设备类. 驱动类文件. 设备类文件. 驱动安装指导文件. 测试用的控制台程序文件.
E N D
Windows98/2000驱动程序编写方法 (下) 杨全胜
4.Driver Works的使用 1)生成简单框架
工程文件名 工程文件目录
创建功能驱动程序 创建过滤器驱动程序
本例不驱动硬件 选择相应总线
驱动类名称 驱动类文件名
驱动类 设备类
驱动类文件 设备类文件 驱动安装指导文件 测试用的控制台程序文件
此时已经具备了一个驱动程序以及做测试用的应用程序的基本框架,我们可以在VC集成环境下区修改有关程序,增加相关的具体操作代码,然后就可以编译和调试了。此时已经具备了一个驱动程序以及做测试用的应用程序的基本框架,我们可以在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的次功能代码联系起来看 public: 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带的工具加载驱动程序和查看调试信息。下面使用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 where 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); }