Kernel Mode Driver Framework >> Pascal (PNP) >> File
WdfDeviceIoNeither
參考資訊:
1. Source Code
WdfDeviceIoNeither的意思就是Neither Buffered Nor Direct I/O,使用這種方式時,I/O Manager會將User Buffer的指標,透過操作後,傳遞給驅動程式使用,因此,驅動程式可以直接存取User Buffer的資料,所以存取速度可以得到很大的改善,對於有速度要求的驅動程式來說,建議使用Neither的方式,不過,關於User Buffer指標的存取問題上,會遇到更多需要面對的問題,如:指標的有效性以及多次存取的同步問題,因此,在選擇使用上,更需要考量到這些額外付出的代價是否值得使用,因為,驅動程式以及User Application雙方都需要很嚴謹的看待這塊共用的Buffer。
Microsoft的說明網頁:
using-neither-buffered-nor-direct-i-o
記憶體指標:
Event | Buffer | Length |
---|---|---|
EvtIoRead | Step 1. WdfRequestRetrieveUnsafeUserOutputBuffer() Step 2. WdfRequestProbeAndLockUserBufferForWrite() Step 3. WdfMemoryGetBuffer() |
傳入的第三個參數 |
EvtIoWrite | Step 1. WdfRequestRetrieveUnsafeUserInputBuffer() Step 2. WdfRequestProbeAndLockUserBufferForRead() Step 3. WdfMemoryGetBuffer() |
傳入的第三個參數 |
main.pas
unit main; interface uses DDDK; const DEV_NAME = '\Device\MyDriver'; SYM_NAME = '\DosDevices\MyDriver'; function __DriverEntry(pOurDriver:PDRIVER_OBJECT; pOurRegistry:PUNICODE_STRING):NTSTATUS; stdcall; implementation var szBuffer: array[0..255] of char; procedure IrpFileCreate(Device:WDFDEVICE; Request:WDFREQUEST; FileObject:WDFFILEOBJECT); stdcall; begin DbgPrint('IrpFileCreate', []); WdfRequestComplete(Request, STATUS_SUCCESS); end; procedure IrpFileClose(FileObject:WDFFILEOBJECT); stdcall; begin DbgPrint('IrpFileClose', []); end; procedure IrpRead(Queue:WDFQUEUE; Request:WDFREQUEST; Length:ULONG); stdcall; var len: ULONG; buf: Pointer; memory: WDFMEMORY; begin DbgPrint('IrpRead', []); WdfRequestRetrieveUnsafeUserOutputBuffer(Request, Length, @buf, @len); WdfRequestProbeAndLockUserBufferForWrite(Request, buf, len, @memory); buf:= WdfMemoryGetBuffer(memory, Nil); len:= strlen(@szBuffer) + 1; memcpy(buf, @szBuffer, len); WdfRequestCompleteWithInformation(Request, STATUS_SUCCESS, len); end; procedure IrpWrite(Queue:WDFQUEUE; Request:WDFREQUEST; Length:ULONG); stdcall; var len: ULONG; buf: Pointer; memory: WDFMEMORY; begin DbgPrint('IrpWrite', []); WdfRequestRetrieveUnsafeUserInputBuffer(Request, Length, @buf, @len); WdfRequestProbeAndLockUserBufferForRead(Request, buf, len, @memory); buf:= WdfMemoryGetBuffer(memory, Nil); memcpy(@szBuffer, buf, Length); DbgPrint('Buffer: %s, Length:%d', [@szBuffer, Length]); WdfRequestCompleteWithInformation(Request, STATUS_SUCCESS, Length); end; function AddDevice(pOurDriver:WDFDRIVER; pDeviceInit:PWDFDEVICE_INIT):NTSTATUS; stdcall; var device: WDFDEVICE; suDevName: UNICODE_STRING; szSymName: UNICODE_STRING; file_cfg: WDF_FILEOBJECT_CONFIG; ioqueue_cfg: WDF_IO_QUEUE_CONFIG; begin WdfDeviceInitSetIoType(pDeviceInit, WdfDeviceIoNeither); WDF_FILEOBJECT_CONFIG_INIT(@file_cfg, @IrpFileCreate, @IrpFileClose, Nil); WdfDeviceInitSetFileObjectConfig(pDeviceInit, @file_cfg, WDF_NO_OBJECT_ATTRIBUTES); RtlInitUnicodeString(@suDevName, DEV_NAME); RtlInitUnicodeString(@szSymName, SYM_NAME); WdfDeviceInitAssignName(pDeviceInit, @suDevName); WdfDeviceCreate(@pDeviceInit, WDF_NO_OBJECT_ATTRIBUTES, @device); WdfDeviceCreateSymbolicLink(device, @szSymName); WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(@ioqueue_cfg, WdfIoQueueDispatchSequential); ioqueue_cfg.EvtIoRead:= @IrpRead; ioqueue_cfg.EvtIoWrite:= @IrpWrite; Result:= WdfIoQueueCreate(device, @ioqueue_cfg, WDF_NO_OBJECT_ATTRIBUTES, WDF_NO_HANDLE); end; function __DriverEntry(pOurDriver:PDRIVER_OBJECT; pOurRegistry:PUNICODE_STRING):NTSTATUS; stdcall; var config: WDF_DRIVER_CONFIG; begin WDF_DRIVER_CONFIG_INIT(@config, AddDevice); WdfDriverCreate(pOurDriver, pOurRegistry, WDF_NO_OBJECT_ATTRIBUTES, @config, WDF_NO_HANDLE); Result:= STATUS_SUCCESS; end; end.
IrpWrite()複製User Application的資料到szBuffer
IrpRead()回填資料給User Application
P.S. 值得注意的是,Lock後的buf也可以拿來使用,只是目前遵照WDF寫法,透過WdfMemoryGetBuffer()統一取得可用的指標。
app.pas
program main; {$APPTYPE CONSOLE} uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, DIALOGS; var fd: DWORD; ret: DWORD; len: DWORD; szBuf: array[0..255] of char; begin fd:= CreateFile('\\.\MyDriver', GENERIC_READ or GENERIC_WRITE, FILE_SHARE_READ, Nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if (fd <> INVALID_HANDLE_VALUE) then begin StrCopy(szBuf, 'I am error'); len:= strlen(szBuf)+1; WriteLn(Output, Format('WR: %s, %d', [szBuf, len])); WriteFile(fd, szBuf, len, ret, Nil); ReadFile(fd, szBuf, len, ret, Nil); WriteLn(Output, Format('RD: %s, %d', [szBuf, ret])); CloseHandle(fd); end else begin WriteLn(Output, 'failed to open mydriver'); end; end.
結果