1. 程式人生 > >鬱金香驅動學習>第三課:新增裝置物件

鬱金香驅動學習>第三課:新增裝置物件



#include <ntddk.h>

//定義個INITCODE巨集,這個巨集表示 初始化的時候載入記憶體,然後可以從記憶體中解除安裝掉
#define INITCODE code_seg("INIT") //;注意這裡是不能加分號的 
#define PAGECODE code_seg("PAGE") //表示記憶體不夠用時,可以置換到虛擬記憶體(硬碟)

//驅動裝置
#pragma INITCODE //表示這個函式執行後,就從記憶體中釋放掉
NTSTATUS CreateMyDevice (IN PDRIVER_OBJECT pDriverObject) 
{
        NTSTATUS status; // NTSTATUS 等價於 LONG
        PDEVICE_OBJECT pDevObj;/*用來返回建立裝置*/

        //UNICODE_STRING 型別為UNICODE的字元結構,裡面包含3個成員,第一個Length 表示buffer位元組的長度,不包含NULL,第二個MaximumLength:buffer總的位元組大小,第三個Buffer:指向寬字元的指標
        //建立裝置名稱
        UNICODE_STRING devName;  
        UNICODE_STRING symLinkName;

        //會動態分配一塊指向“\\Device\\yjxDDK_Device”的記憶體指標,賦值給devName.Buffer;
        RtlInitUnicodeString(&devName,L"\\Device\\yjxDDK_Device");/*對devName初始化字串為 "\\Device\\yjxDDK_Device"*/

        //IoCreateDevice 建立裝置物件,並更新pDriverObject->DeviceObject 為新建立的裝置物件
        //介紹每個引數
        // pDriverObject  該引數用於在驅動程式和新裝置物件之間建立連線,
        // 0              第二個引數是裝置擴充套件結構的大小
        // &devName       命名該裝置物件的UNICODE_STRING串的地址
        // &FILE_DEVICE_UNKNOWN       裝置型別
        // 0              為裝置物件提供Characteristics標誌
        // TRUE           指出裝置是否是排斥的
        // &pDevObj       裝置物件的名字,有了名字應用程式就可以訪問該裝置的驅動物件了
        status = IoCreateDevice( pDriverObject,\
                0,\
                &devName,\
                FILE_DEVICE_UNKNOWN,\
                0, TRUE,\
                &pDevObj);

        //NT_SUCCESS巨集定義:表示判斷 status>=0 
        if (!NT_SUCCESS(status)) //成功返回0  0>=0 嗎 true 取反  false 不執行
        {
                if(status == STATUS_INSUFFICIENT_RESOURCES)
                {
                        KdPrint(("STATUS_INSUFFICIENT_RESOURCES 資源不足"));
                }
                if(status == STATUS_OBJECT_NAME_EXISTS)
                {
                        KdPrint(("STATUS_OBJECT_NAME_EXISTS 指定物件不存在"));
                }
                if(status == STATUS_OBJECT_NAME_COLLISION)
                {
                        KdPrint(("STATUS_INSUFFICIENT_RESOURCES 物件名有衝突"));
                }
                KdPrint(("建立裝置錯誤,返回值是=%d ",status));
                return status;
        }
                
        KdPrint(("建立裝置成功,返回值是=%d ",status));

        //所建立裝置被設定為直接緩衝I/O,這是裝置讀寫三種方式中的一種
        pDevObj->Flags |= DO_BUFFERED_IO;
        //建立符號連結

        RtlInitUnicodeString(&symLinkName,L"\\??\\yjx888");

        //建立一個裝置連結。驅動程式雖然有了裝置名稱,但是這種裝置名只能在核心狀態可見,而對於應用程式是不可見的,因此,驅動需要要暴露一個符號連結,來方便應用程式的訪問,該連結指向真正的裝置名稱
        status = IoCreateSymbolicLink( &symLinkName,&devName );
        if (!NT_SUCCESS(status)) 
        {
                KdPrint(("建立符號連線錯誤,返回值是=%d ",status));
                //刪除裝置物件
                IoDeleteDevice( pDevObj );
                return status;
        }
        KdPrint(("建立符號連線成功,返回值是=%d ",status));
        return STATUS_SUCCESS;
}



//解除安裝函式的前置說明
VOID DDK_Unload(IN PDRIVER_OBJECT pDriverObject);  

//設定函式程式碼存放的程式碼段,這是是放在init段中
#pragma INITCODE
//NTSTATUS 等價與 LONG  
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING B)
{
        KdPrint(("驅動成功被載入..."));

        //建立裝置物件
        CreateMyDevice(pDriverObject);

        //Driverunload 回撥函式的一個指標,這裡的回撥函式是解除安裝驅動的函式
        pDriverObject->DriverUnload = DDK_Unload;
        return 1;
}
VOID DDK_Unload(IN PDRIVER_OBJECT pDriverObject)
{
        
        //KdPrint使用方法類似printf,注意KdPrint((" ",  ));使用的是雙括號。
        //這個比DbgPrint 呼叫要稍好。因為在free 版不被編譯。
        KdPrint(("驅動成功被解除安裝..."));

        DbgPrint("DbgPrint功能與KdPrint相同");
}