From: Aric Stewart Subject: [PATCH v6] ntoskrnl.exe: Implement ZwLoadDriver and ZwUnloadDriver Message-Id: <56A63505.8080009@codeweavers.com> Date: Mon, 25 Jan 2016 08:45:25 -0600 Code is mostly moved from winedevice.exe winedevice.exe now uses these functions v3: No longer use advapi32 Registry functions v4: Fix FALSE return code (thanks to Huw Davies for spotting this one) Remove WINE_ from debuging macros v5: Locking and other suggestions from Sebastian Lackner Correct return code type check in winedevice (thanks Nikolay Sivov)` v6: Fix typo of STATUS_SUCESS Signed-off-by: Aric Stewart --- dlls/ntoskrnl.exe/ntoskrnl.c | 343 ++++++++++++++++++++++++++++++++++++ dlls/ntoskrnl.exe/ntoskrnl.exe.spec | 4 +- programs/winedevice/device.c | 243 +------------------------ 3 files changed, 350 insertions(+), 240 deletions(-) diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c index 04f0198..471b6e5 100644 --- a/dlls/ntoskrnl.exe/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/ntoskrnl.c @@ -72,6 +72,27 @@ static DWORD request_thread; static DWORD client_tid; static DWORD client_pid; +/* Loaded driver list */ +typedef struct _loaded_driver { + struct list entry; + + UNICODE_STRING name; + HMODULE module; + DRIVER_OBJECT driver_obj; + DRIVER_EXTENSION driver_extension; +} loaded_driver; + +struct list loaded_drivers = LIST_INIT(loaded_drivers); + +static RTL_CRITICAL_SECTION driver_loader_lock; +static RTL_CRITICAL_SECTION_DEBUG critsect_debug = +{ + 0, 0, &driver_loader_lock, + { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": driver_loader_lock") } +}; +static RTL_CRITICAL_SECTION driver_loader_lock = { &critsect_debug, -1, 0, 0, 0, 0 }; + #ifdef __i386__ #define DEFINE_FASTCALL1_ENTRYPOINT( name ) \ __ASM_STDCALL_FUNC( name, 4, \ @@ -2407,3 +2428,325 @@ NTSTATUS WINAPI CmUnRegisterCallback(LARGE_INTEGER cookie) FIXME("(%s): stub\n", wine_dbgstr_longlong(cookie.QuadPart)); return STATUS_NOT_IMPLEMENTED; } + + +/* find the LDR_MODULE corresponding to the driver module */ +static LDR_MODULE *find_ldr_module( HMODULE module ) +{ + LIST_ENTRY *entry, *list = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList; + + for (entry = list->Flink; entry != list; entry = entry->Flink) + { + LDR_MODULE *ldr = CONTAINING_RECORD(entry, LDR_MODULE, InMemoryOrderModuleList); + if (ldr->BaseAddress == module) return ldr; + if (ldr->BaseAddress > (void *)module) break; + } + return NULL; +} + +/* load the driver module file */ +static HMODULE load_driver_module( const WCHAR *name ) +{ + IMAGE_NT_HEADERS *nt; + const IMAGE_IMPORT_DESCRIPTOR *imports; + SYSTEM_BASIC_INFORMATION info; + int i; + INT_PTR delta; + ULONG size; + HMODULE module = LoadLibraryW( name ); + + if (!module) return NULL; + nt = RtlImageNtHeader( module ); + + if (!(delta = (char *)module - (char *)nt->OptionalHeader.ImageBase)) return module; + + /* the loader does not apply relocations to non page-aligned binaries or executables, + * we have to do it ourselves */ + + NtQuerySystemInformation( SystemBasicInformation, &info, sizeof(info), NULL ); + if (nt->OptionalHeader.SectionAlignment < info.PageSize || + !(nt->FileHeader.Characteristics & IMAGE_FILE_DLL)) + { + DWORD old; + IMAGE_BASE_RELOCATION *rel, *end; + + if ((rel = RtlImageDirectoryEntryToData( module, TRUE, IMAGE_DIRECTORY_ENTRY_BASERELOC, &size ))) + { + TRACE( "%s: relocating from %p to %p\n", + wine_dbgstr_w(name), (char *)module - delta, module ); + end = (IMAGE_BASE_RELOCATION *)((char *)rel + size); + while (rel < end && rel->SizeOfBlock) + { + void *page = (char *)module + rel->VirtualAddress; + VirtualProtect( page, info.PageSize, PAGE_EXECUTE_READWRITE, &old ); + rel = LdrProcessRelocationBlock( page, (rel->SizeOfBlock - sizeof(*rel)) / sizeof(USHORT), + (USHORT *)(rel + 1), delta ); + if (old != PAGE_EXECUTE_READWRITE) VirtualProtect( page, info.PageSize, old, &old ); + if (!rel) goto error; + } + /* make sure we don't try again */ + size = FIELD_OFFSET( IMAGE_NT_HEADERS, OptionalHeader ) + nt->FileHeader.SizeOfOptionalHeader; + VirtualProtect( nt, size, PAGE_READWRITE, &old ); + nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = 0; + VirtualProtect( nt, size, old, &old ); + } + } + + /* make sure imports are relocated too */ + + if ((imports = RtlImageDirectoryEntryToData( module, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &size ))) + { + for (i = 0; imports[i].Name && imports[i].FirstThunk; i++) + { + char *name = (char *)module + imports[i].Name; + WCHAR buffer[32], *p = buffer; + + while (p < buffer + 32) if (!(*p++ = *name++)) break; + if (p <= buffer + 32) FreeLibrary( load_driver_module( buffer ) ); + } + } + + return module; + +error: + FreeLibrary( module ); + return NULL; +} + +/* call the driver init entry point */ +static NTSTATUS init_driver( const WCHAR *driver_name, UNICODE_STRING *keyname, loaded_driver *driver ) +{ + unsigned int i; + NTSTATUS status; + const IMAGE_NT_HEADERS *nt = RtlImageNtHeader( driver->module ); + + if (!nt->OptionalHeader.AddressOfEntryPoint) return STATUS_SUCCESS; + + driver->driver_obj.Size = sizeof(driver->driver_obj); + driver->driver_obj.DriverSection = find_ldr_module( driver->module ); + driver->driver_obj.DriverInit = (PDRIVER_INITIALIZE)((char *)driver->module + nt->OptionalHeader.AddressOfEntryPoint); + driver->driver_obj.DriverExtension = &driver->driver_extension; + + driver->driver_obj.DriverExtension->DriverObject = &driver->driver_obj; + driver->driver_obj.DriverExtension->ServiceKeyName = *keyname; + + if (TRACE_ON(relay)) + DPRINTF( "%04x:Call driver init %p (obj=%p,str=%s)\n", GetCurrentThreadId(), + driver->driver_obj.DriverInit, &driver->driver_obj, wine_dbgstr_w(keyname->Buffer) ); + + status = driver->driver_obj.DriverInit( &driver->driver_obj, keyname ); + + if (TRACE_ON(relay)) + DPRINTF( "%04x:Ret driver init %p (obj=%p,str=%s) retval=%08x\n", GetCurrentThreadId(), + driver->driver_obj.DriverInit, &driver->driver_obj, wine_dbgstr_w(keyname->Buffer), status ); + + TRACE( "init done for %s obj %p\n", wine_dbgstr_w(driver_name), &driver->driver_obj ); + TRACE( "- DriverInit = %p\n", driver->driver_obj.DriverInit ); + TRACE( "- DriverStartIo = %p\n", driver->driver_obj.DriverStartIo ); + TRACE( "- DriverUnload = %p\n", driver->driver_obj.DriverUnload ); + for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) + TRACE( "- MajorFunction[%d] = %p\n", i, driver->driver_obj.MajorFunction[i] ); + + return status; +} + +/*********************************************************************** + * ZwLoadDriver (NTOSKRNL.EXE.@) + */ +NTSTATUS WINAPI ZwLoadDriver(const UNICODE_STRING *DriverServiceName) +{ + static const WCHAR driversW[] = {'\\','d','r','i','v','e','r','s','\\',0}; + static const WCHAR systemrootW[] = {'\\','S','y','s','t','e','m','R','o','o','t','\\',0}; + static const WCHAR postfixW[] = {'.','s','y','s',0}; + static const WCHAR ntprefixW[] = {'\\','?','?','\\',0}; + static const WCHAR ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0}; + static const WCHAR servicesW[] = {'\\','R','e','g','i','s','t','r','y', + '\\','M','a','c','h','i','n','e', + '\\','S','y','s','t','e','m', + '\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t', + '\\','S','e','r','v','i','c','e','s','\\',0}; + + UNICODE_STRING keypath, reg_str; + HMODULE module; + LPWSTR path = NULL, keypath_buffer = NULL, image_path = NULL; + LPWSTR driver_name = NULL; + DWORD size; + HANDLE driver_hkey; + OBJECT_ATTRIBUTES attr; + NTSTATUS status; + char buffer[256]; + static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data ); + loaded_driver *driver; + + RtlEnterCriticalSection(&driver_loader_lock); + + /* Check if driver is already loaded */ + LIST_FOR_EACH_ENTRY(driver, &loaded_drivers, loaded_driver, entry) + { + if (RtlEqualUnicodeString(DriverServiceName, &driver->name, FALSE)) + { + RtlLeaveCriticalSection(&driver_loader_lock); + return ERROR_SUCCESS; + } + } + + /* Ensure NULL termination of incoming driver name */ + driver_name = HeapAlloc(GetProcessHeap(), 0, DriverServiceName->Length + + sizeof(WCHAR)); + lstrcpynW(driver_name, DriverServiceName->Buffer, DriverServiceName->Length/sizeof(WCHAR) + 1); + driver_name[DriverServiceName->Length/sizeof(WCHAR) + 1] = 0; + + keypath_buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(servicesW) + + DriverServiceName->Length + sizeof(WCHAR)); + lstrcpyW(keypath_buffer, servicesW); + lstrcatW(keypath_buffer, driver_name); + + attr.Length = sizeof(attr); + attr.RootDirectory = 0; + attr.ObjectName = &keypath; + attr.Attributes = 0; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + + RtlInitUnicodeString(&keypath, keypath_buffer); + + status = NtCreateKey(&driver_hkey, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL); + if (status != STATUS_SUCCESS) + { + ERR("cannot open key %s, err=0x%x\n", wine_dbgstr_w(keypath_buffer), status); + HeapFree(GetProcessHeap(), 0, keypath_buffer); + HeapFree(GetProcessHeap(), 0, driver_name); + RtlLeaveCriticalSection(&driver_loader_lock); + return status; + } + + /* read the executable path from memory */ + size = 0; + RtlInitUnicodeString(®_str, ImagePathW); + + status = NtQueryValueKey(driver_hkey, ®_str, KeyValuePartialInformation, buffer, info_size, &size); + if (status == STATUS_BUFFER_OVERFLOW) + { + KEY_VALUE_PARTIAL_INFORMATION *info; + + image_path = HeapAlloc(GetProcessHeap(), 0, size); + info = (KEY_VALUE_PARTIAL_INFORMATION *) image_path; + status = NtQueryValueKey(driver_hkey, ®_str, KeyValuePartialInformation, image_path, size, &size); + + if (status == STATUS_SUCCESS) + { + size = ExpandEnvironmentStringsW((LPCWSTR)info->Data,NULL,0); + path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR)); + ExpandEnvironmentStringsW((LPCWSTR)info->Data,path,size); + HeapFree(GetProcessHeap(), 0, image_path); + } + else + { + TRACE("Failed to load driver path(0x%x): %s\n", status, + wine_dbgstr_w((LPCWSTR)info->Data)); + NtClose(driver_hkey); + HeapFree(GetProcessHeap(), 0, image_path); + HeapFree(GetProcessHeap(), 0, keypath_buffer); + HeapFree(GetProcessHeap(), 0, driver_name); + RtlLeaveCriticalSection(&driver_loader_lock); + return status; + } + + if (!strncmpiW(path, systemrootW, 12)) + { + WCHAR buffer[MAX_PATH]; + + GetWindowsDirectoryW(buffer, MAX_PATH); + + image_path = HeapAlloc(GetProcessHeap(), 0, + (size - 11 + strlenW(buffer)) * sizeof(WCHAR)); + lstrcpyW(image_path, buffer); + lstrcatW(image_path, path + 11); + HeapFree(GetProcessHeap(), 0, path); + path = image_path; + } + else if (!strncmpW(path, ntprefixW, 4)) + image_path = path + 4; + else + image_path = path; + } + else + { + /* default is to use the driver name + ".sys" */ + WCHAR buffer[MAX_PATH]; + GetSystemDirectoryW(buffer, MAX_PATH); + path = HeapAlloc(GetProcessHeap(),0, + (strlenW(buffer) + strlenW(driversW) + strlenW(postfixW) + 1) + *sizeof(WCHAR) + DriverServiceName->Length); + lstrcpyW(path, buffer); + lstrcatW(path, driversW); + lstrcatW(path, driver_name); + lstrcatW(path, postfixW); + image_path = path; + } + NtClose(driver_hkey); + + TRACE("loading driver %s\n", wine_dbgstr_w(image_path)); + + module = load_driver_module(image_path); + HeapFree(GetProcessHeap(), 0, path); + + if (!module) + { + HeapFree(GetProcessHeap(), 0, keypath_buffer); + HeapFree(GetProcessHeap(), 0, driver_name); + RtlLeaveCriticalSection(&driver_loader_lock); + return STATUS_NOT_FOUND; + } + + driver = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*driver)); + driver->module = module; + RtlInitUnicodeString(&driver->name, driver_name); + + init_driver(driver_name, &keypath, driver); + + list_add_tail(&loaded_drivers, &driver->entry); + + RtlLeaveCriticalSection(&driver_loader_lock); + return STATUS_SUCCESS; +} + +/*********************************************************************** + * ZwUnloadDriver (NTOSKRNL.EXE.@) + */ +NTSTATUS WINAPI ZwUnloadDriver(const UNICODE_STRING *DriverServiceName) +{ + loaded_driver *driver, *ptr; + + RtlEnterCriticalSection(&driver_loader_lock); + LIST_FOR_EACH_ENTRY_SAFE(driver, ptr, &loaded_drivers, loaded_driver, entry) + { + if (RtlEqualUnicodeString(DriverServiceName, &driver->name, FALSE)) + { + list_remove(&driver->entry); + + if (driver->driver_obj.DriverUnload) + { + if (TRACE_ON(relay)) + DPRINTF("%04x:Call driver unload %p (obj=%p)\n", GetCurrentThreadId(), + driver->driver_obj.DriverUnload, &driver->driver_obj ); + + driver->driver_obj.DriverUnload( &driver->driver_obj); + + if (TRACE_ON(relay)) + DPRINTF("%04x:Ret driver unload %p (obj=%p)\n", GetCurrentThreadId(), + driver->driver_obj.DriverUnload, &driver->driver_obj); + } + + RtlFreeUnicodeString(&driver->name); + RtlFreeUnicodeString(&driver->driver_extension.ServiceKeyName); + FreeLibrary(driver->module); + HeapFree(GetProcessHeap(), 0, driver); + RtlLeaveCriticalSection(&driver_loader_lock); + return STATUS_SUCCESS; + } + } + + RtlLeaveCriticalSection(&driver_loader_lock); + return STATUS_NOT_FOUND; +} diff --git a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec index 1319ada..a98a523 100644 --- a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec +++ b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec @@ -1314,7 +1314,7 @@ @ stdcall ZwFsControlFile(long long long long long long long long long long) ntdll.ZwFsControlFile @ stdcall ZwInitiatePowerAction(long long long long) ntdll.ZwInitiatePowerAction @ stdcall ZwIsProcessInJob(long long) ntdll.ZwIsProcessInJob -@ stdcall ZwLoadDriver(ptr) ntdll.ZwLoadDriver +@ stdcall ZwLoadDriver(ptr) @ stdcall ZwLoadKey(ptr ptr) ntdll.ZwLoadKey @ stdcall ZwMakeTemporaryObject(long) ntdll.ZwMakeTemporaryObject @ stdcall ZwMapViewOfSection(long long ptr long long ptr ptr long long long) ntdll.ZwMapViewOfSection @@ -1384,7 +1384,7 @@ @ stdcall ZwTerminateJobObject(long long) ntdll.ZwTerminateJobObject @ stdcall ZwTerminateProcess(long long) ntdll.ZwTerminateProcess @ stub ZwTranslateFilePath -@ stdcall ZwUnloadDriver(ptr) ntdll.ZwUnloadDriver +@ stdcall ZwUnloadDriver(ptr) @ stdcall ZwUnloadKey(long) ntdll.ZwUnloadKey @ stdcall ZwUnmapViewOfSection(long ptr) ntdll.ZwUnmapViewOfSection @ stdcall ZwWaitForMultipleObjects(long ptr long long ptr) ntdll.ZwWaitForMultipleObjects diff --git a/programs/winedevice/device.c b/programs/winedevice/device.c index ef1e1ef..77648f2 100644 --- a/programs/winedevice/device.c +++ b/programs/winedevice/device.c @@ -25,253 +25,19 @@ #include "ntstatus.h" #define WIN32_NO_STATUS -#include "windef.h" -#include "winbase.h" #include "winternl.h" -#include "winreg.h" -#include "winnls.h" #include "winsvc.h" #include "ddk/wdm.h" #include "wine/unicode.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(winedevice); -WINE_DECLARE_DEBUG_CHANNEL(relay); extern NTSTATUS CDECL wine_ntoskrnl_main_loop( HANDLE stop_event ); static WCHAR *driver_name; static SERVICE_STATUS_HANDLE service_handle; -static HKEY driver_hkey; static HANDLE stop_event; -static DRIVER_OBJECT driver_obj; -static DRIVER_EXTENSION driver_extension; - -/* find the LDR_MODULE corresponding to the driver module */ -static LDR_MODULE *find_ldr_module( HMODULE module ) -{ - LIST_ENTRY *entry, *list = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList; - - for (entry = list->Flink; entry != list; entry = entry->Flink) - { - LDR_MODULE *ldr = CONTAINING_RECORD(entry, LDR_MODULE, InMemoryOrderModuleList); - if (ldr->BaseAddress == module) return ldr; - if (ldr->BaseAddress > (void *)module) break; - } - return NULL; -} - -/* load the driver module file */ -static HMODULE load_driver_module( const WCHAR *name ) -{ - IMAGE_NT_HEADERS *nt; - const IMAGE_IMPORT_DESCRIPTOR *imports; - SYSTEM_BASIC_INFORMATION info; - int i; - INT_PTR delta; - ULONG size; - HMODULE module = LoadLibraryW( name ); - - if (!module) return NULL; - nt = RtlImageNtHeader( module ); - - if (!(delta = (char *)module - (char *)nt->OptionalHeader.ImageBase)) return module; - - /* the loader does not apply relocations to non page-aligned binaries or executables, - * we have to do it ourselves */ - - NtQuerySystemInformation( SystemBasicInformation, &info, sizeof(info), NULL ); - if (nt->OptionalHeader.SectionAlignment < info.PageSize || - !(nt->FileHeader.Characteristics & IMAGE_FILE_DLL)) - { - DWORD old; - IMAGE_BASE_RELOCATION *rel, *end; - - if ((rel = RtlImageDirectoryEntryToData( module, TRUE, IMAGE_DIRECTORY_ENTRY_BASERELOC, &size ))) - { - WINE_TRACE( "%s: relocating from %p to %p\n", - wine_dbgstr_w(name), (char *)module - delta, module ); - end = (IMAGE_BASE_RELOCATION *)((char *)rel + size); - while (rel < end && rel->SizeOfBlock) - { - void *page = (char *)module + rel->VirtualAddress; - VirtualProtect( page, info.PageSize, PAGE_EXECUTE_READWRITE, &old ); - rel = LdrProcessRelocationBlock( page, (rel->SizeOfBlock - sizeof(*rel)) / sizeof(USHORT), - (USHORT *)(rel + 1), delta ); - if (old != PAGE_EXECUTE_READWRITE) VirtualProtect( page, info.PageSize, old, &old ); - if (!rel) goto error; - } - /* make sure we don't try again */ - size = FIELD_OFFSET( IMAGE_NT_HEADERS, OptionalHeader ) + nt->FileHeader.SizeOfOptionalHeader; - VirtualProtect( nt, size, PAGE_READWRITE, &old ); - nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = 0; - VirtualProtect( nt, size, old, &old ); - } - } - - /* make sure imports are relocated too */ - - if ((imports = RtlImageDirectoryEntryToData( module, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &size ))) - { - for (i = 0; imports[i].Name && imports[i].FirstThunk; i++) - { - char *name = (char *)module + imports[i].Name; - WCHAR buffer[32], *p = buffer; - - while (p < buffer + 32) if (!(*p++ = *name++)) break; - if (p <= buffer + 32) FreeLibrary( load_driver_module( buffer ) ); - } - } - - return module; - -error: - FreeLibrary( module ); - return NULL; -} - -/* call the driver init entry point */ -static NTSTATUS init_driver( HMODULE module, UNICODE_STRING *keyname ) -{ - unsigned int i; - NTSTATUS status; - const IMAGE_NT_HEADERS *nt = RtlImageNtHeader( module ); - - if (!nt->OptionalHeader.AddressOfEntryPoint) return STATUS_SUCCESS; - - driver_obj.Size = sizeof(driver_obj); - driver_obj.DriverSection = find_ldr_module( module ); - driver_obj.DriverInit = (PDRIVER_INITIALIZE)((char *)module + nt->OptionalHeader.AddressOfEntryPoint); - driver_obj.DriverExtension = &driver_extension; - - driver_extension.DriverObject = &driver_obj; - driver_extension.ServiceKeyName = *keyname; - - if (WINE_TRACE_ON(relay)) - WINE_DPRINTF( "%04x:Call driver init %p (obj=%p,str=%s)\n", GetCurrentThreadId(), - driver_obj.DriverInit, &driver_obj, wine_dbgstr_w(keyname->Buffer) ); - - status = driver_obj.DriverInit( &driver_obj, keyname ); - - if (WINE_TRACE_ON(relay)) - WINE_DPRINTF( "%04x:Ret driver init %p (obj=%p,str=%s) retval=%08x\n", GetCurrentThreadId(), - driver_obj.DriverInit, &driver_obj, wine_dbgstr_w(keyname->Buffer), status ); - - WINE_TRACE( "init done for %s obj %p\n", wine_dbgstr_w(driver_name), &driver_obj ); - WINE_TRACE( "- DriverInit = %p\n", driver_obj.DriverInit ); - WINE_TRACE( "- DriverStartIo = %p\n", driver_obj.DriverStartIo ); - WINE_TRACE( "- DriverUnload = %p\n", driver_obj.DriverUnload ); - for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) - WINE_TRACE( "- MajorFunction[%d] = %p\n", i, driver_obj.MajorFunction[i] ); - - return status; -} - -/* call the driver unload function */ -static void unload_driver( HMODULE module, DRIVER_OBJECT *driver_obj ) -{ - if (driver_obj->DriverUnload) - { - if (WINE_TRACE_ON(relay)) - WINE_DPRINTF( "%04x:Call driver unload %p (obj=%p)\n", GetCurrentThreadId(), - driver_obj->DriverUnload, driver_obj ); - - driver_obj->DriverUnload( driver_obj ); - - if (WINE_TRACE_ON(relay)) - WINE_DPRINTF( "%04x:Ret driver unload %p (obj=%p)\n", GetCurrentThreadId(), - driver_obj->DriverUnload, driver_obj ); - } - FreeLibrary( module ); -} - -/* load the .sys module for a device driver */ -static HMODULE load_driver(void) -{ - static const WCHAR driversW[] = {'\\','d','r','i','v','e','r','s','\\',0}; - static const WCHAR systemrootW[] = {'\\','S','y','s','t','e','m','R','o','o','t','\\',0}; - static const WCHAR postfixW[] = {'.','s','y','s',0}; - static const WCHAR ntprefixW[] = {'\\','?','?','\\',0}; - static const WCHAR ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0}; - static const WCHAR servicesW[] = {'\\','R','e','g','i','s','t','r','y', - '\\','M','a','c','h','i','n','e', - '\\','S','y','s','t','e','m', - '\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t', - '\\','S','e','r','v','i','c','e','s','\\',0}; - - UNICODE_STRING keypath; - HMODULE module; - LPWSTR path = NULL, str; - DWORD type, size; - - str = HeapAlloc( GetProcessHeap(), 0, sizeof(servicesW) + strlenW(driver_name)*sizeof(WCHAR) ); - lstrcpyW( str, servicesW ); - lstrcatW( str, driver_name ); - - if (RegOpenKeyW( HKEY_LOCAL_MACHINE, str + 18 /* skip \registry\machine */, &driver_hkey )) - { - WINE_ERR( "cannot open key %s, err=%u\n", wine_dbgstr_w(str), GetLastError() ); - HeapFree( GetProcessHeap(), 0, str); - return FALSE; - } - RtlInitUnicodeString( &keypath, str ); - - /* read the executable path from memory */ - size = 0; - if (!RegQueryValueExW( driver_hkey, ImagePathW, NULL, &type, NULL, &size )) - { - str = HeapAlloc( GetProcessHeap(), 0, size ); - if (!RegQueryValueExW( driver_hkey, ImagePathW, NULL, &type, (LPBYTE)str, &size )) - { - size = ExpandEnvironmentStringsW(str,NULL,0); - path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR)); - ExpandEnvironmentStringsW(str,path,size); - } - HeapFree( GetProcessHeap(), 0, str ); - if (!path) return FALSE; - - if (!strncmpiW( path, systemrootW, 12 )) - { - WCHAR buffer[MAX_PATH]; - - GetWindowsDirectoryW(buffer, MAX_PATH); - - str = HeapAlloc(GetProcessHeap(), 0, (size -11 + strlenW(buffer)) - * sizeof(WCHAR)); - lstrcpyW(str, buffer); - lstrcatW(str, path + 11); - HeapFree( GetProcessHeap(), 0, path ); - path = str; - } - else if (!strncmpW( path, ntprefixW, 4 )) - str = path + 4; - else - str = path; - } - else - { - /* default is to use the driver name + ".sys" */ - WCHAR buffer[MAX_PATH]; - GetSystemDirectoryW(buffer, MAX_PATH); - path = HeapAlloc(GetProcessHeap(),0, - (strlenW(buffer) + strlenW(driversW) + strlenW(driver_name) + strlenW(postfixW) + 1) - *sizeof(WCHAR)); - lstrcpyW(path, buffer); - lstrcatW(path, driversW); - lstrcatW(path, driver_name); - lstrcatW(path, postfixW); - str = path; - } - - WINE_TRACE( "loading driver %s\n", wine_dbgstr_w(str) ); - - module = load_driver_module( str ); - HeapFree( GetProcessHeap(), 0, path ); - if (!module) return NULL; - - init_driver( module, &keypath ); - return module; -} static DWORD WINAPI service_handler( DWORD ctrl, DWORD event_type, LPVOID event_data, LPVOID context ) { @@ -305,7 +71,7 @@ static DWORD WINAPI service_handler( DWORD ctrl, DWORD event_type, LPVOID event_ static void WINAPI ServiceMain( DWORD argc, LPWSTR *argv ) { SERVICE_STATUS status; - HMODULE driver_module; + UNICODE_STRING DriverName; WINE_TRACE( "starting service %s\n", wine_dbgstr_w(driver_name) ); @@ -324,15 +90,16 @@ static void WINAPI ServiceMain( DWORD argc, LPWSTR *argv ) status.dwWaitHint = 10000; SetServiceStatus( service_handle, &status ); - driver_module = load_driver(); - if (driver_module) + RtlInitUnicodeString( &DriverName, driver_name ); + + if ( ZwLoadDriver( &DriverName ) == STATUS_SUCCESS ) { status.dwCurrentState = SERVICE_RUNNING; status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; SetServiceStatus( service_handle, &status ); wine_ntoskrnl_main_loop( stop_event ); - unload_driver( driver_module, &driver_obj ); + ZwUnloadDriver( &DriverName ); } else WINE_ERR( "driver %s failed to load\n", wine_dbgstr_w(driver_name) );