链表的使用
链表是驱动开发中经常遇到的一个数据结构,主要是双向循环链表;要使用链表,需要用到一个LIST_ENTRY的结构,其定义如下:
typedef struct _LIST_ENTRY {
struct _LIST_ENTRY *Flink; // 指向下一个节点
struct _LIST_ENTRY *Blink; // 指向前一个节点
} LIST_ENTRY, *PLIST_ENTRY;
在实际的编程中,我们需要自己定义链表的节点,并把节点的第一个成员设置为LIST_ENTRY类型的变量(不一定放在第一位,但通常是这样);此外,我们还需要一个LIST_ENTRY类型的链表头;其他的就靠下面的函数或者宏来操作了:
InitializeListHead,初始化链表头
IsListEmpty,判断链表是否为空
InsertHeadList,从链表头部插入节点
InsertTailList,从链表尾部插入节点
RemoveHeadList,从链表头部删除节点
RemoveTailList,从链表尾部删除节点
CONTAINING_RECORD,从RemoveHeadList或者RemoveTailList返回的数据获取一个指向删除节点的指针
示例代码:
typedef struct _LIST_NODE
{
LIST_ENTRY ListEntry;
ULONG ulData;
} LIST_NODE, *PLIST_NODE;
VOID LinkListTest()
{
LIST_ENTRY listHead;
PLIST_NODE pListNode = NULL;
ULONG i = 0;
InitializeListHead(&listHead);
DebugPrint(("Begin insert to link list\r\n"));
for (i = 0; i < 10; ++i)
{
pListNode = (PLIST_NODE)
ExAllocatePool(PagedPool, sizeof(LIST_NODE));
pListNode->ulData = i;
InsertHeadList(&listHead, &pListNode->ListEntry);
}
DebugPrint(("Begin remove from link list\r\n"));
while (!IsListEmpty(&listHead))
{
PLIST_ENTRY pEntry = RemoveTailList(&listHead);
pListNode = CONTAINING_RECORD(pEntry,
LIST_NODE,
ListEntry);
DebugPrint(("Delete Node's Value: %d\r\n", pListNode->ulData));
ExFreePool(pListNode);
}
}
DPC定时器的使用
DPC定时器可以对任意间隔时间进行定时,DPC定时器内部使用定时器对象KTIMER,当对定时器设定一个时间间隔后,每隔这段时间操作系统就会将一个DPC例程插入DPC队列,当操作系统读取DPC队列时,对应的DPC例程被执行。在DPC定时器需要用到的一些函数:
KeInitializeTimer,初始化定时器对象
KeInitializeDpc,初始化DPC对象
KeSetTimer,开启定时器
KeCancelTimer,取消定时器
在调用KeSetTimer之后,只会触发一次DPC例程。如果想周期触发DPC例程,需要在DPC例程触发后,再次调用KeSetTimer。示例代码可以参考《Windows驱动开发技术详解》一书。