⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 plugplay.c

📁 ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机理和API函数调用几乎相同。甚至可以兼容XP的程序。喜欢研究系统内核的人可以看一看。
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
 * COPYRIGHT:       See COPYING in the top level directory
 * PROJECT:         ReactOS kernel
 * FILE:            ntoskrnl/io/plugplay.c
 * PURPOSE:         Plug-and-play interface routines
 *
 * PROGRAMMERS:     Eric Kohl <eric.kohl@t-online.de>
 */

/* INCLUDES *****************************************************************/

#include <ntoskrnl.h>

#define NDEBUG
#include <internal/debug.h>

#if defined (ALLOC_PRAGMA)
#pragma alloc_text(INIT, IopInitPlugPlayEvents)
#endif

typedef struct _PNP_EVENT_ENTRY
{
  LIST_ENTRY ListEntry;
  PLUGPLAY_EVENT_BLOCK Event;
} PNP_EVENT_ENTRY, *PPNP_EVENT_ENTRY;


/* GLOBALS *******************************************************************/

static LIST_ENTRY IopPnpEventQueueHead;
static KEVENT IopPnpNotifyEvent;

/* FUNCTIONS *****************************************************************/

NTSTATUS INIT_FUNCTION
IopInitPlugPlayEvents(VOID)
{
    InitializeListHead(&IopPnpEventQueueHead);

    KeInitializeEvent(&IopPnpNotifyEvent,
                      SynchronizationEvent,
                      FALSE);

    return STATUS_SUCCESS;
}


NTSTATUS
IopQueueTargetDeviceEvent(const GUID *Guid,
                          PUNICODE_STRING DeviceIds)
{
    PPNP_EVENT_ENTRY EventEntry;
    ULONG TotalSize;

    TotalSize =
        FIELD_OFFSET(PLUGPLAY_EVENT_BLOCK, TargetDevice.DeviceIds) +
        DeviceIds->MaximumLength;

    EventEntry = ExAllocatePool(NonPagedPool,
                                TotalSize + FIELD_OFFSET(PNP_EVENT_ENTRY, Event));
    if (EventEntry == NULL)
        return STATUS_INSUFFICIENT_RESOURCES;

    memcpy(&EventEntry->Event.EventGuid,
           Guid,
           sizeof(GUID));
    EventEntry->Event.EventCategory = TargetDeviceChangeEvent;
    EventEntry->Event.TotalSize = TotalSize;

    memcpy(&EventEntry->Event.TargetDevice.DeviceIds,
           DeviceIds->Buffer,
           DeviceIds->MaximumLength);

    InsertHeadList(&IopPnpEventQueueHead,
                   &EventEntry->ListEntry);
    KeSetEvent(&IopPnpNotifyEvent,
               0,
               FALSE);

    return STATUS_SUCCESS;
}


/*
 * Remove the current PnP event from the tail of the event queue
 * and signal IopPnpNotifyEvent if there is yet another event in the queue.
 */
static NTSTATUS
IopRemovePlugPlayEvent(VOID)
{
  /* Remove a pnp event entry from the tail of the queue */
  if (!IsListEmpty(&IopPnpEventQueueHead))
  {
    ExFreePool(RemoveTailList(&IopPnpEventQueueHead));
  }

  /* Signal the next pnp event in the queue */
  if (!IsListEmpty(&IopPnpEventQueueHead))
  {
    KeSetEvent(&IopPnpNotifyEvent,
               0,
               FALSE);
  }

  return STATUS_SUCCESS;
}


