1.
設備對象一共同擁有三種讀寫方式:緩沖區方式讀寫(Buffered方式);直接方式讀寫(Direct方式)。Neither方式。這三種方式的Flags分別相應DO_BUFFERED_IO,DO_DIRECT_IO,0
在buffered方式中。I/O管理器先創建一個與用戶模式數據緩沖區大小相等的系統緩沖區。而你的驅動程序將使用這個系統緩沖區工作。I/O管理器負責在系統緩沖區和用戶模式緩沖區之間復制數據。
?
在direct方式中,I/O管理器鎖定了包括用戶模式緩沖區的物理內存頁。并創建一個稱為MDL(內存描寫敘述符表)的輔助數據結構來描寫敘述鎖定頁。因此你的驅動程序將使用MDL工作。?
在neither方式中。I/O管理器僅簡單地把用戶模式的虛擬地址傳遞給你。
而使用用戶模式地址的驅動程序應十分小心。
2.
以下介紹緩沖區方式讀寫。其長處是比較簡單的攻克了將用戶地址傳入驅動的問題,缺點是須要用戶模式和內核模式之間數據復制。可想而知。執行效率會受到影響。
適合少量內存操作時使用的一種方法。
創建好設備IoCreateDevice后。須要設置DO_BUFFERED_IO, ?pDevObj->Flags |= DO_BUFFERED_IO.
如今以readfile為例,首先應用程序中須要提供一段緩沖區并把緩沖區大小作為參數傳入,比如
UCHAR OutputBuffer[10];
DWORD RetLen = 0;
readfile(hDevice,OutputBuffer,sizeof(OutputBuffer),&RetLen,NULL);
OutputBuffer是提供的輸出緩沖區。是用戶模式的內存地址,操作系統將此緩沖區的數據拷貝到內核模式下的地址中,sizeof(OutputBuffer)是緩沖區的大小,而RetLen是真正的輸出的字節數。
那么內核模式怎么得到此內核模式地址呢?怎么得到writefile或readfile的字節數呢?答案在以下。
此內核模式下的地址能夠通過此readfile創建的IRP的AssociatedIrp.SystemBuffer得到。
假如請求的IRP為PIRP pIrp(通常是派遣函數的參數),那么UCHAR* OutputBuffer= (UCHAR*)pIrp->AssociatedIrp.SystemBuffer;
而readfile請求的字節數為IO_STACK_LOCATION中的Parameters.Read.Length,writefilew為IO_STACK_LOCATION中的Parameters.Write.Length
//得到當前堆棧
PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);
//得到readfile緩沖區大小
ULONG cbread = stack->Parameters..Read.Length;
//得到writefile緩沖區大小
ULONG cbwrite = stack->Parameters.Write.Length;
得到了內核模式下的緩沖區地址了就能夠對此緩沖區操作了。比方:
UCHAR*?OutputBuffer= (UCHAR*)pIrp->AssociatedIrp.SystemBuffer;
ULONG cbread = stack->Parameters..Read.Length;
memcpy(OutputBuffer,0xBB,cbread);
這樣用戶模式下的緩沖區內得到的數據是0xBB。
另外還要設置實際操作的字節數,pIrp->IoStatus.Information = cbread;(實際操作的字節數不一定要設置為緩沖區的大小。但也不應該大于緩沖區的大小)
那么用戶模式下readfile的RetLen被設置為cbread。
以下是IRP_MJ_READ的派遣函數:
NTSTATUS DispatchRead(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp)
{KdPrint(("Enter DispatchRead\n"));//對一般IRP的簡單操作。后面會介紹對IRP更復雜的操作NTSTATUS status = STATUS_SUCCESS;PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);ULONG ulReadLength = stack->Parameters.Read.Length;// 完畢IRP//設置IRP完畢狀態pIrp->IoStatus.Status = status;//設置IRP操作了多少字節pIrp->IoStatus.Information = ulReadLength; memset(pIrp->AssociatedIrp.SystemBuffer,0xAA,ulReadLength);//處理IRPIoCompleteRequest( pIrp, IO_NO_INCREMENT );KdPrint(("Leave DispatchRead\n"));return status;
}
設備讀寫方式:直接讀取方式:http://blog.csdn.net/liyun123gx/article/details/38043849
Neither方式:http://blog.csdn.net/liyun123gx/article/details/38046865