天天看點

VS2008 開發驅動程式

1.       前言

随着計算機科學技術的發展,驅動程式的開發悄然成為各個計算機應用領域(特别是編寫與硬體相關程式)的程式員的關注的話題,對于那些迫切希望探究驅動程式開發奧秘的程式員來講,面對鋪天蓋地,五花八門的各種圖書資料,難免出現不知從何入手的問題,本文将帶領你利用微軟成熟的開發設計環境,自己動手開發出幾類最簡單的驅動程式,抛磚引玉,希望大家能夠從中吸取到自己需要的知識,戳破驅動程式開發神秘的面紗,提升自身軟體設計實力,為祖國的軟體事業發展做出更大的貢獻。

本人在學習驅動程式開發伊始,懵懵懂懂中也翻閱了不少前輩們的書籍,也在網際網路上搜集了不少關于驅動開發方面的資料,出處無法一一列舉,本文也将引用或者參考部分内容,在此感謝原著對本人的幫助,對前輩們獻上我最崇高的敬意。

2.       開發環境搭建

2.1   軟體平台搭建:

Microsoft Visual Studio 2008 , WDK7,VMware Workstation6.5.

安裝VS2008及MSDN 。MSDN 可以幫助你更好使用VS2008,在出現問題找不到答案時,可以仔細閱讀一下MSDN ,會提供一些必要的幫助。并且可以通過MSDN免費得到WDK7的下載下傳連接配接。VS2008安裝步驟略。

下載下傳,安裝WDK7,即(Windows Driver Kits 7.0.0)。提示選擇安裝選項時,建議全部選擇安裝,WDK便自動安裝WinDbg(Windows調試工具),用于使用虛拟機對驅動程式代碼進行調試。安裝步驟略。

安裝VMware Workstation.建議選擇安裝6.0以上版本。安裝步驟略。安裝成功以後建立Windows虛拟機,筆者選擇的是WindowsXP系統(其他Windows系統大體相同),并安裝系統映像,使之成為可以正常工作的WindowsXP虛拟系統。

2.2   調試平台搭建:

軟體平台搭建成功以後,調試平台的搭建需要以下幾個步驟。

第一步,修改WindowsXP虛拟機的系統配置。

1.       修改虛拟機配置。在硬體中選擇添加序列槽。在連接配接屬性中選擇“使用命名管道”。保留預設命名管道名稱//./pipe/com_1。在序列槽端屬性中選擇“The end is the server.”,“The other end is an application. ”。勾選I/0模式中的”Yield CPU on Polled”複選框。

2.       啟動虛拟機進入WindowsXP系統,打開“我的電腦”視窗,在“工具”菜單裡面選擇“檔案夾選項”并點選,在檔案夾選項彈出視窗選擇“檢視”頁籤。在“進階選項”中去除“隐藏受保護的作業系統檔案”複選框勾選。并選擇“顯示所有檔案和檔案夾“。确定後系統關閉彈出視窗。

3.       打開系統的安裝分區,筆者電腦預設安裝的C槽。在根目錄下可以找到“boot.ini”配置檔案。輕按兩下打開檔案。修改[boot loader]。Timeouts = 30.修改[Operating systems],複制其中關于WindowsXP 的一行字元(如果是純淨系統隻有一行系統描述,有些系統可能帶有DOS安裝工具的選項,我們隻需要複制關于安裝Windows系統的描述),添加一新行并粘貼複制描述字元串。在系統描述字元串裡面添加“-Debug”以示和前面項目的差別,行末添加“/debug /debugport=COM1 /baudrate=115200” 。儲存關閉檔案。關閉系統。

4.       從開始菜單中選擇“Debugging Tools for Windows(X86)”中的windbg并打開。

在file 菜單下的Symbol Search Path項點選,彈出Symbol Search Path對話框。在Symbol Path編輯框裡面輸入srv*c:/windows/symbols*http://msdl.microsoft.com/download/symbols;cache*c:/windows/symbols。并建立C:/Windows/symbols檔案夾。在file 菜單下選擇Kernal Debug選項,彈出Kernal Debugging對話框,選擇COM頁籤,輸入波特率為115200,端口名//./pipe/com_1 。勾選Pipe複選框。确定後WinDbg即處于等待管道連接配接狀态。

5.       重新啟動WindowsXP虛拟機。在引導清單(即可看到我們在第3步中添加的系統描述)中,選擇帶有“-Debug”選項(前面設定哪項)并回車。正常情況下,在啟動一段時間後WinDbg即顯示連接配接成功。選擇WinDbg中的Debug菜單下break選項,如果虛拟機響應,WinDbg調試菜單和工具欄即變為有效狀态,可以進行單步等其他操作。說明調試平台搭建成功。首次進行連接配接可能需要較長時間。