/*
 * Plug and Play event structure used by NtGetPlugPlayEvent.
 *
 * EventGuid
 *    Can be one of the following values:
 *       GUID_HWPROFILE_QUERY_CHANGE
 *       GUID_HWPROFILE_CHANGE_CANCELLED
 *       GUID_HWPROFILE_CHANGE_COMPLETE
 *       GUID_TARGET_DEVICE_QUERY_REMOVE
 *       GUID_TARGET_DEVICE_REMOVE_CANCELLED
 *       GUID_TARGET_DEVICE_REMOVE_COMPLETE
 *       GUID_PNP_CUSTOM_NOTIFICATION
 *       GUID_PNP_POWER_NOTIFICATION
 *       GUID_DEVICE_* (see above)
 *
 * EventCategory
 *    Type of the event that happened.
 *
 * Result
 *    ?
 *
 * Flags
 *    ?
 *
 * TotalSize
 *    Size of the event block including the device IDs and other
 *    per category specific fields.
 */
/*
 * NtGetPlugPlayEvent
 *
 * Returns one Plug & Play event from a global queue.
 *
 * Parameters
 *    Reserved1
 *    Reserved2
 *       Always set to zero.
 *
 *    Buffer
 *       The buffer that will be filled with the event information on
 *       successful return from the function.
 *
 *    BufferSize
 *       Size of the buffer pointed by the Buffer parameter. If the
 *       buffer size is not large enough to hold the whole event
 *       information, error STATUS_BUFFER_TOO_SMALL is returned and
 *       the buffer remains untouched.
 *
 * Return Values
 *    STATUS_PRIVILEGE_NOT_HELD
 *    STATUS_BUFFER_TOO_SMALL
 *    STATUS_SUCCESS
 *
 * Remarks
 *    This function isn't multi-thread safe!
 *
 * @implemented
 */
NTSTATUS STDCALL
NtGetPlugPlayEvent(IN ULONG Reserved1,
                   IN ULONG Reserved2,
                   OUT PPLUGPLAY_EVENT_BLOCK Buffer,
                   IN ULONG BufferSize)
{
  PPNP_EVENT_ENTRY Entry;
  NTSTATUS Status;

  DPRINT("NtGetPlugPlayEvent() called\n");

  /* Function can only be called from user-mode */
  if (KeGetPreviousMode() == KernelMode)
  {
    DPRINT1("NtGetPlugPlayEvent cannot be called from kernel mode!\n");
    return STATUS_ACCESS_DENIED;
  }

  /* Check for Tcb privilege */
  if (!SeSinglePrivilegeCheck(SeTcbPrivilege,
                              UserMode))
  {
    DPRINT1("NtGetPlugPlayEvent: Caller does not hold the SeTcbPrivilege privilege!\n");
    return STATUS_PRIVILEGE_NOT_HELD;
  }

  /* Wait for a PnP event */
  DPRINT("Waiting for pnp notification event\n");
  Status = KeWaitForSingleObject(&IopPnpNotifyEvent,
                                 UserRequest,
                                 KernelMode,
                                 FALSE,
                                 NULL);
  if (!NT_SUCCESS(Status))
  {
    DPRINT1("KeWaitForSingleObject() failed (Status %lx)\n", Status);
    return Status;
  }

  /* Get entry from the tail of the queue */
  Entry = CONTAINING_RECORD(IopPnpEventQueueHead.Blink,
                            PNP_EVENT_ENTRY,
                            ListEntry);

  /* Check the buffer size */
  if (BufferSize < Entry->Event.TotalSize)
  {
    DPRINT1("Buffer is too small for the pnp-event\n");
    return STATUS_BUFFER_TOO_SMALL;
  }

  /* Copy event data to the user buffer */
  memcpy(Buffer,
         &Entry->Event,
         Entry->Event.TotalSize);

  DPRINT("NtGetPlugPlayEvent() done\n");

  return STATUS_SUCCESS;
}


static PDEVICE_OBJECT
IopTraverseDeviceNode(PDEVICE_NODE Node, PUNICODE_STRING DeviceInstance)
{
    PDEVICE_OBJECT DeviceObject;
    PDEVICE_NODE ChildNode;

    if (RtlEqualUnicodeString(&Node->InstancePath,
                              DeviceInstance, TRUE))
    {
        ObReferenceObject(Node->PhysicalDeviceObject);
        return Node->PhysicalDeviceObject;
    }

    /* Traversal of all children nodes */
    for (ChildNode = Node->Child;
         ChildNode != NULL;
         ChildNode = ChildNode->NextSibling)
    {
        DeviceObject = IopTraverseDeviceNode(ChildNode, DeviceInstance);
        if (DeviceObject != NULL)
        {
            return DeviceObject;
        }
    }

    return NULL;
}


