1196 lines
36 KiB
C
1196 lines
36 KiB
C
/*
|
|
* ntoskrnl.exe implementation
|
|
*
|
|
* Copyright (C) 2007 Alexandre Julliard
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include "wine/port.h"
|
|
|
|
#include <stdarg.h>
|
|
|
|
#define NONAMELESSUNION
|
|
#define NONAMELESSSTRUCT
|
|
|
|
#include "ntstatus.h"
|
|
#define WIN32_NO_STATUS
|
|
#include "windef.h"
|
|
#include "winternl.h"
|
|
#include "excpt.h"
|
|
#include "ddk/ntddk.h"
|
|
#include "wine/unicode.h"
|
|
#include "wine/server.h"
|
|
#include "wine/list.h"
|
|
#include "wine/debug.h"
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(ntoskrnl);
|
|
WINE_DECLARE_DEBUG_CHANNEL(relay);
|
|
|
|
|
|
KSYSTEM_TIME KeTickCount = { 0, 0, 0 };
|
|
|
|
typedef struct _KSERVICE_TABLE_DESCRIPTOR
|
|
{
|
|
PULONG_PTR Base;
|
|
PULONG Count;
|
|
ULONG Limit;
|
|
PUCHAR Number;
|
|
} KSERVICE_TABLE_DESCRIPTOR, *PKSERVICE_TABLE_DESCRIPTOR;
|
|
|
|
KSERVICE_TABLE_DESCRIPTOR KeServiceDescriptorTable[4] = { { 0 } };
|
|
|
|
typedef void (WINAPI *PCREATE_PROCESS_NOTIFY_ROUTINE)(HANDLE,HANDLE,BOOLEAN);
|
|
typedef void (WINAPI *PCREATE_THREAD_NOTIFY_ROUTINE)(HANDLE,HANDLE,BOOLEAN);
|
|
|
|
static struct list Irps = LIST_INIT(Irps);
|
|
|
|
struct IrpInstance
|
|
{
|
|
struct list entry;
|
|
IRP *irp;
|
|
};
|
|
|
|
#ifdef __i386__
|
|
#define DEFINE_FASTCALL1_ENTRYPOINT( name ) \
|
|
__ASM_GLOBAL_FUNC( name, \
|
|
"popl %eax\n\t" \
|
|
"pushl %ecx\n\t" \
|
|
"pushl %eax\n\t" \
|
|
"jmp " __ASM_NAME("__regs_") #name )
|
|
#define DEFINE_FASTCALL2_ENTRYPOINT( name ) \
|
|
__ASM_GLOBAL_FUNC( name, \
|
|
"popl %eax\n\t" \
|
|
"pushl %edx\n\t" \
|
|
"pushl %ecx\n\t" \
|
|
"pushl %eax\n\t" \
|
|
"jmp " __ASM_NAME("__regs_") #name )
|
|
#endif
|
|
|
|
static inline LPCSTR debugstr_us( const UNICODE_STRING *us )
|
|
{
|
|
if (!us) return "<null>";
|
|
return debugstr_wn( us->Buffer, us->Length / sizeof(WCHAR) );
|
|
}
|
|
|
|
static HANDLE get_device_manager(void)
|
|
{
|
|
static HANDLE device_manager;
|
|
HANDLE handle = 0, ret = device_manager;
|
|
|
|
if (!ret)
|
|
{
|
|
SERVER_START_REQ( create_device_manager )
|
|
{
|
|
req->access = SYNCHRONIZE;
|
|
req->attributes = 0;
|
|
if (!wine_server_call( req )) handle = wine_server_ptr_handle( reply->handle );
|
|
}
|
|
SERVER_END_REQ;
|
|
|
|
if (!handle)
|
|
{
|
|
ERR( "failed to create the device manager\n" );
|
|
return 0;
|
|
}
|
|
if (!(ret = InterlockedCompareExchangePointer( &device_manager, handle, 0 )))
|
|
ret = handle;
|
|
else
|
|
NtClose( handle ); /* somebody beat us to it */
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/* exception handler for emulation of privileged instructions */
|
|
static LONG CALLBACK vectored_handler( EXCEPTION_POINTERS *ptrs )
|
|
{
|
|
EXCEPTION_RECORD *record = ptrs->ExceptionRecord;
|
|
|
|
if (record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION ||
|
|
record->ExceptionCode == EXCEPTION_PRIV_INSTRUCTION)
|
|
{
|
|
#ifdef __i386__
|
|
CONTEXT *context = ptrs->ContextRecord;
|
|
extern DWORD __wine_emulate_instruction( EXCEPTION_RECORD *rec, CONTEXT *context );
|
|
|
|
if (__wine_emulate_instruction( record, context ) == ExceptionContinueExecution)
|
|
return EXCEPTION_CONTINUE_EXECUTION;
|
|
#else
|
|
FIXME( "Privileged instruction emulation not implemented on this CPU\n" );
|
|
#endif
|
|
}
|
|
return EXCEPTION_CONTINUE_SEARCH;
|
|
}
|
|
|
|
/* process an ioctl request for a given device */
|
|
static NTSTATUS process_ioctl( DEVICE_OBJECT *device, ULONG code, void *in_buff, ULONG in_size,
|
|
void *out_buff, ULONG *out_size )
|
|
{
|
|
IRP irp;
|
|
MDL mdl;
|
|
IO_STACK_LOCATION irpsp;
|
|
PDRIVER_DISPATCH dispatch = device->DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL];
|
|
NTSTATUS status;
|
|
LARGE_INTEGER count;
|
|
|
|
TRACE( "ioctl %x device %p in_size %u out_size %u\n", code, device, in_size, *out_size );
|
|
|
|
/* so we can spot things that we should initialize */
|
|
memset( &irp, 0x55, sizeof(irp) );
|
|
memset( &irpsp, 0x66, sizeof(irpsp) );
|
|
memset( &mdl, 0x77, sizeof(mdl) );
|
|
|
|
irp.RequestorMode = UserMode;
|
|
irp.AssociatedIrp.SystemBuffer = in_buff;
|
|
irp.UserBuffer = out_buff;
|
|
irp.MdlAddress = &mdl;
|
|
irp.Tail.Overlay.s.u.CurrentStackLocation = &irpsp;
|
|
irp.UserIosb = NULL;
|
|
|
|
irpsp.MajorFunction = IRP_MJ_DEVICE_CONTROL;
|
|
irpsp.Parameters.DeviceIoControl.OutputBufferLength = *out_size;
|
|
irpsp.Parameters.DeviceIoControl.InputBufferLength = in_size;
|
|
irpsp.Parameters.DeviceIoControl.IoControlCode = code;
|
|
irpsp.Parameters.DeviceIoControl.Type3InputBuffer = in_buff;
|
|
irpsp.DeviceObject = device;
|
|
irpsp.CompletionRoutine = NULL;
|
|
|
|
mdl.Next = NULL;
|
|
mdl.Size = 0;
|
|
mdl.StartVa = out_buff;
|
|
mdl.ByteCount = *out_size;
|
|
mdl.ByteOffset = 0;
|
|
|
|
device->CurrentIrp = &irp;
|
|
|
|
KeQueryTickCount( &count ); /* update the global KeTickCount */
|
|
|
|
if (TRACE_ON(relay))
|
|
DPRINTF( "%04x:Call driver dispatch %p (device=%p,irp=%p)\n",
|
|
GetCurrentThreadId(), dispatch, device, &irp );
|
|
|
|
status = dispatch( device, &irp );
|
|
|
|
if (TRACE_ON(relay))
|
|
DPRINTF( "%04x:Ret driver dispatch %p (device=%p,irp=%p) retval=%08x\n",
|
|
GetCurrentThreadId(), dispatch, device, &irp, status );
|
|
|
|
*out_size = (irp.IoStatus.u.Status >= 0) ? irp.IoStatus.Information : 0;
|
|
return irp.IoStatus.u.Status;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* wine_ntoskrnl_main_loop (Not a Windows API)
|
|
*/
|
|
NTSTATUS CDECL wine_ntoskrnl_main_loop( HANDLE stop_event )
|
|
{
|
|
HANDLE manager = get_device_manager();
|
|
obj_handle_t ioctl = 0;
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
ULONG code = 0;
|
|
void *in_buff, *out_buff = NULL;
|
|
DEVICE_OBJECT *device = NULL;
|
|
ULONG in_size = 4096, out_size = 0;
|
|
HANDLE handles[2];
|
|
|
|
if (!(in_buff = HeapAlloc( GetProcessHeap(), 0, in_size )))
|
|
{
|
|
ERR( "failed to allocate buffer\n" );
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
handles[0] = stop_event;
|
|
handles[1] = manager;
|
|
|
|
for (;;)
|
|
{
|
|
SERVER_START_REQ( get_next_device_request )
|
|
{
|
|
req->manager = wine_server_obj_handle( manager );
|
|
req->prev = ioctl;
|
|
req->status = status;
|
|
wine_server_add_data( req, out_buff, out_size );
|
|
wine_server_set_reply( req, in_buff, in_size );
|
|
if (!(status = wine_server_call( req )))
|
|
{
|
|
code = reply->code;
|
|
ioctl = reply->next;
|
|
device = wine_server_get_ptr( reply->user_ptr );
|
|
in_size = reply->in_size;
|
|
out_size = reply->out_size;
|
|
}
|
|
else
|
|
{
|
|
ioctl = 0; /* no previous ioctl */
|
|
out_size = 0;
|
|
in_size = reply->in_size;
|
|
}
|
|
}
|
|
SERVER_END_REQ;
|
|
|
|
switch(status)
|
|
{
|
|
case STATUS_SUCCESS:
|
|
HeapFree( GetProcessHeap(), 0, out_buff );
|
|
if (out_size) out_buff = HeapAlloc( GetProcessHeap(), 0, out_size );
|
|
else out_buff = NULL;
|
|
status = process_ioctl( device, code, in_buff, in_size, out_buff, &out_size );
|
|
break;
|
|
case STATUS_BUFFER_OVERFLOW:
|
|
HeapFree( GetProcessHeap(), 0, in_buff );
|
|
in_buff = HeapAlloc( GetProcessHeap(), 0, in_size );
|
|
/* restart with larger buffer */
|
|
break;
|
|
case STATUS_PENDING:
|
|
if (WaitForMultipleObjects( 2, handles, FALSE, INFINITE ) == WAIT_OBJECT_0)
|
|
{
|
|
HeapFree( GetProcessHeap(), 0, in_buff );
|
|
HeapFree( GetProcessHeap(), 0, out_buff );
|
|
return STATUS_SUCCESS;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* IoAllocateDriverObjectExtension (NTOSKRNL.EXE.@)
|
|
*/
|
|
NTSTATUS WINAPI IoAllocateDriverObjectExtension( PDRIVER_OBJECT DriverObject,
|
|
PVOID ClientIdentificationAddress,
|
|
ULONG DriverObjectExtensionSize,
|
|
PVOID *DriverObjectExtension )
|
|
{
|
|
FIXME( "stub: %p, %p, %u, %p\n", DriverObject, ClientIdentificationAddress,
|
|
DriverObjectExtensionSize, DriverObjectExtension );
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* IoGetDriverObjectExtension (NTOSKRNL.EXE.@)
|
|
*/
|
|
PVOID WINAPI IoGetDriverObjectExtension( PDRIVER_OBJECT DriverObject,
|
|
PVOID ClientIdentificationAddress )
|
|
{
|
|
FIXME( "stub: %p, %p\n", DriverObject, ClientIdentificationAddress );
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* IoInitializeIrp (NTOSKRNL.EXE.@)
|
|
*/
|
|
void WINAPI IoInitializeIrp( IRP *irp, USHORT size, CCHAR stack_size )
|
|
{
|
|
TRACE( "%p, %u, %d\n", irp, size, stack_size );
|
|
|
|
RtlZeroMemory( irp, size );
|
|
|
|
irp->Type = IO_TYPE_IRP;
|
|
irp->Size = size;
|
|
InitializeListHead( &irp->ThreadListEntry );
|
|
irp->StackCount = stack_size;
|
|
irp->CurrentLocation = stack_size + 1;
|
|
irp->Tail.Overlay.s.u.CurrentStackLocation =
|
|
(PIO_STACK_LOCATION)(irp + 1) + stack_size;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* IoAllocateIrp (NTOSKRNL.EXE.@)
|
|
*/
|
|
PIRP WINAPI IoAllocateIrp( CCHAR stack_size, BOOLEAN charge_quota )
|
|
{
|
|
SIZE_T size;
|
|
PIRP irp;
|
|
|
|
TRACE( "%d, %d\n", stack_size, charge_quota );
|
|
|
|
size = sizeof(IRP) + stack_size * sizeof(IO_STACK_LOCATION);
|
|
irp = ExAllocatePool( NonPagedPool, size );
|
|
if (irp == NULL)
|
|
return NULL;
|
|
IoInitializeIrp( irp, size, stack_size );
|
|
irp->AllocationFlags = IRP_ALLOCATED_FIXED_SIZE;
|
|
if (charge_quota)
|
|
irp->AllocationFlags |= IRP_LOOKASIDE_ALLOCATION;
|
|
return irp;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* IoFreeIrp (NTOSKRNL.EXE.@)
|
|
*/
|
|
void WINAPI IoFreeIrp( IRP *irp )
|
|
{
|
|
TRACE( "%p\n", irp );
|
|
|
|
ExFreePool( irp );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* IoAllocateMdl (NTOSKRNL.EXE.@)
|
|
*/
|
|
PMDL WINAPI IoAllocateMdl( PVOID VirtualAddress, ULONG Length, BOOLEAN SecondaryBuffer, BOOLEAN ChargeQuota, PIRP Irp )
|
|
{
|
|
FIXME( "stub: %p, %u, %i, %i, %p\n", VirtualAddress, Length, SecondaryBuffer, ChargeQuota, Irp );
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* IoAllocateWorkItem (NTOSKRNL.EXE.@)
|
|
*/
|
|
PIO_WORKITEM WINAPI IoAllocateWorkItem( PDEVICE_OBJECT DeviceObject )
|
|
{
|
|
FIXME( "stub: %p\n", DeviceObject );
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* IoAttachDeviceToDeviceStack (NTOSKRNL.EXE.@)
|
|
*/
|
|
PDEVICE_OBJECT WINAPI IoAttachDeviceToDeviceStack( DEVICE_OBJECT *source,
|
|
DEVICE_OBJECT *target )
|
|
{
|
|
TRACE( "%p, %p\n", source, target );
|
|
target->AttachedDevice = source;
|
|
source->StackSize = target->StackSize + 1;
|
|
return target;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* IoBuildDeviceIoControlRequest (NTOSKRNL.EXE.@)
|
|
*/
|
|
PIRP WINAPI IoBuildDeviceIoControlRequest( ULONG IoControlCode,
|
|
PDEVICE_OBJECT DeviceObject,
|
|
PVOID InputBuffer,
|
|
ULONG InputBufferLength,
|
|
PVOID OutputBuffer,
|
|
ULONG OutputBufferLength,
|
|
BOOLEAN InternalDeviceIoControl,
|
|
PKEVENT Event,
|
|
PIO_STATUS_BLOCK IoStatusBlock )
|
|
{
|
|
PIRP irp;
|
|
PIO_STACK_LOCATION irpsp;
|
|
struct IrpInstance *instance;
|
|
|
|
TRACE( "%x, %p, %p, %u, %p, %u, %u, %p, %p\n",
|
|
IoControlCode, DeviceObject, InputBuffer, InputBufferLength,
|
|
OutputBuffer, OutputBufferLength, InternalDeviceIoControl,
|
|
Event, IoStatusBlock );
|
|
|
|
if (DeviceObject == NULL)
|
|
return NULL;
|
|
|
|
irp = IoAllocateIrp( DeviceObject->StackSize, FALSE );
|
|
if (irp == NULL)
|
|
return NULL;
|
|
|
|
instance = HeapAlloc( GetProcessHeap(), 0, sizeof(struct IrpInstance) );
|
|
if (instance == NULL)
|
|
{
|
|
IoFreeIrp( irp );
|
|
return NULL;
|
|
}
|
|
instance->irp = irp;
|
|
list_add_tail( &Irps, &instance->entry );
|
|
|
|
irpsp = irp->Tail.Overlay.s.u.CurrentStackLocation - 1;
|
|
irpsp->MajorFunction = InternalDeviceIoControl ?
|
|
IRP_MJ_INTERNAL_DEVICE_CONTROL : IRP_MJ_DEVICE_CONTROL;
|
|
irpsp->Parameters.DeviceIoControl.IoControlCode = IoControlCode;
|
|
irp->UserIosb = IoStatusBlock;
|
|
irp->UserEvent = Event;
|
|
|
|
return irp;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* IoCreateDriver (NTOSKRNL.EXE.@)
|
|
*/
|
|
NTSTATUS WINAPI IoCreateDriver( UNICODE_STRING *name, PDRIVER_INITIALIZE init )
|
|
{
|
|
DRIVER_OBJECT *driver;
|
|
DRIVER_EXTENSION *extension;
|
|
NTSTATUS status;
|
|
|
|
if (!(driver = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY,
|
|
sizeof(*driver) + sizeof(*extension) )))
|
|
return STATUS_NO_MEMORY;
|
|
|
|
if ((status = RtlDuplicateUnicodeString( 1, name, &driver->DriverName )))
|
|
{
|
|
RtlFreeHeap( GetProcessHeap(), 0, driver );
|
|
return status;
|
|
}
|
|
|
|
extension = (DRIVER_EXTENSION *)(driver + 1);
|
|
driver->Size = sizeof(*driver);
|
|
driver->DriverInit = init;
|
|
driver->DriverExtension = extension;
|
|
extension->DriverObject = driver;
|
|
extension->ServiceKeyName = driver->DriverName;
|
|
|
|
status = driver->DriverInit( driver, name );
|
|
|
|
if (status)
|
|
{
|
|
RtlFreeUnicodeString( &driver->DriverName );
|
|
RtlFreeHeap( GetProcessHeap(), 0, driver );
|
|
}
|
|
return status;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* IoDeleteDriver (NTOSKRNL.EXE.@)
|
|
*/
|
|
void WINAPI IoDeleteDriver( DRIVER_OBJECT *driver )
|
|
{
|
|
RtlFreeUnicodeString( &driver->DriverName );
|
|
RtlFreeHeap( GetProcessHeap(), 0, driver );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* IoCreateDevice (NTOSKRNL.EXE.@)
|
|
*/
|
|
NTSTATUS WINAPI IoCreateDevice( DRIVER_OBJECT *driver, ULONG ext_size,
|
|
UNICODE_STRING *name, DEVICE_TYPE type,
|
|
ULONG characteristics, BOOLEAN exclusive,
|
|
DEVICE_OBJECT **ret_device )
|
|
{
|
|
NTSTATUS status;
|
|
DEVICE_OBJECT *device;
|
|
HANDLE handle = 0;
|
|
HANDLE manager = get_device_manager();
|
|
|
|
TRACE( "(%p, %u, %s, %u, %x, %u, %p)\n",
|
|
driver, ext_size, debugstr_us(name), type, characteristics, exclusive, ret_device );
|
|
|
|
if (!(device = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*device) + ext_size )))
|
|
return STATUS_NO_MEMORY;
|
|
|
|
SERVER_START_REQ( create_device )
|
|
{
|
|
req->access = 0;
|
|
req->attributes = 0;
|
|
req->rootdir = 0;
|
|
req->manager = wine_server_obj_handle( manager );
|
|
req->user_ptr = wine_server_client_ptr( device );
|
|
if (name) wine_server_add_data( req, name->Buffer, name->Length );
|
|
if (!(status = wine_server_call( req ))) handle = wine_server_ptr_handle( reply->handle );
|
|
}
|
|
SERVER_END_REQ;
|
|
|
|
if (status == STATUS_SUCCESS)
|
|
{
|
|
device->DriverObject = driver;
|
|
device->DeviceExtension = device + 1;
|
|
device->DeviceType = type;
|
|
device->StackSize = 1;
|
|
device->Reserved = handle;
|
|
|
|
device->NextDevice = driver->DeviceObject;
|
|
driver->DeviceObject = device;
|
|
|
|
*ret_device = device;
|
|
}
|
|
else HeapFree( GetProcessHeap(), 0, device );
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* IoDeleteDevice (NTOSKRNL.EXE.@)
|
|
*/
|
|
void WINAPI IoDeleteDevice( DEVICE_OBJECT *device )
|
|
{
|
|
NTSTATUS status;
|
|
|
|
TRACE( "%p\n", device );
|
|
|
|
SERVER_START_REQ( delete_device )
|
|
{
|
|
req->handle = wine_server_obj_handle( device->Reserved );
|
|
status = wine_server_call( req );
|
|
}
|
|
SERVER_END_REQ;
|
|
|
|
if (status == STATUS_SUCCESS)
|
|
{
|
|
DEVICE_OBJECT **prev = &device->DriverObject->DeviceObject;
|
|
while (*prev && *prev != device) prev = &(*prev)->NextDevice;
|
|
if (*prev) *prev = (*prev)->NextDevice;
|
|
NtClose( device->Reserved );
|
|
HeapFree( GetProcessHeap(), 0, device );
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* IoCreateSymbolicLink (NTOSKRNL.EXE.@)
|
|
*/
|
|
NTSTATUS WINAPI IoCreateSymbolicLink( UNICODE_STRING *name, UNICODE_STRING *target )
|
|
{
|
|
HANDLE handle;
|
|
OBJECT_ATTRIBUTES attr;
|
|
|
|
attr.Length = sizeof(attr);
|
|
attr.RootDirectory = 0;
|
|
attr.ObjectName = name;
|
|
attr.Attributes = OBJ_CASE_INSENSITIVE | OBJ_OPENIF;
|
|
attr.SecurityDescriptor = NULL;
|
|
attr.SecurityQualityOfService = NULL;
|
|
|
|
TRACE( "%s -> %s\n", debugstr_us(name), debugstr_us(target) );
|
|
/* FIXME: store handle somewhere */
|
|
return NtCreateSymbolicLinkObject( &handle, SYMBOLIC_LINK_ALL_ACCESS, &attr, target );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* IoDeleteSymbolicLink (NTOSKRNL.EXE.@)
|
|
*/
|
|
NTSTATUS WINAPI IoDeleteSymbolicLink( UNICODE_STRING *name )
|
|
{
|
|
HANDLE handle;
|
|
OBJECT_ATTRIBUTES attr;
|
|
NTSTATUS status;
|
|
|
|
attr.Length = sizeof(attr);
|
|
attr.RootDirectory = 0;
|
|
attr.ObjectName = name;
|
|
attr.Attributes = OBJ_CASE_INSENSITIVE;
|
|
attr.SecurityDescriptor = NULL;
|
|
attr.SecurityQualityOfService = NULL;
|
|
|
|
if (!(status = NtOpenSymbolicLinkObject( &handle, 0, &attr )))
|
|
{
|
|
SERVER_START_REQ( unlink_object )
|
|
{
|
|
req->handle = wine_server_obj_handle( handle );
|
|
status = wine_server_call( req );
|
|
}
|
|
SERVER_END_REQ;
|
|
NtClose( handle );
|
|
}
|
|
return status;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* IoGetDeviceObjectPointer (NTOSKRNL.EXE.@)
|
|
*/
|
|
NTSTATUS WINAPI IoGetDeviceObjectPointer( UNICODE_STRING *name, ACCESS_MASK access, PFILE_OBJECT *file, PDEVICE_OBJECT *device )
|
|
{
|
|
FIXME( "stub: %s %x %p %p\n", debugstr_us(name), access, file, device );
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* IofCallDriver (NTOSKRNL.EXE.@)
|
|
*/
|
|
#ifdef DEFINE_FASTCALL2_ENTRYPOINT
|
|
DEFINE_FASTCALL2_ENTRYPOINT( IofCallDriver )
|
|
NTSTATUS WINAPI __regs_IofCallDriver( DEVICE_OBJECT *device, IRP *irp )
|
|
#else
|
|
NTSTATUS WINAPI IofCallDriver( DEVICE_OBJECT *device, IRP *irp )
|
|
#endif
|
|
{
|
|
PDRIVER_DISPATCH dispatch;
|
|
IO_STACK_LOCATION *irpsp;
|
|
NTSTATUS status;
|
|
|
|
TRACE( "%p %p\n", device, irp );
|
|
|
|
--irp->CurrentLocation;
|
|
irpsp = --irp->Tail.Overlay.s.u.CurrentStackLocation;
|
|
dispatch = device->DriverObject->MajorFunction[irpsp->MajorFunction];
|
|
status = dispatch( device, irp );
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* IoGetRelatedDeviceObject (NTOSKRNL.EXE.@)
|
|
*/
|
|
PDEVICE_OBJECT WINAPI IoGetRelatedDeviceObject( PFILE_OBJECT obj )
|
|
{
|
|
FIXME( "stub: %p\n", obj );
|
|
return NULL;
|
|
}
|
|
|
|
static CONFIGURATION_INFORMATION configuration_information;
|
|
|
|
/***********************************************************************
|
|
* IoGetConfigurationInformation (NTOSKRNL.EXE.@)
|
|
*/
|
|
PCONFIGURATION_INFORMATION WINAPI IoGetConfigurationInformation(void)
|
|
{
|
|
FIXME( "partial stub\n" );
|
|
/* FIXME: return actual devices on system */
|
|
return &configuration_information;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* IoRegisterDriverReinitialization (NTOSKRNL.EXE.@)
|
|
*/
|
|
void WINAPI IoRegisterDriverReinitialization( PDRIVER_OBJECT obj, PDRIVER_REINITIALIZE reinit, PVOID context )
|
|
{
|
|
FIXME( "stub: %p %p %p\n", obj, reinit, context );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* IoRegisterShutdownNotification (NTOSKRNL.EXE.@)
|
|
*/
|
|
NTSTATUS WINAPI IoRegisterShutdownNotification( PDEVICE_OBJECT obj )
|
|
{
|
|
FIXME( "stub: %p\n", obj );
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* IofCompleteRequest (NTOSKRNL.EXE.@)
|
|
*/
|
|
#ifdef DEFINE_FASTCALL2_ENTRYPOINT
|
|
DEFINE_FASTCALL2_ENTRYPOINT( IofCompleteRequest )
|
|
void WINAPI __regs_IofCompleteRequest( IRP *irp, UCHAR priority_boost )
|
|
#else
|
|
void WINAPI IofCompleteRequest( IRP *irp, UCHAR priority_boost )
|
|
#endif
|
|
{
|
|
IO_STACK_LOCATION *irpsp;
|
|
PIO_COMPLETION_ROUTINE routine;
|
|
IO_STATUS_BLOCK *iosb;
|
|
struct IrpInstance *instance;
|
|
NTSTATUS status, stat;
|
|
int call_flag = 0;
|
|
|
|
TRACE( "%p %u\n", irp, priority_boost );
|
|
|
|
iosb = irp->UserIosb;
|
|
status = irp->IoStatus.u.Status;
|
|
while (irp->CurrentLocation <= irp->StackCount)
|
|
{
|
|
irpsp = irp->Tail.Overlay.s.u.CurrentStackLocation;
|
|
routine = irpsp->CompletionRoutine;
|
|
call_flag = 0;
|
|
/* FIXME: add SL_INVOKE_ON_CANCEL support */
|
|
if (routine)
|
|
{
|
|
if ((irpsp->Control & SL_INVOKE_ON_SUCCESS) && STATUS_SUCCESS == status)
|
|
call_flag = 1;
|
|
if ((irpsp->Control & SL_INVOKE_ON_ERROR) && STATUS_SUCCESS != status)
|
|
call_flag = 1;
|
|
}
|
|
++irp->CurrentLocation;
|
|
++irp->Tail.Overlay.s.u.CurrentStackLocation;
|
|
if (call_flag)
|
|
{
|
|
TRACE( "calling %p( %p, %p, %p )\n", routine,
|
|
irpsp->DeviceObject, irp, irpsp->Context );
|
|
stat = routine( irpsp->DeviceObject, irp, irpsp->Context );
|
|
TRACE( "CompletionRoutine returned %x\n", stat );
|
|
if (STATUS_MORE_PROCESSING_REQUIRED == stat)
|
|
return;
|
|
}
|
|
}
|
|
if (iosb && STATUS_SUCCESS == status)
|
|
{
|
|
iosb->u.Status = irp->IoStatus.u.Status;
|
|
iosb->Information = irp->IoStatus.Information;
|
|
}
|
|
LIST_FOR_EACH_ENTRY( instance, &Irps, struct IrpInstance, entry )
|
|
{
|
|
if (instance->irp == irp)
|
|
{
|
|
list_remove( &instance->entry );
|
|
HeapFree( GetProcessHeap(), 0, instance );
|
|
IoFreeIrp( irp );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* InterlockedCompareExchange (NTOSKRNL.EXE.@)
|
|
*/
|
|
#ifdef DEFINE_FASTCALL2_ENTRYPOINT
|
|
DEFINE_FASTCALL2_ENTRYPOINT( NTOSKRNL_InterlockedCompareExchange )
|
|
LONG WINAPI __regs_NTOSKRNL_InterlockedCompareExchange( LONG volatile *dest, LONG xchg, LONG compare )
|
|
#else
|
|
LONG WINAPI NTOSKRNL_InterlockedCompareExchange( LONG volatile *dest, LONG xchg, LONG compare )
|
|
#endif
|
|
{
|
|
return InterlockedCompareExchange( dest, xchg, compare );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* InterlockedDecrement (NTOSKRNL.EXE.@)
|
|
*/
|
|
#ifdef DEFINE_FASTCALL1_ENTRYPOINT
|
|
DEFINE_FASTCALL1_ENTRYPOINT( NTOSKRNL_InterlockedDecrement )
|
|
LONG WINAPI __regs_NTOSKRNL_InterlockedDecrement( LONG volatile *dest )
|
|
#else
|
|
LONG WINAPI NTOSKRNL_InterlockedDecrement( LONG volatile *dest )
|
|
#endif
|
|
{
|
|
return InterlockedDecrement( dest );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* InterlockedExchange (NTOSKRNL.EXE.@)
|
|
*/
|
|
#ifdef DEFINE_FASTCALL2_ENTRYPOINT
|
|
DEFINE_FASTCALL2_ENTRYPOINT( NTOSKRNL_InterlockedExchange )
|
|
LONG WINAPI __regs_NTOSKRNL_InterlockedExchange( LONG volatile *dest, LONG val )
|
|
#else
|
|
LONG WINAPI NTOSKRNL_InterlockedExchange( LONG volatile *dest, LONG val )
|
|
#endif
|
|
{
|
|
return InterlockedExchange( dest, val );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* InterlockedExchangeAdd (NTOSKRNL.EXE.@)
|
|
*/
|
|
#ifdef DEFINE_FASTCALL2_ENTRYPOINT
|
|
DEFINE_FASTCALL2_ENTRYPOINT( NTOSKRNL_InterlockedExchangeAdd )
|
|
LONG WINAPI __regs_NTOSKRNL_InterlockedExchangeAdd( LONG volatile *dest, LONG incr )
|
|
#else
|
|
LONG WINAPI NTOSKRNL_InterlockedExchangeAdd( LONG volatile *dest, LONG incr )
|
|
#endif
|
|
{
|
|
return InterlockedExchangeAdd( dest, incr );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* InterlockedIncrement (NTOSKRNL.EXE.@)
|
|
*/
|
|
#ifdef DEFINE_FASTCALL1_ENTRYPOINT
|
|
DEFINE_FASTCALL1_ENTRYPOINT( NTOSKRNL_InterlockedIncrement )
|
|
LONG WINAPI __regs_NTOSKRNL_InterlockedIncrement( LONG volatile *dest )
|
|
#else
|
|
LONG WINAPI NTOSKRNL_InterlockedIncrement( LONG volatile *dest )
|
|
#endif
|
|
{
|
|
return InterlockedIncrement( dest );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* ExAllocatePool (NTOSKRNL.EXE.@)
|
|
*/
|
|
PVOID WINAPI ExAllocatePool( POOL_TYPE type, SIZE_T size )
|
|
{
|
|
return ExAllocatePoolWithTag( type, size, 0 );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* ExAllocatePoolWithQuota (NTOSKRNL.EXE.@)
|
|
*/
|
|
PVOID WINAPI ExAllocatePoolWithQuota( POOL_TYPE type, SIZE_T size )
|
|
{
|
|
return ExAllocatePoolWithTag( type, size, 0 );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* ExAllocatePoolWithTag (NTOSKRNL.EXE.@)
|
|
*/
|
|
PVOID WINAPI ExAllocatePoolWithTag( POOL_TYPE type, SIZE_T size, ULONG tag )
|
|
{
|
|
/* FIXME: handle page alignment constraints */
|
|
void *ret = HeapAlloc( GetProcessHeap(), 0, size );
|
|
TRACE( "%lu pool %u -> %p\n", size, type, ret );
|
|
return ret;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* ExAllocatePoolWithQuotaTag (NTOSKRNL.EXE.@)
|
|
*/
|
|
PVOID WINAPI ExAllocatePoolWithQuotaTag( POOL_TYPE type, SIZE_T size, ULONG tag )
|
|
{
|
|
return ExAllocatePoolWithTag( type, size, tag );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* ExFreePool (NTOSKRNL.EXE.@)
|
|
*/
|
|
void WINAPI ExFreePool( void *ptr )
|
|
{
|
|
ExFreePoolWithTag( ptr, 0 );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* ExFreePoolWithTag (NTOSKRNL.EXE.@)
|
|
*/
|
|
void WINAPI ExFreePoolWithTag( void *ptr, ULONG tag )
|
|
{
|
|
TRACE( "%p\n", ptr );
|
|
HeapFree( GetProcessHeap(), 0, ptr );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* KeInitializeEvent (NTOSKRNL.EXE.@)
|
|
*/
|
|
void WINAPI KeInitializeEvent( PRKEVENT Event, EVENT_TYPE Type, BOOLEAN State )
|
|
{
|
|
FIXME( "stub: %p %d %d\n", Event, Type, State );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* KeInitializeSpinLock (NTOSKRNL.EXE.@)
|
|
*/
|
|
void WINAPI KeInitializeSpinLock( PKSPIN_LOCK SpinLock )
|
|
{
|
|
FIXME( "stub: %p\n", SpinLock );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* KeInitializeTimerEx (NTOSKRNL.EXE.@)
|
|
*/
|
|
void WINAPI KeInitializeTimerEx( PKTIMER Timer, TIMER_TYPE Type )
|
|
{
|
|
FIXME( "stub: %p %d\n", Timer, Type );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* KeInitializeTimer (NTOSKRNL.EXE.@)
|
|
*/
|
|
void WINAPI KeInitializeTimer( PKTIMER Timer )
|
|
{
|
|
KeInitializeTimerEx(Timer, NotificationTimer);
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* KeQueryActiveProcessors (NTOSKRNL.EXE.@)
|
|
*
|
|
* Return the active Processors as bitmask
|
|
*
|
|
* RETURNS
|
|
* active Processors as bitmask
|
|
*
|
|
*/
|
|
KAFFINITY WINAPI KeQueryActiveProcessors( void )
|
|
{
|
|
DWORD_PTR AffinityMask;
|
|
|
|
GetProcessAffinityMask( GetCurrentProcess(), &AffinityMask, NULL);
|
|
return AffinityMask;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* KeQueryInterruptTime (NTOSKRNL.EXE.@)
|
|
*
|
|
* Return the interrupt time count
|
|
*
|
|
*/
|
|
ULONGLONG WINAPI KeQueryInterruptTime( void )
|
|
{
|
|
LARGE_INTEGER totaltime;
|
|
|
|
KeQueryTickCount(&totaltime);
|
|
return totaltime.QuadPart;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* KeQuerySystemTime (NTOSKRNL.EXE.@)
|
|
*/
|
|
void WINAPI KeQuerySystemTime( LARGE_INTEGER *time )
|
|
{
|
|
NtQuerySystemTime( time );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* KeQueryTickCount (NTOSKRNL.EXE.@)
|
|
*/
|
|
void WINAPI KeQueryTickCount( LARGE_INTEGER *count )
|
|
{
|
|
count->QuadPart = NtGetTickCount();
|
|
/* update the global variable too */
|
|
KeTickCount.LowPart = count->u.LowPart;
|
|
KeTickCount.High1Time = count->u.HighPart;
|
|
KeTickCount.High2Time = count->u.HighPart;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* KeQueryTimeIncrement (NTOSKRNL.EXE.@)
|
|
*/
|
|
ULONG WINAPI KeQueryTimeIncrement(void)
|
|
{
|
|
return 10000;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* MmAllocateNonCachedMemory (NTOSKRNL.EXE.@)
|
|
*/
|
|
PVOID WINAPI MmAllocateNonCachedMemory( SIZE_T size )
|
|
{
|
|
TRACE( "%lu\n", size );
|
|
return VirtualAlloc( NULL, size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE|PAGE_NOCACHE );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* MmFreeNonCachedMemory (NTOSKRNL.EXE.@)
|
|
*/
|
|
void WINAPI MmFreeNonCachedMemory( void *addr, SIZE_T size )
|
|
{
|
|
TRACE( "%p %lu\n", addr, size );
|
|
VirtualFree( addr, 0, MEM_RELEASE );
|
|
}
|
|
|
|
/***********************************************************************
|
|
* MmIsAddressValid (NTOSKRNL.EXE.@)
|
|
*
|
|
* Check if the process can access the virtual address without a pagefault
|
|
*
|
|
* PARAMS
|
|
* VirtualAddress [I] Address to check
|
|
*
|
|
* RETURNS
|
|
* Failure: FALSE
|
|
* Success: TRUE (Accessing the Address works without a Pagefault)
|
|
*
|
|
*/
|
|
BOOLEAN WINAPI MmIsAddressValid(PVOID VirtualAddress)
|
|
{
|
|
TRACE("(%p)\n", VirtualAddress);
|
|
return !IsBadWritePtr(VirtualAddress, 1);
|
|
}
|
|
|
|
/***********************************************************************
|
|
* MmPageEntireDriver (NTOSKRNL.EXE.@)
|
|
*/
|
|
PVOID WINAPI MmPageEntireDriver(PVOID AddrInSection)
|
|
{
|
|
TRACE("%p\n", AddrInSection);
|
|
return AddrInSection;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* MmResetDriverPaging (NTOSKRNL.EXE.@)
|
|
*/
|
|
void WINAPI MmResetDriverPaging(PVOID AddrInSection)
|
|
{
|
|
TRACE("%p\n", AddrInSection);
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* ObReferenceObjectByHandle (NTOSKRNL.EXE.@)
|
|
*/
|
|
NTSTATUS WINAPI ObReferenceObjectByHandle( HANDLE obj, ACCESS_MASK access,
|
|
POBJECT_TYPE type,
|
|
KPROCESSOR_MODE mode, PVOID* ptr,
|
|
POBJECT_HANDLE_INFORMATION info)
|
|
{
|
|
FIXME( "stub: %p %x %p %d %p %p\n", obj, access, type, mode, ptr, info);
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* ObfDereferenceObject (NTOSKRNL.EXE.@)
|
|
*/
|
|
#ifdef DEFINE_FASTCALL1_ENTRYPOINT
|
|
DEFINE_FASTCALL1_ENTRYPOINT( ObfDereferenceObject )
|
|
void WINAPI __regs_ObfDereferenceObject( VOID *obj )
|
|
#else
|
|
void WINAPI ObfDereferenceObject( VOID *obj )
|
|
#endif
|
|
{
|
|
FIXME( "stub: %p\n", obj );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* PsCreateSystemThread (NTOSKRNL.EXE.@)
|
|
*/
|
|
NTSTATUS WINAPI PsCreateSystemThread(PHANDLE ThreadHandle, ULONG DesiredAccess,
|
|
POBJECT_ATTRIBUTES ObjectAttributes,
|
|
HANDLE ProcessHandle, PCLIENT_ID ClientId,
|
|
PKSTART_ROUTINE StartRoutine, PVOID StartContext)
|
|
{
|
|
if (!ProcessHandle) ProcessHandle = GetCurrentProcess();
|
|
return RtlCreateUserThread(ProcessHandle, 0, FALSE, 0, 0,
|
|
0, StartRoutine, StartContext,
|
|
ThreadHandle, ClientId);
|
|
}
|
|
|
|
/***********************************************************************
|
|
* PsGetCurrentProcessId (NTOSKRNL.EXE.@)
|
|
*/
|
|
HANDLE WINAPI PsGetCurrentProcessId(void)
|
|
{
|
|
return UlongToHandle(GetCurrentProcessId()); /* FIXME: not quite right... */
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* PsGetCurrentThreadId (NTOSKRNL.EXE.@)
|
|
*/
|
|
HANDLE WINAPI PsGetCurrentThreadId(void)
|
|
{
|
|
return UlongToHandle(GetCurrentThreadId()); /* FIXME: not quite right... */
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* PsGetVersion (NTOSKRNL.EXE.@)
|
|
*/
|
|
BOOLEAN WINAPI PsGetVersion(ULONG *major, ULONG *minor, ULONG *build, UNICODE_STRING *version )
|
|
{
|
|
RTL_OSVERSIONINFOEXW info;
|
|
|
|
RtlGetVersion( &info );
|
|
if (major) *major = info.dwMajorVersion;
|
|
if (minor) *minor = info.dwMinorVersion;
|
|
if (build) *build = info.dwBuildNumber;
|
|
|
|
if (version)
|
|
{
|
|
#if 0 /* FIXME: GameGuard passes an uninitialized pointer in version->Buffer */
|
|
size_t len = min( strlenW(info.szCSDVersion)*sizeof(WCHAR), version->MaximumLength );
|
|
memcpy( version->Buffer, info.szCSDVersion, len );
|
|
if (len < version->MaximumLength) version->Buffer[len / sizeof(WCHAR)] = 0;
|
|
version->Length = len;
|
|
#endif
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* PsSetCreateProcessNotifyRoutine (NTOSKRNL.EXE.@)
|
|
*/
|
|
NTSTATUS WINAPI PsSetCreateProcessNotifyRoutine( PCREATE_PROCESS_NOTIFY_ROUTINE callback, BOOLEAN remove )
|
|
{
|
|
FIXME( "stub: %p %d\n", callback, remove );
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* PsSetCreateThreadNotifyRoutine (NTOSKRNL.EXE.@)
|
|
*/
|
|
NTSTATUS WINAPI PsSetCreateThreadNotifyRoutine( PCREATE_THREAD_NOTIFY_ROUTINE NotifyRoutine )
|
|
{
|
|
FIXME( "stub: %p\n", NotifyRoutine );
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* MmGetSystemRoutineAddress (NTOSKRNL.EXE.@)
|
|
*/
|
|
PVOID WINAPI MmGetSystemRoutineAddress(PUNICODE_STRING SystemRoutineName)
|
|
{
|
|
HMODULE hMod;
|
|
STRING routineNameA;
|
|
PVOID pFunc = NULL;
|
|
|
|
static const WCHAR ntoskrnlW[] = {'n','t','o','s','k','r','n','l','.','e','x','e',0};
|
|
static const WCHAR halW[] = {'h','a','l','.','d','l','l',0};
|
|
|
|
if (!SystemRoutineName) return NULL;
|
|
|
|
if (RtlUnicodeStringToAnsiString( &routineNameA, SystemRoutineName, TRUE ) == STATUS_SUCCESS)
|
|
{
|
|
/* We only support functions exported from ntoskrnl.exe or hal.dll */
|
|
hMod = GetModuleHandleW( ntoskrnlW );
|
|
pFunc = GetProcAddress( hMod, routineNameA.Buffer );
|
|
if (!pFunc)
|
|
{
|
|
hMod = GetModuleHandleW( halW );
|
|
if (hMod) pFunc = GetProcAddress( hMod, routineNameA.Buffer );
|
|
}
|
|
RtlFreeAnsiString( &routineNameA );
|
|
}
|
|
|
|
TRACE( "%s -> %p\n", debugstr_us(SystemRoutineName), pFunc );
|
|
return pFunc;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* MmQuerySystemSize (NTOSKRNL.EXE.@)
|
|
*/
|
|
MM_SYSTEMSIZE WINAPI MmQuerySystemSize(void)
|
|
{
|
|
FIXME("stub\n");
|
|
return MmLargeSystem;
|
|
}
|
|
|
|
|
|
/*****************************************************
|
|
* DllMain
|
|
*/
|
|
BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved )
|
|
{
|
|
static void *handler;
|
|
LARGE_INTEGER count;
|
|
|
|
switch(reason)
|
|
{
|
|
case DLL_PROCESS_ATTACH:
|
|
DisableThreadLibraryCalls( inst );
|
|
handler = RtlAddVectoredExceptionHandler( TRUE, vectored_handler );
|
|
KeQueryTickCount( &count ); /* initialize the global KeTickCount */
|
|
break;
|
|
case DLL_PROCESS_DETACH:
|
|
RtlRemoveVectoredExceptionHandler( handler );
|
|
break;
|
|
}
|
|
return TRUE;
|
|
}
|