从 Windows 7 开始, 内核名称解析 功能允许内核模式组件在 Unicode 主机名和传输地址之间执行与协议无关的转换。 可以使用以下 Winsock 内核 (WSK) 客户端级函数来执行此名称解析:
这些函数执行名称-地址转换的方式与用户模式函数 FreeAddrInfoW、 GetAddrInfoW 和 GetNameInfoW 分别类似。
若要利用此功能,必须使用将 NTDDI_VERSION 宏设置为 NTDDI_WIN7 或更高版本来编译或重新编译驱动程序。
为了使驱动程序使用内核名称解析功能,它必须执行以下调用序列:
调用 WskRegister 以向 WSK 注册。
调用 WskCaptureProviderNPI 以捕获 WSK 提供程序 网络编程接口 (NPI) 。
使用完 WSK 提供程序 NPI 后,调用 WskReleaseProviderNPI 以释放 WSK 提供程序 NPI。
调用 WskDeregister 以取消注册 WSK 应用程序。
下面的代码示例使用上述调用序列来演示 WSK 应用程序如何调用 WskGetAddressInfo 函数将主机名转换为传输地址。
NTSTATUS
SyncIrpCompletionRoutine(
__in PDEVICE_OBJECT Reserved,
__in PIRP Irp,
__in PVOID Context
)
{
PKEVENT compEvent = (PKEVENT)Context;
UNREFERENCED_PARAMETER(Reserved);
UNREFERENCED_PARAMETER(Irp);
KeSetEvent(compEvent, 2, FALSE);
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS
KernelNameResolutionSample(
__in PCWSTR NodeName,
__in_opt PCWSTR ServiceName,
__in_opt PADDRINFOEXW Hints,
__in PWSK_PROVIDER_NPI WskProviderNpi
)
{
NTSTATUS status;
PIRP irp;
KEVENT completionEvent;
UNICODE_STRING uniNodeName, uniServiceName, *uniServiceNamePtr;
PADDRINFOEXW results;
PAGED_CODE();
//
// Initialize UNICODE_STRING structures for NodeName and ServiceName
//
RtlInitUnicodeString(&uniNodeName, NodeName);
if(ServiceName == NULL) {
uniServiceNamePtr = NULL;
}
else {
RtlInitUnicodeString(&uniServiceName, ServiceName);
uniServiceNamePtr = &uniServiceName;
}
//
// Use an event object to synchronously wait for the
// WskGetAddressInfo request to be completed.
//
KeInitializeEvent(&completionEvent, SynchronizationEvent, FALSE);
//
// Allocate an IRP for the WskGetAddressInfo request, and set the
// IRP completion routine, which will signal the completionEvent
// when the request is completed.
//
irp = IoAllocateIrp(1, FALSE);
if(irp == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
IoSetCompletionRoutine(irp, SyncIrpCompletionRoutine,
&completionEvent, TRUE, TRUE, TRUE);
//
// Make the WskGetAddressInfo request.
//
WskProviderNpi->Dispatch->WskGetAddressInfo (
WskProviderNpi->Client,
&uniNodeName,
uniServiceNamePtr,
NS_ALL,
NULL, // Provider
Hints,
&results,
NULL, // OwningProcess
NULL, // OwningThread
irp);
//
// Wait for completion. Note that processing of name resolution results
// can also be handled directly within the IRP completion routine, but
// for simplicity, this example shows how to wait synchronously for
// completion.
//
KeWaitForSingleObject(&completionEvent, Executive,
KernelMode, FALSE, NULL);
status = irp->IoStatus.Status;
IoFreeIrp(irp);
if(!NT_SUCCESS(status)) {
return status;
}
//
// Process the name resolution results by iterating through the addresses
// within the returned ADDRINFOEXW structure.
//
results; // your code here
//
// Release the returned ADDRINFOEXW structure when no longer needed.
//
WskProviderNpi->Dispatch->WskFreeAddressInfo(
WskProviderNpi->Client,
results);
return status;
}