static PDEVICE_OBJECT
IopGetDeviceObjectFromDeviceInstance(PUNICODE_STRING DeviceInstance)
{
#if 0
    OBJECT_ATTRIBUTES ObjectAttributes;
    UNICODE_STRING KeyName, ValueName;
    LPWSTR KeyNameBuffer;
    HANDLE InstanceKeyHandle;
    HANDLE ControlKeyHandle;
    NTSTATUS Status;
    PKEY_VALUE_PARTIAL_INFORMATION ValueInformation;
    ULONG ValueInformationLength;
    PDEVICE_OBJECT DeviceObject = NULL;

    DPRINT("IopGetDeviceObjectFromDeviceInstance(%wZ) called\n", DeviceInstance);

    KeyNameBuffer = ExAllocatePool(PagedPool,
                                   (49 * sizeof(WCHAR)) + DeviceInstance->Length);
    if (KeyNameBuffer == NULL)
    {
        DPRINT1("Failed to allocate key name buffer!\n");
        return NULL;
    }

    wcscpy(KeyNameBuffer, L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\");
    wcscat(KeyNameBuffer, DeviceInstance->Buffer);

    RtlInitUnicodeString(&KeyName,
                         KeyNameBuffer);
    InitializeObjectAttributes(&ObjectAttributes,
                               &KeyName,
                               OBJ_CASE_INSENSITIVE,
                               NULL,
                               NULL);

    Status = ZwOpenKey(&InstanceKeyHandle,
                       KEY_READ,
                       &ObjectAttributes);
    ExFreePool(KeyNameBuffer);
    if (!NT_SUCCESS(Status))
    {
        DPRINT1("Failed to open the instance key (Status %lx)\n", Status);
        return NULL;
    }

    /* Open the 'Control' subkey */
    RtlInitUnicodeString(&KeyName,
                         L"Control");
    InitializeObjectAttributes(&ObjectAttributes,
                               &KeyName,
                               OBJ_CASE_INSENSITIVE,
                               InstanceKeyHandle,
                               NULL);

    Status = ZwOpenKey(&ControlKeyHandle,
                       KEY_READ,
                       &ObjectAttributes);
    ZwClose(InstanceKeyHandle);
    if (!NT_SUCCESS(Status))
    {
        DPRINT1("Failed to open the 'Control' key (Status %lx)\n", Status);
        return NULL;
    }

    /* Query the 'DeviceReference' value */
    RtlInitUnicodeString(&ValueName,
                         L"DeviceReference");
    ValueInformationLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION,
                             Data[0]) + sizeof(ULONG);
    ValueInformation = ExAllocatePool(PagedPool, ValueInformationLength);
    if (ValueInformation == NULL)
    {
        DPRINT1("Failed to allocate the name information buffer!\n");
        ZwClose(ControlKeyHandle);
        return NULL;
    }

    Status = ZwQueryValueKey(ControlKeyHandle,
                             &ValueName,
                             KeyValuePartialInformation,
                             ValueInformation,
                             ValueInformationLength,
                             &ValueInformationLength);
    ZwClose(ControlKeyHandle);
    if (!NT_SUCCESS(Status))
    {
        DPRINT1("Failed to query the 'DeviceReference' value (Status %lx)\n", Status);
        return NULL;
    }

    /* Check the device object */
    RtlCopyMemory(&DeviceObject,
                  ValueInformation->Data,
                  sizeof(PDEVICE_OBJECT));

    DPRINT("DeviceObject: %p\n", DeviceObject);

    if (DeviceObject->Type != IO_TYPE_DEVICE ||
        DeviceObject->DeviceObjectExtension == NULL ||
        DeviceObject->DeviceObjectExtension->DeviceNode == NULL ||
        !RtlEqualUnicodeString(&DeviceObject->DeviceObjectExtension->DeviceNode->InstancePath,
                               DeviceInstance, TRUE))
    {
        DPRINT1("Invalid object type!\n");
        return NULL;
    }

    DPRINT("Instance path: %wZ\n", &DeviceObject->DeviceObjectExtension->DeviceNode->InstancePath);

    ObReferenceObject(DeviceObject);

    DPRINT("IopGetDeviceObjectFromDeviceInstance() done\n");

    return DeviceObject;
#endif

    if (IopRootDeviceNode == NULL)
        return NULL;

    if (DeviceInstance == NULL ||
        DeviceInstance->Length == 0
        )
    {
        if (IopRootDeviceNode->PhysicalDeviceObject)
        {
            ObReferenceObject(IopRootDeviceNode->PhysicalDeviceObject);
            return IopRootDeviceNode->PhysicalDeviceObject;
        }
        else
            return NULL;
    }

    return IopTraverseDeviceNode(IopRootDeviceNode, DeviceInstance);

}

