Q:
請問有什么方法實現驅動程序主動和應用程序進行實時通訊,而不用應用程序采用定時查詢的方法?
比如驅動有一事件發生需要立即通知應用程序,或驅動程序需要向應用程序讀取一些內容.
A:
有一個很容易的方式,在驅動程序和應用程序之間用一個事件。
在應用程序CreateFile的時候,驅動程序IoCreateSynchronizationEvent一個有名的事件,然后應用程序CreateEvent/OpenEvent此有名事件即可。
注意點:
1,不要在驅動初始化的時候創建事件,此時大多不能成功創建;
2,讓驅動先創建,那么此后應用程序打開時,只能讀(Waitxxxx),不能寫(SetEvent/ResetEvent)。反之,如果應用程序先創建,則應用程序和驅動程序都有讀寫權限;
3,用名字比較理想,注意驅動中名字在\BaseNamedObjects\下,例如應用程序用“xxxEvent”,那么驅動中就是“\BaseNamedObjects\xxxEvent”;
4,用HANDLE的方式也可以,但是在WIN98下是否可行,未知。
5,此后,驅動對讀請求應立即返回,否則就返回失敗。不然將失去用事件通知的意義(不再等待讀完成,而是有需要(通知事件)時才會讀);
6,應用程序發現有事件,應該在一個循環中讀取,直到讀取失敗,表明沒有數據可讀;否則會漏掉后續數據,而沒有及時讀取;
Sample Code:
// Describe the share memory.
typedef struct _PKT_BUFFER
{
PMDL BufferMdl;
PVOID UserBaseAddress;
PVOID KernelBaseAddress;
}PKT_BUFFER, *PPKT_BUFFER;
typedef struct _SHARE_EVENT_CONTEXT
{
WCHAR EventName[128]; // Event name, the only connection btw ring0/ring3
HANDLE Win32EventHandle; // Ring3 copy of the event handle
HANDLE DriverEventHandle; // Ring0 copy of the event handle
PVOID DriverEventObject; // The event object
}SHARE_EVENT_CONTEXT, *PSHARE_EVENT_CONTEXT;
BOOLEAN CreateShareMemory(PPKT_BUFFER PktBuffer, ULONG Size)
{
PktBuffer->KernelBaseAddress = ExAllocatePoolWithTag(NonPagedPool,
Size,
'MpaM');
if(!PktBuffer->KernelBaseAddress)
return FALSE;
//
// Allocate and initalize an MDL that describes the buffer
//
PktBuffer->BufferMdl = IoAllocateMdl(PktBuffer->KernelBaseAddress,
Size,
FALSE,
FALSE,
NULL);
if(!PktBuffer->BufferMdl)
{
ExFreePool(PktBuffer->KernelBaseAddress);
PktBuffer->KernelBaseAddress =NULL;
return FALSE;
}
MmBuildMdlForNonPagedPool(PktBuffer->BufferMdl);
DEBUGP(DL_INFO, ("CreateShareMemory: KernelBaseAddress = 0x%p\n", PktBuffer->KernelBaseAddress));
return TRUE;
}
VOID DestroyShareMemory(PPKT_BUFFER PktBuffer)
{
if(PktBuffer->BufferMdl)
{
IoFreeMdl(PktBuffer->BufferMdl);
PktBuffer->BufferMdl = NULL;
}
if(PktBuffer->KernelBaseAddress)
{
ExFreePool(PktBuffer->KernelBaseAddress);
PktBuffer->KernelBaseAddress = NULL;
}
}
//This function works in user dispatch code.
BOOLEAN MapSharedMemory(PPKT_BUFFER PktBuffer)
{
if(!PktBuffer->BufferMdl)
return FALSE;
//
// The preferred V5 way to map the buffer into user space
//
PktBuffer->UserBaseAddress =
MmMapLockedPagesSpecifyCache(PktBuffer->BufferMdl, // MDL
UserMode, // Mode
MmCached, // Caching
NULL, // Address
FALSE, // Bugcheck?
NormalPagePriority); // Priority
if(!PktBuffer->UserBaseAddress)
return FALSE;
DEBUGP(DL_INFO, ("MapSharedMemory SUCCESS, UserBaseAddress %p\n", PktBuffer->UserBaseAddress));
return TRUE;
}
VOID UnmapSharedMemory(PPKT_BUFFER PktBuffer)
{
if(PktBuffer->UserBaseAddress)
{
MmUnmapLockedPages(PktBuffer->UserBaseAddress, PktBuffer->BufferMdl);
PktBuffer->UserBaseAddress = NULL;
}
}
BOOLEAN CreateShareEvent(PSHARE_EVENT_CONTEXT ShareEvent)
{
UNICODE_STRING UnicodeName;
WCHAR UnicodeBuffer[128] = L"\BaseNamedObjects\";
RtlInitUnicodeString(&UnicodeName, UnicodeBuffer);
UnicodeName.MaximumLength = 128;
RtlAppendUnicodeToString(&UnicodeName, ShareEvent->EventName);
ShareEvent->DriverEventObject = IoCreateSynchronizationEvent(&UnicodeName,
&ShareEvent->DriverEventHandle);
if(ShareEvent->DriverEventObject == NULL)
{
ShareEvent->DriverEventHandle = NULL;
DEBUGP(DL_INFO, ("CreateSynchronizationEvent FAILED Name=%ws\n", UnicodeBuffer));
return FALSE;
}
else
{
KeClearEvent(ShareEvent->DriverEventObject);
DEBUGP(DL_INFO, ("CreateSynchronizationEvent SUCCESS Name=%ws DriverEventObject=%p, DriverEventHandle=%u\n",
UnicodeBuffer,
ShareEvent->DriverEventObject,
ShareEvent->DriverEventHandle));
return TRUE;
}
}
VOID DestroyShareEvents(PSHARE_EVENT_CONTEXT ShareEvent)
{
if(ShareEvent->DriverEventHandle)
{
ZwClose(ShareEvent->DriverEventHandle);
ShareEvent->DriverEventObject = NULL;
ShareEvent->DriverEventHandle = NULL;
}
}
|