3.       KDM驅動開發示例

3.1   項目屬性配置

1.       打開VS2008,建立一個Visual C++  à  Win32 à win32空項目。例如DDKDemo。

2.       打開VS2008 的“生成”菜單中的“配置管理器”選項。在活動解決方案配置中選擇《建立》,建立一個Check空的解決方案配置。

3.       在解決方案管理器中,建立一個DDKDemo.h頭檔案,一個DDKDemo.cpp源檔案。

4.       打開VS2008的“項目”菜單裡面“屬性”選項。即打開Test項目屬性頁。在項目屬性頁選擇“配置屬性”,打開十字圖示。

5.       選擇“C/C++”并展開内部選項。

在“正常”選項中,在“附加包含目錄”中添加wdk 引用頭檔案目錄。并去除“從父級或項目預設設定繼承”複選框的勾選。Wdk頭檔案目錄如下:

                       D:/WinDDK/7600.16385.0/inc/api

                      D:/WinDDK/7600.16385.0/inc/crt

                      D:/WinDDK/7600.16385.0/inc/ddk

                      注意筆者的WDK安裝目錄在D盤。

             在“調試資訊格式”中選擇 “C7 相容(/Z7)”選項。

             在“警告等級”中選擇“3級(/W3)”。

             在“将警告視為錯誤”中選擇“是(/WX)”。

在“優化”選項中,在“優化”中選擇“禁用(/Od)”。

在“預處理器”選項中,在“預處理器定義”中添加                  “WIN32=100;_X86_=1;WINVER=0x501;DBG=1”。并去除“從父級或項目預設屬性繼承”複選框的勾選。

在“進階”選項中,選擇“調用約定”為“__stdcall  (/Gz)”。

6.       選擇“連結器”并展開内部選項。

在“正常”選項中,修改“輸出檔案”的檔案擴充名為 .sys 添加“附加庫目錄”

                       D:/WinDDK/7600.16385.0/lib/Crt/i386

                       D:/WinDDK/7600.16385.0/lib/wxp/i386

并去除“從父級或項目預設設定繼承”複選框的勾選。

在“輸入”選項中,添加“附加依賴項”ntoskrnl.lib并去除“從父級或項目預設設定繼承”複選框的勾選。

在“清單檔案”選項中,選擇“生成清單”為否。

在“調試”選項中,選擇“生成調試資訊”為“是 (/Debug)”。

在“系統”選項中,選擇“子系統”為“本機 (/SUBSYSTEM:NATIVE)”。選擇“驅動程式”為“驅動程式(/DRIVER)”。

在“進階”中,添加“入口點”為DriverEntry。選擇“随即基址”為“預設值”。選擇“資料執行保護”為預設值。選擇“目标計算機”為“MachineX86(/MACHINE:X86)”。

在“指令行”選項中,添加“/SECTION:INIT,D /IGNORE:4078”。

3.2   示例代碼簡介

#pragma once

//KDM驅動程式頭檔案

extern "C"

{

#include<ntddk.h>

}

//定義幾個函數段屬性宏

#define PAGEDCODE code_seg("PAGED")                   //分頁記憶體段

#define LOCKEDPAGE code_seg()                    //非分頁記憶體段

#define INITCODE code_seg("INIT")                //初始化記憶體段

//定義裝置擴充結構,用于儲存裝置屬性

typedef struct _DEVICE_EXTENSION

{

  PDEVICE_OBJECT pDeviceObject;                  //裝置對象指針

  UNICODE_STRING ustrDeviceName;                 //裝置名

  UNICODE_STRING ustrSymbolicName;          //符合連接配接名

}DEVICE_EXTENSION,*PDEVICE_EXTENSION;

//輔助建立裝置函數聲明

NTSTATUS CreateDevice(IN PDRIVER_OBJECT pDriverObject);

//驅動解除安裝回調函數

VOID DDKUnload(IN PDRIVER_OBJECT pDriverObject);

//驅動投遞函數

NTSTATUS DDKDispatchRoutine(IN PDEVICE_OBJECT pDeviceObject,

                              IN PIRP pIrp);

#include "DDKDemo.h"

#pragma INITCODE

extern "C" NTSTATUS DriverEntry(

       IN PDRIVER_OBJECT pDriverObject,

       IN PUNICODE_STRING ustrRegistryPath)

