You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
663 lines
18 KiB
663 lines
18 KiB
/*++
|
|
|
|
Copyright (c) 1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
win32.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the definition of the executive Win32 objects.
|
|
Functions to manage these objects are implemented in win32k.sys.
|
|
|
|
Author:
|
|
|
|
James I. Anderson (jima) 14-June-1995
|
|
|
|
Environment:
|
|
|
|
Kernel mode only.
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "exp.h"
|
|
|
|
//
|
|
// Address of windowstation and desktop object type descriptors.
|
|
//
|
|
|
|
POBJECT_TYPE ExWindowStationObjectType;
|
|
POBJECT_TYPE ExDesktopObjectType;
|
|
|
|
PKWIN32_CLOSEMETHOD_CALLOUT ExDesktopCloseProcedureCallout;
|
|
PKWIN32_CLOSEMETHOD_CALLOUT ExWindowStationCloseProcedureCallout;
|
|
PKWIN32_OPENMETHOD_CALLOUT ExDesktopOpenProcedureCallout;
|
|
PKWIN32_OKTOCLOSEMETHOD_CALLOUT ExDesktopOkToCloseProcedureCallout;
|
|
PKWIN32_OKTOCLOSEMETHOD_CALLOUT ExWindowStationOkToCloseProcedureCallout;
|
|
PKWIN32_DELETEMETHOD_CALLOUT ExDesktopDeleteProcedureCallout;
|
|
PKWIN32_DELETEMETHOD_CALLOUT ExWindowStationDeleteProcedureCallout;
|
|
PKWIN32_PARSEMETHOD_CALLOUT ExWindowStationParseProcedureCallout;
|
|
PKWIN32_OPENMETHOD_CALLOUT ExWindowStationOpenProcedureCallout;
|
|
|
|
//
|
|
// common types for above win32 callouts and parameters
|
|
//
|
|
|
|
typedef PVOID PKWIN32_CALLOUT_PARAMETERS;
|
|
|
|
typedef
|
|
NTSTATUS
|
|
(*PKWIN32_CALLOUT) (
|
|
IN PKWIN32_CALLOUT_PARAMETERS
|
|
);
|
|
|
|
NTSTATUS
|
|
ExpWin32SessionCallout(
|
|
IN PKWIN32_CALLOUT CalloutRoutine,
|
|
IN PKWIN32_CALLOUT_PARAMETERS Parameters,
|
|
IN ULONG SessionId,
|
|
OUT PNTSTATUS CalloutStatus OPTIONAL
|
|
);
|
|
|
|
VOID
|
|
ExpWin32CloseProcedure(
|
|
IN PEPROCESS Process OPTIONAL,
|
|
IN PVOID Object,
|
|
IN ACCESS_MASK GrantedAccess,
|
|
IN ULONG_PTR ProcessHandleCount,
|
|
IN ULONG_PTR SystemHandleCount );
|
|
|
|
BOOLEAN
|
|
ExpWin32OkayToCloseProcedure(
|
|
IN PEPROCESS Process OPTIONAL,
|
|
IN PVOID Object,
|
|
IN HANDLE Handle,
|
|
IN KPROCESSOR_MODE PreviousMode
|
|
);
|
|
|
|
VOID
|
|
ExpWin32DeleteProcedure(
|
|
IN PVOID Object
|
|
);
|
|
|
|
NTSTATUS
|
|
ExpWin32ParseProcedure (
|
|
IN PVOID ParseObject,
|
|
IN PVOID ObjectType,
|
|
IN OUT PACCESS_STATE AccessState,
|
|
IN KPROCESSOR_MODE AccessMode,
|
|
IN ULONG Attributes,
|
|
IN OUT PUNICODE_STRING CompleteName,
|
|
IN OUT PUNICODE_STRING RemainingName,
|
|
IN OUT PVOID Context OPTIONAL,
|
|
IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,
|
|
OUT PVOID *Object
|
|
);
|
|
|
|
NTSTATUS
|
|
ExpWin32OpenProcedure(
|
|
IN OB_OPEN_REASON OpenReason,
|
|
IN PEPROCESS Process OPTIONAL,
|
|
IN PVOID Object,
|
|
IN ACCESS_MASK GrantedAccess,
|
|
IN ULONG HandleCount
|
|
);
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text (INIT, ExpWin32Initialization)
|
|
#pragma alloc_text (PAGE, ExpWin32CloseProcedure)
|
|
#pragma alloc_text (PAGE, ExpWin32OkayToCloseProcedure)
|
|
#pragma alloc_text (PAGE, ExpWin32DeleteProcedure)
|
|
#pragma alloc_text (PAGE, ExpWin32OpenProcedure)
|
|
#pragma alloc_text (PAGE, ExpWin32ParseProcedure)
|
|
#pragma alloc_text (PAGE, ExpWin32SessionCallout)
|
|
#endif
|
|
|
|
|
|
/*
|
|
* windowstation generic mapping
|
|
*/
|
|
#ifdef ALLOC_DATA_PRAGMA
|
|
#pragma const_seg("INITCONST")
|
|
#endif
|
|
const GENERIC_MAPPING ExpWindowStationMapping = {
|
|
STANDARD_RIGHTS_READ,
|
|
STANDARD_RIGHTS_WRITE,
|
|
STANDARD_RIGHTS_EXECUTE,
|
|
STANDARD_RIGHTS_REQUIRED
|
|
};
|
|
|
|
/*
|
|
* desktop generic mapping
|
|
*/
|
|
const GENERIC_MAPPING ExpDesktopMapping = {
|
|
STANDARD_RIGHTS_READ,
|
|
STANDARD_RIGHTS_WRITE,
|
|
STANDARD_RIGHTS_EXECUTE,
|
|
STANDARD_RIGHTS_REQUIRED
|
|
};
|
|
#ifdef ALLOC_DATA_PRAGMA
|
|
#pragma const_seg()
|
|
#endif
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Close Procedure for Win32k windostation and desktop objects
|
|
|
|
Arguments:
|
|
Defined by OB_CLOSE_METHOD
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
VOID ExpWin32CloseProcedure(
|
|
IN PEPROCESS Process OPTIONAL,
|
|
IN PVOID Object,
|
|
IN ACCESS_MASK GrantedAccess,
|
|
IN ULONG_PTR ProcessHandleCount,
|
|
IN ULONG_PTR SystemHandleCount )
|
|
{
|
|
|
|
//
|
|
// SessionId is the first field in the Win32k Object structure
|
|
//
|
|
ULONG SessionId = *((PULONG)Object);
|
|
WIN32_CLOSEMETHOD_PARAMETERS CloseParams;
|
|
NTSTATUS Status;
|
|
|
|
CloseParams.Process = Process;
|
|
CloseParams.Object = Object;
|
|
CloseParams.GrantedAccess = GrantedAccess;
|
|
CloseParams.ProcessHandleCount = (ULONG)ProcessHandleCount;
|
|
CloseParams.SystemHandleCount = (ULONG)SystemHandleCount;
|
|
|
|
if ((OBJECT_TO_OBJECT_HEADER(Object)->Type) == ExDesktopObjectType) {
|
|
|
|
Status = ExpWin32SessionCallout((PKWIN32_CALLOUT)ExDesktopCloseProcedureCallout,
|
|
(PKWIN32_CALLOUT_PARAMETERS)&CloseParams,
|
|
SessionId,
|
|
NULL);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
} else if ((OBJECT_TO_OBJECT_HEADER(Object)->Type) == ExWindowStationObjectType) {
|
|
|
|
Status = ExpWin32SessionCallout((PKWIN32_CALLOUT)ExWindowStationCloseProcedureCallout,
|
|
(PKWIN32_CALLOUT_PARAMETERS)&CloseParams,
|
|
SessionId,
|
|
NULL);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
} else {
|
|
ASSERT((OBJECT_TO_OBJECT_HEADER(Object)->Type) == ExDesktopObjectType || (OBJECT_TO_OBJECT_HEADER(Object)->Type == ExWindowStationObjectType));
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
OkayToClose Procedure for Win32k windostation and desktop objects
|
|
|
|
Arguments:
|
|
Defined by OB_OKAYTOCLOSE_METHOD
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
BOOLEAN ExpWin32OkayToCloseProcedure(
|
|
IN PEPROCESS Process OPTIONAL,
|
|
IN PVOID Object,
|
|
IN HANDLE Handle,
|
|
IN KPROCESSOR_MODE PreviousMode
|
|
)
|
|
{
|
|
//
|
|
// SessionId is the first field in the Win32k Object structure
|
|
//
|
|
ULONG SessionId = *((PULONG)Object);
|
|
WIN32_OKAYTOCLOSEMETHOD_PARAMETERS OKToCloseParams;
|
|
NTSTATUS Status, CallStatus = STATUS_UNSUCCESSFUL;
|
|
|
|
OKToCloseParams.Process = Process;
|
|
OKToCloseParams.Object = Object;
|
|
OKToCloseParams.Handle = Handle;
|
|
OKToCloseParams.PreviousMode = PreviousMode;
|
|
|
|
if (OBJECT_TO_OBJECT_HEADER(Object)->Type == ExDesktopObjectType) {
|
|
|
|
Status = ExpWin32SessionCallout((PKWIN32_CALLOUT)ExDesktopOkToCloseProcedureCallout,
|
|
(PKWIN32_CALLOUT_PARAMETERS)&OKToCloseParams,
|
|
SessionId,
|
|
&CallStatus);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
} else if (OBJECT_TO_OBJECT_HEADER(Object)->Type == ExWindowStationObjectType) {
|
|
|
|
Status = ExpWin32SessionCallout((PKWIN32_CALLOUT)ExWindowStationOkToCloseProcedureCallout,
|
|
(PKWIN32_CALLOUT_PARAMETERS)&OKToCloseParams,
|
|
SessionId,
|
|
&CallStatus);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
} else {
|
|
ASSERT(OBJECT_TO_OBJECT_HEADER(Object)->Type == ExDesktopObjectType ||
|
|
OBJECT_TO_OBJECT_HEADER(Object)->Type == ExWindowStationObjectType);
|
|
|
|
}
|
|
|
|
return (BOOLEAN)(NT_SUCCESS(CallStatus));
|
|
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Delete Procedure for Win32k windostation and desktop objects
|
|
|
|
Arguments:
|
|
Defined by OB_DELETE_METHOD
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
VOID ExpWin32DeleteProcedure(
|
|
IN PVOID Object
|
|
)
|
|
{
|
|
//
|
|
// SessionId is the first field in the Win32k Object structure
|
|
//
|
|
ULONG SessionId = *((PULONG)Object);
|
|
WIN32_DELETEMETHOD_PARAMETERS DeleteParams;
|
|
NTSTATUS Status;
|
|
|
|
DeleteParams.Object = Object;
|
|
|
|
|
|
if (OBJECT_TO_OBJECT_HEADER(Object)->Type == ExDesktopObjectType) {
|
|
|
|
Status = ExpWin32SessionCallout((PKWIN32_CALLOUT)ExDesktopDeleteProcedureCallout,
|
|
(PKWIN32_CALLOUT_PARAMETERS)&DeleteParams,
|
|
SessionId,
|
|
NULL);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
} else if (OBJECT_TO_OBJECT_HEADER(Object)->Type == ExWindowStationObjectType) {
|
|
|
|
Status = ExpWin32SessionCallout((PKWIN32_CALLOUT)ExWindowStationDeleteProcedureCallout,
|
|
(PKWIN32_CALLOUT_PARAMETERS)&DeleteParams,
|
|
SessionId,
|
|
NULL);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
} else {
|
|
ASSERT(OBJECT_TO_OBJECT_HEADER(Object)->Type == ExDesktopObjectType ||
|
|
OBJECT_TO_OBJECT_HEADER(Object)->Type == ExWindowStationObjectType);
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Open Procedure for Win32k desktop objects
|
|
|
|
Arguments:
|
|
Defined by OB_OPEN_METHOD
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
|
|
NTSTATUS
|
|
ExpWin32OpenProcedure(
|
|
IN OB_OPEN_REASON OpenReason,
|
|
IN PEPROCESS Process OPTIONAL,
|
|
IN PVOID Object,
|
|
IN ACCESS_MASK GrantedAccess,
|
|
IN ULONG HandleCount
|
|
)
|
|
{
|
|
|
|
//
|
|
// SessionId is the first field in the Win32k Object structure
|
|
//
|
|
ULONG SessionId = *((PULONG)Object);
|
|
WIN32_OPENMETHOD_PARAMETERS OpenParams;
|
|
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
|
|
|
OpenParams.OpenReason = OpenReason;
|
|
OpenParams.Process = Process;
|
|
OpenParams.Object = Object;
|
|
OpenParams.GrantedAccess = GrantedAccess;
|
|
OpenParams.HandleCount = HandleCount;
|
|
|
|
|
|
if ((OBJECT_TO_OBJECT_HEADER(Object)->Type) == ExDesktopObjectType) {
|
|
|
|
Status = ExpWin32SessionCallout((PKWIN32_CALLOUT)ExDesktopOpenProcedureCallout,
|
|
(PKWIN32_CALLOUT_PARAMETERS)&OpenParams,
|
|
SessionId,
|
|
NULL);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
} else if ((OBJECT_TO_OBJECT_HEADER(Object)->Type) == ExWindowStationObjectType) {
|
|
|
|
Status = ExpWin32SessionCallout((PKWIN32_CALLOUT)ExWindowStationOpenProcedureCallout,
|
|
(PKWIN32_CALLOUT_PARAMETERS)&OpenParams,
|
|
SessionId,
|
|
NULL);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
} else {
|
|
ASSERT((OBJECT_TO_OBJECT_HEADER(Object)->Type) == ExDesktopObjectType || (OBJECT_TO_OBJECT_HEADER(Object)->Type == ExWindowStationObjectType));
|
|
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Parse Procedure for Win32k windostation objects
|
|
|
|
Arguments:
|
|
Defined by OB_PARSE_METHOD
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
|
|
NTSTATUS ExpWin32ParseProcedure (
|
|
IN PVOID ParseObject,
|
|
IN PVOID ObjectType,
|
|
IN OUT PACCESS_STATE AccessState,
|
|
IN KPROCESSOR_MODE AccessMode,
|
|
IN ULONG Attributes,
|
|
IN OUT PUNICODE_STRING CompleteName,
|
|
IN OUT PUNICODE_STRING RemainingName,
|
|
IN OUT PVOID Context OPTIONAL,
|
|
IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,
|
|
OUT PVOID *Object
|
|
)
|
|
{
|
|
|
|
//
|
|
// SessionId is the first field in the Win32k Object structure
|
|
//
|
|
ULONG SessionId = *((PULONG)ParseObject);
|
|
WIN32_PARSEMETHOD_PARAMETERS ParseParams;
|
|
NTSTATUS Status, CallStatus = STATUS_UNSUCCESSFUL;
|
|
|
|
ParseParams.ParseObject = ParseObject;
|
|
ParseParams.ObjectType = ObjectType;
|
|
ParseParams.AccessState = AccessState;
|
|
ParseParams.AccessMode = AccessMode;
|
|
ParseParams.Attributes = Attributes;
|
|
ParseParams.CompleteName = CompleteName;
|
|
ParseParams.RemainingName = RemainingName;
|
|
ParseParams.Context = Context;
|
|
ParseParams.SecurityQos = SecurityQos;
|
|
ParseParams.Object = Object;
|
|
|
|
//
|
|
// Parse Procedure is only provided for WindowStation objects
|
|
//
|
|
Status = ExpWin32SessionCallout((PKWIN32_CALLOUT)ExWindowStationParseProcedureCallout,
|
|
(PKWIN32_CALLOUT_PARAMETERS)&ParseParams,
|
|
SessionId,
|
|
&CallStatus);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
return CallStatus;
|
|
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
ExpWin32Initialization (
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function creates the Win32 object type descriptors at system
|
|
initialization and stores the address of the object type descriptor
|
|
in local static storage.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
A value of TRUE is returned if the Win32 object type descriptors are
|
|
successfully created. Otherwise a value of FALSE is returned.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
|
|
NTSTATUS Status;
|
|
UNICODE_STRING TypeName;
|
|
|
|
//
|
|
// Initialize string descriptor.
|
|
//
|
|
|
|
RtlInitUnicodeString(&TypeName, L"WindowStation");
|
|
|
|
//
|
|
// Create windowstation object type descriptor.
|
|
//
|
|
|
|
RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
|
|
ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
|
|
ObjectTypeInitializer.GenericMapping = ExpWindowStationMapping;
|
|
ObjectTypeInitializer.SecurityRequired = TRUE;
|
|
ObjectTypeInitializer.PoolType = NonPagedPool;
|
|
|
|
ObjectTypeInitializer.CloseProcedure = ExpWin32CloseProcedure;
|
|
ObjectTypeInitializer.DeleteProcedure = ExpWin32DeleteProcedure;
|
|
ObjectTypeInitializer.OkayToCloseProcedure = ExpWin32OkayToCloseProcedure;
|
|
|
|
ObjectTypeInitializer.ParseProcedure = ExpWin32ParseProcedure;
|
|
ObjectTypeInitializer.OpenProcedure = ExpWin32OpenProcedure;
|
|
|
|
ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK |
|
|
OBJ_PERMANENT |
|
|
OBJ_EXCLUSIVE;
|
|
ObjectTypeInitializer.ValidAccessMask = STANDARD_RIGHTS_REQUIRED;
|
|
Status = ObCreateObjectType(&TypeName,
|
|
&ObjectTypeInitializer,
|
|
(PSECURITY_DESCRIPTOR)NULL,
|
|
&ExWindowStationObjectType);
|
|
|
|
//
|
|
// If the windowstation object type descriptor was not successfully
|
|
// created, then return a value of FALSE.
|
|
//
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
return FALSE;
|
|
|
|
|
|
|
|
//
|
|
// Initialize string descriptor.
|
|
//
|
|
|
|
RtlInitUnicodeString(&TypeName, L"Desktop");
|
|
|
|
ObjectTypeInitializer.ParseProcedure = NULL; //Desktop has no Parse Procedure
|
|
|
|
//
|
|
// Create windowstation object type descriptor.
|
|
//
|
|
|
|
ObjectTypeInitializer.GenericMapping = ExpDesktopMapping;
|
|
Status = ObCreateObjectType(&TypeName,
|
|
&ObjectTypeInitializer,
|
|
(PSECURITY_DESCRIPTOR)NULL,
|
|
&ExDesktopObjectType);
|
|
|
|
|
|
//
|
|
// If the desktop object type descriptor was successfully created, then
|
|
// return a value of TRUE. Otherwise return a value of FALSE.
|
|
//
|
|
|
|
return (BOOLEAN)(NT_SUCCESS(Status));
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
ExpWin32SessionCallout(
|
|
IN PKWIN32_CALLOUT CalloutRoutine,
|
|
IN PKWIN32_CALLOUT_PARAMETERS Parameters,
|
|
IN ULONG SessionId,
|
|
OUT PNTSTATUS CalloutStatus OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine calls the specified callout routine in session space, for the
|
|
specified session.
|
|
|
|
Parameters:
|
|
|
|
CalloutRoutine - Callout routine in session space.
|
|
|
|
Parameters - Parameters to pass the callout routine.
|
|
|
|
SessionId - Specifies the ID of the session in which the specified
|
|
callout routine is to be called.
|
|
|
|
CalloutStatus - Optionally, supplies the address of a variable to receive
|
|
the NTSTATUS code returned by the callout routine.
|
|
|
|
Return Value:
|
|
|
|
Status code that indicates whether or not the function was successful.
|
|
|
|
Notes:
|
|
|
|
Returns STATUS_NOT_FOUND if the specified session was not found.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status, CallStatus;
|
|
PVOID OpaqueSession;
|
|
KAPC_STATE ApcState;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Make sure we have all the information we need to deliver notification.
|
|
//
|
|
if (CalloutRoutine == NULL) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Make sure the callout routine in session space.
|
|
//
|
|
ASSERT(MmIsSessionAddress((PVOID)CalloutRoutine));
|
|
|
|
if ((PsGetCurrentProcess()->Flags & PS_PROCESS_FLAGS_IN_SESSION) &&
|
|
(SessionId == PsGetCurrentProcessSessionId())) {
|
|
//
|
|
// If the call is from a user mode process, and we are asked to call the
|
|
// current session, call directly.
|
|
//
|
|
CallStatus = (CalloutRoutine)(Parameters);
|
|
|
|
//
|
|
// Return the callout status.
|
|
//
|
|
if (ARGUMENT_PRESENT(CalloutStatus)) {
|
|
*CalloutStatus = CallStatus;
|
|
}
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
} else {
|
|
//
|
|
// Reference the session object for the specified session.
|
|
//
|
|
OpaqueSession = MmGetSessionById(SessionId);
|
|
if (OpaqueSession == NULL) {
|
|
return STATUS_NOT_FOUND;
|
|
}
|
|
|
|
//
|
|
// Attach to the specified session.
|
|
//
|
|
Status = MmAttachSession(OpaqueSession, &ApcState);
|
|
if (!NT_SUCCESS(Status)) {
|
|
KdPrintEx((DPFLTR_SYSTEM_ID, DPFLTR_WARNING_LEVEL,
|
|
"ExpWin32SessionCallout: "
|
|
"could not attach to 0x%p, session %d for registered notification callout @ 0x%p\n",
|
|
OpaqueSession,
|
|
SessionId,
|
|
CalloutRoutine));
|
|
MmQuitNextSession(OpaqueSession);
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Dispatch notification to the callout routine.
|
|
//
|
|
CallStatus = (CalloutRoutine)(Parameters);
|
|
|
|
//
|
|
// Return the callout status.
|
|
//
|
|
if (ARGUMENT_PRESENT(CalloutStatus)) {
|
|
*CalloutStatus = CallStatus;
|
|
}
|
|
|
|
//
|
|
// Detach from the session.
|
|
//
|
|
Status = MmDetachSession(OpaqueSession, &ApcState);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
//
|
|
// Dereference the session object.
|
|
//
|
|
Status = MmQuitNextSession(OpaqueSession);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
}
|
|
|
|
return Status;
|
|
}
|