|
Q:
請(qǐng)問有什么方法實(shí)現(xiàn)驅(qū)動(dòng)程序主動(dòng)和應(yīng)用程序進(jìn)行實(shí)時(shí)通訊,而不用應(yīng)用程序采用定時(shí)查詢的方法?
比如驅(qū)動(dòng)有一事件發(fā)生需要立即通知應(yīng)用程序,或驅(qū)動(dòng)程序需要向應(yīng)用程序讀取一些內(nèi)容.
A:
有一個(gè)很容易的方式,在驅(qū)動(dòng)程序和應(yīng)用程序之間用一個(gè)事件。
在應(yīng)用程序CreateFile的時(shí)候,驅(qū)動(dòng)程序IoCreateSynchronizationEvent一個(gè)有名的事件,然后應(yīng)用程序CreateEvent/OpenEvent此有名事件即可。
注意點(diǎn):
1,不要在驅(qū)動(dòng)初始化的時(shí)候創(chuàng)建事件,此時(shí)大多不能成功創(chuàng)建;
2,讓驅(qū)動(dòng)先創(chuàng)建,那么此后應(yīng)用程序打開時(shí),只能讀(Waitxxxx),不能寫(SetEvent/ResetEvent)。反之,如果應(yīng)用程序先創(chuàng)建,則應(yīng)用程序和驅(qū)動(dòng)程序都有讀寫權(quán)限;
3,用名字比較理想,注意驅(qū)動(dòng)中名字在\BaseNamedObjects\下,例如應(yīng)用程序用“xxxEvent”,那么驅(qū)動(dòng)中就是“\BaseNamedObjects\xxxEvent”;
4,用HANDLE的方式也可以,但是在WIN98下是否可行,未知。
5,此后,驅(qū)動(dòng)對(duì)讀請(qǐng)求應(yīng)立即返回,否則就返回失敗。不然將失去用事件通知的意義(不再等待讀完成,而是有需要(通知事件)時(shí)才會(huì)讀);
6,應(yīng)用程序發(fā)現(xiàn)有事件,應(yīng)該在一個(gè)循環(huán)中讀取,直到讀取失敗,表明沒有數(shù)據(jù)可讀;否則會(huì)漏掉后續(xù)數(shù)據(jù),而沒有及時(shí)讀。
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;
}
}
|
|