{

  NTSTATUS status;

  DbgPrint(("Hello,My Windows!Enter DriverEntry!/n"));

         //添加一個調試斷點,用于使用WinDbg進行源代碼調試

  DbgBreakPoint();

  //注冊其他驅動回調函數入口

  pDriverObject->DriverUnload=DDKUnload;

  pDriverObject->MajorFunction[IRP_MJ_CREATE]=DDKDispatchRoutine;

  pDriverObject->MajorFunction[IRP_MJ_CLOSE]=DDKDispatchRoutine;

  pDriverObject->MajorFunction[IRP_MJ_WRITE]=DDKDispatchRoutine;

  pDriverObject->MajorFunction[IRP_MJ_READ]=DDKDispatchRoutine;

  //建立裝置

  status=CreateDevice(pDriverObject);

  DbgPrint(("DriverEntry end!/n"));

  return status;

}

#pragma INITCODE

NTSTATUS CreateDevice(IN PDRIVER_OBJECT pDriverObject)

{

  NTSTATUS status;

  PDEVICE_OBJECT pDeviceObject;

  PDEVICE_EXTENSION pDeviceExtension;

  DbgPrint(("Enter CreateDevice!/n"));

  //建立裝置名稱

  UNICODE_STRING DeviceName;

  RtlInitUnicodeString(&DeviceName,L"//Device//DDKDevice");

  //建立裝置

  status=IoCreateDevice(pDriverObject,

       sizeof(DEVICE_EXTENSION),

       &(UNICODE_STRING)DeviceName,

       FILE_DEVICE_UNKNOWN,

       0,TRUE,

       &pDeviceObject);

  if(!NT_SUCCESS(status))

  {

       return status;

  }

  //添加擴充屬性

  pDeviceObject->Flags |= DO_BUFFERED_IO;

  //建立符合連接配接

  UNICODE_STRING SymbolicLinkName;

  RtlInitUnicodeString(&SymbolicLinkName,L"//??//MyDDKDevice");

  pDeviceExtension=(PDEVICE_EXTENSION)pDeviceObject->DeviceExtension;

  pDeviceExtension->pDeviceObject=pDeviceObject;

  pDeviceExtension->ustrDeviceName=DeviceName;

  pDeviceExtension->ustrSymbolicName=SymbolicLinkName;

  status=IoCreateSymbolicLink(&SymbolicLinkName,&DeviceName);

  if(!NT_SUCCESS(status))

  {

       IoDeleteDevice(pDeviceObject);

       DbgPrint(("CreateDevice Failed!/n"));

       return status;

  }

  DbgPrint(("CreateDevice end!/n"));

  return STATUS_SUCCESS;

}

#pragma PAGEDCODE

VOID DDKUnload(IN PDRIVER_OBJECT pDriverObject)

{

  PDEVICE_OBJECT pNextObject;

  DbgPrint(("Enter DDKUnload/n"));

  pNextObject=pDriverObject->DeviceObject;

  while(pNextObject !=NULL)

  {

       //周遊所有挂載裝置

       PDEVICE_EXTENSION pDevExtension=(PDEVICE_EXTENSION)pNextObject->DeviceExtension;

       UNICODE_STRING SymLink=pDevExtension->ustrSymbolicName;

       IoDeleteSymbolicLink(&SymLink);

       pNextObject=pNextObject->NextDevice;

       IoDeleteDevice(pDevExtension->pDeviceObject);

  }

}

#pragma PAGEDCODE

NTSTATUS DDKDispatchRoutine(IN PDEVICE_OBJECT pDeviceObject,

                              IN PIRP pIrp)

{

  DbgPrint(("Enter DDKDispatchRoutine!/n"));

  NTSTATUS status=STATUS_SUCCESS;

  pIrp->IoStatus.Status=status;

  pIrp->IoStatus.Information=0;

  IoCompleteRequest(pIrp,IO_NO_INCREMENT);

  DbgPrint(("DDKDispatchRountine end!/n"));

  return status;

}

3.3   安裝調試示例

打開DDKDemo所在目錄,進入Check檔案夾,複制DDKDemo.sys檔案到虛拟機中。

驅動的安裝可以有二種選擇,一種使用安裝工具進行安裝,一種自己編寫安裝程式。對于初學者,可以從網上下載下傳DriverMonitor驅動調試安裝工具來安裝自己生成的驅動程式。

打開WinDbg,在file菜單中打開Source Search Path項,在彈出的對話框的Source Path中添加DDKDemo目标檔案夾全路徑,即上述的Check檔案夾的全路徑。在Debug菜單中選擇Source Mode為選擇狀态,啟動Kernal Debug 核心調試。

在WindowsXP虛拟機中安裝加載DDKDemo.sys驅動程式,驅動程式被加載以後,虛拟機即在我們設定的斷點中斷,同時WinDbg處于激活狀态。在WinDbg中選擇單步執行,單步兩下,WinDbg即可彈出附帶源碼的驅動程式調試視窗。現在你已經進入裡系統驅動加載的過程中了,可以随意檢視程式執行過程中的參變量的變化。接下來就是你自己施展才華時候了。呵呵~~

繼續閱讀