在前面的代码分析里,发现创建一个线程,而这个线程运行的主函数是PnpEventThread。那么创建这个线程是用来做什么事情的呢?那就得去分析文件reactos/base/setup/usetup/interface/devinst.c里的代码,如下:
#001 DWORD WINAPI
#002 PnpEventThread(IN LPVOID lpParameter)
#003 {
#004 NTSTATUS Status;
#005
#006 DPRINT1("Device PnpEventThread 20090721/n");
#007
调用函数EventThread来做真实的事件处理。
#008 Status = EventThread(lpParameter);
调用内核API函数NtTerminateThread来终止线程运行。
#009 NtTerminateThread(NtCurrentThread(), Status);
#010 return 0;
#011 }
继续查看函数EventThread的代码:
#001 NTSTATUS
#002 EventThread(IN LPVOID lpParameter)
#003 {
初始化两个准备使用的注册表键值。
#004 UNICODE_STRING EnumU = RTL_CONSTANT_STRING(L"//Registry//Machine//SYSTEM//CurrentControlSet//Enum");
#005 UNICODE_STRING ServicesU = RTL_CONSTANT_STRING(L"//Registry//Machine//SYSTEM//CurrentControlSet//Services");
#006 PPLUGPLAY_EVENT_BLOCK PnpEvent;
#007 OBJECT_ATTRIBUTES ObjectAttributes;
#008 ULONG PnpEventSize;
#009 HINF hInf;
#010 HANDLE hEnum, hServices;
#011 NTSTATUS Status;
#012
获取参数。
#013 hInf = *(HINF *)lpParameter;
#014
打开系统枚举键。
#015 InitializeObjectAttributes(&ObjectAttributes, &EnumU, OBJ_CASE_INSENSITIVE, NULL, NULL);
#016 Status = NtOpenKey(&hEnum, 0, &ObjectAttributes);
#017 if (!NT_SUCCESS(Status))
#018 {
#019 DPRINT1("NtOpenKey('%wZ') failed with status 0x%08lx/n", &EnumU, Status);
#020 return Status;
#021 }
#022
创建系统服务键。
#023 InitializeObjectAttributes(&ObjectAttributes, &ServicesU, OBJ_CASE_INSENSITIVE, NULL, NULL);
#024 Status = NtCreateKey(&hServices, 0, &ObjectAttributes, 0, NULL, 0, NULL);
#025 if (!NT_SUCCESS(Status))
#026 {
#027 DPRINT1("NtCreateKey('%wZ') failed with status 0x%08lx/n", &ServicesU, Status);
#028 NtClose(hEnum);
#029 return Status;
#030 }
#031
分配使用堆内存空间。
#032 PnpEventSize = 0x1000;
#033 PnpEvent = (PPLUGPLAY_EVENT_BLOCK)RtlAllocateHeap(ProcessHeap, 0, PnpEventSize);
#034 if (PnpEvent == NULL)
#035 {
#036 NtClose(hEnum);
#037 NtClose(hServices);
#038 return STATUS_NO_MEMORY;
#039 }
#040
循环地进行线程处理工作。
#041 for (;;)
#042 {
#043 DPRINT("Calling NtGetPlugPlayEvent()/n");
#044
等待下一个即插即用事件。
#045 /* Wait for the next pnp event */
#046 Status = NtGetPlugPlayEvent(0, 0, PnpEvent, PnpEventSize);
#047
是否前面分配的缓冲区太小。
#048 /* Resize the buffer for the PnP event if it's too small. */
#049 if (Status == STATUS_BUFFER_TOO_SMALL)
#050 {
#051 PnpEventSize += 0x400;
#052 RtlFreeHeap(ProcessHeap, 0, PnpEvent);
#053 PnpEvent = (PPLUGPLAY_EVENT_BLOCK)RtlAllocateHeap(ProcessHeap, 0, PnpEventSize);
#054 if (PnpEvent == NULL)
#055 {
#056 NtClose(hEnum);
#057 NtClose(hServices);
#058 return STATUS_NO_MEMORY;
#059 }
#060 continue;
#061 }
#062
等待事件出错处理。
#063 if (!NT_SUCCESS(Status))
#064 {
#065 DPRINT("NtPlugPlayEvent() failed (Status %lx)/n", Status);
#066 break;
#067 }
#068
处理枚举的设备。
#069 /* Process the pnp event */
#070 DPRINT("Received PnP Event/n");
#071 if (IsEqualIID(&PnpEvent->EventGuid, (REFGUID)&GUID_DEVICE_ENUMERATED))
#072 {
#073 DPRINT1("Device arrival event: %S/n", PnpEvent->TargetDevice.DeviceIds);
调用函数InstallDevice来安装设备。
#074 InstallDevice(hInf, hEnum, hServices, PnpEvent->TargetDevice.DeviceIds);
#075 }
#076 else
#077 {
#078 DPRINT("Unknown event/n");
#079 }
#080
通知可以处理下一个事件。
#081 /* Dequeue the current pnp event and signal the next one */
#082 NtPlugPlayControl(PlugPlayControlUserResponse, NULL, 0);
#083 }
#084
#085 RtlFreeHeap(ProcessHeap, 0, PnpEvent);
#086 NtClose(hEnum);
#087 NtClose(hServices);
#088
#089 return STATUS_SUCCESS;
#090 }
在函数 EventThread 里,主要就是循环地处理设备事件,调用函数 InstallDevice 来安装设备驱动程序。