static NTSTATUS
IopCaptureUnicodeString(PUNICODE_STRING DstName, PUNICODE_STRING SrcName)
{
    NTSTATUS Status = STATUS_SUCCESS;
    UNICODE_STRING Name;

    Name.Buffer = NULL;
    _SEH_TRY
    {
	Name.Length = SrcName->Length;
	Name.MaximumLength = SrcName->MaximumLength;
	if (Name.Length > Name.MaximumLength)
	{
	    Status = STATUS_INVALID_PARAMETER;
	    _SEH_LEAVE;
	}
	if (Name.MaximumLength)
	{
	    ProbeForRead(SrcName->Buffer,
		         Name.MaximumLength,
			 sizeof(WCHAR));
	    Name.Buffer = ExAllocatePool(NonPagedPool, Name.MaximumLength);
	    if (Name.Buffer == NULL)
	    {
		Status = STATUS_INSUFFICIENT_RESOURCES;
		_SEH_LEAVE;
	    }
	    memcpy(Name.Buffer, SrcName->Buffer, Name.MaximumLength);
	}
	*DstName = Name;
    }
    _SEH_HANDLE
    {
        Status = _SEH_GetExceptionCode();
    }
    _SEH_END;
    
    if (!NT_SUCCESS(Status) && Name.Buffer)
    {   
	ExFreePool(Name.Buffer);
    }
    return Status;
}

static NTSTATUS
IopGetDeviceProperty(PPLUGPLAY_CONTROL_PROPERTY_DATA PropertyData)
{
    PDEVICE_OBJECT DeviceObject = NULL;
    NTSTATUS Status = STATUS_SUCCESS;
    UNICODE_STRING DeviceInstance;
    ULONG BufferSize;
    ULONG Property = 0;
    PVOID Buffer;

    DPRINT("IopGetDeviceProperty() called\n");
    DPRINT("Device name: %wZ\n", &PropertyData->DeviceInstance);

    Status = IopCaptureUnicodeString(&DeviceInstance, &PropertyData->DeviceInstance);
    if (!NT_SUCCESS(Status))
    {
	return Status;
    }

    _SEH_TRY
    {
	Property = PropertyData->Property;
        BufferSize = PropertyData->BufferSize;
        ProbeForWrite(PropertyData->Buffer,
                      BufferSize,
                      sizeof(UCHAR));
    }
    _SEH_HANDLE
    {
        Status = _SEH_GetExceptionCode();
    }
    _SEH_END;
    
    if (!NT_SUCCESS(Status))
    {
	ExFreePool(DeviceInstance.Buffer);
	return Status;
    }

    /* Get the device object */
    DeviceObject = IopGetDeviceObjectFromDeviceInstance(&PropertyData->DeviceInstance);
    ExFreePool(DeviceInstance.Buffer);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -