From 14447b1088e07e8ce50e712b6271589d8fba88bf Mon Sep 17 00:00:00 2001 From: Damjan Jovanovic Date: Sat, 3 May 2014 20:18:26 +0200 Subject: ntoskrnl.exe: migrate driver loading to ntoskrnl.exe so it can be reused To: wine-patches@winehq.org MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="------------2.6.3" This is a multi-part message in MIME format. --------------2.6.3 Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit --- dlls/ntoskrnl.exe/Makefile.in | 1 + dlls/ntoskrnl.exe/ntoskrnl.c | 230 ++++++++++++++++++++++++++++++++++++ dlls/ntoskrnl.exe/ntoskrnl.exe.spec | 1 + programs/winedevice/device.c | 228 +---------------------------------- 4 files changed, 234 insertions(+), 226 deletions(-) --------------2.6.3 Content-Type: text/x-patch; name="0002-ntoskrnl.exe-migrate-driver-loading-to-ntoskrnl.exe-so.txt" Content-Transfer-Encoding: 8bit Content-Disposition: attachment; filename="0002-ntoskrnl.exe-migrate-driver-loading-to-ntoskrnl.exe-so.txt" diff --git a/dlls/ntoskrnl.exe/Makefile.in b/dlls/ntoskrnl.exe/Makefile.in index adb1327..799c264 100644 --- a/dlls/ntoskrnl.exe/Makefile.in +++ b/dlls/ntoskrnl.exe/Makefile.in @@ -1,5 +1,6 @@ MODULE = ntoskrnl.exe IMPORTLIB = ntoskrnl.exe +IMPORTS = advapi32 C_SRCS = \ instr.c \ diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c index 04f0198..eb981dd 100644 --- a/dlls/ntoskrnl.exe/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/ntoskrnl.c @@ -30,10 +30,12 @@ #include "ntstatus.h" #define WIN32_NO_STATUS #include "windef.h" +#include "winbase.h" #include "winternl.h" #include "excpt.h" #include "winioctl.h" #include "ddk/csq.h" +#include "winreg.h" #include "ddk/ntddk.h" #include "ddk/ntifs.h" #include "ddk/wdm.h" @@ -502,6 +504,234 @@ NTSTATUS CDECL wine_ntoskrnl_main_loop( HANDLE stop_event ) } +/* 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, LPCWSTR driver_name, DRIVER_OBJECT **p_driver_obj, + UNICODE_STRING *keyname ) +{ + unsigned int i; + DRIVER_OBJECT *driver_obj = NULL; + NTSTATUS status; + const IMAGE_NT_HEADERS *nt = RtlImageNtHeader( module ); + + if (!nt->OptionalHeader.AddressOfEntryPoint) return STATUS_SUCCESS; + + driver_obj = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(DRIVER_OBJECT) + sizeof(DRIVER_EXTENSION) ); + if (driver_obj == NULL) + return STATUS_NO_MEMORY; + + driver_obj->Size = sizeof(*driver_obj); + /* FIXME: DriverSection is wrong, see http://stackoverflow.com/questions/9017952/driver-object-driversection */ + driver_obj->DriverSection = find_ldr_module( module ); + driver_obj->DriverInit = (PDRIVER_INITIALIZE)((char *)module + nt->OptionalHeader.AddressOfEntryPoint); + driver_obj->DriverExtension = (DRIVER_EXTENSION *)(driver_obj + 1); + + driver_obj->DriverExtension->DriverObject = driver_obj; + driver_obj->DriverExtension->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] ); + + if (status == STATUS_SUCCESS) + *p_driver_obj = driver_obj; + else + RtlFreeHeap( GetProcessHeap(), 0, driver_obj ); + return status; +} + +/*********************************************************************** + * wine_ntoskrnl_load_driver (Not a Windows API) + */ +HMODULE CDECL wine_ntoskrnl_load_driver( LPCWSTR driver_name, DRIVER_OBJECT **driver_obj ) +{ + 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; + HKEY driver_hkey; + 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; + + if (init_driver( module, driver_name, driver_obj, &keypath ) != STATUS_SUCCESS) + { + FreeLibrary(module); + return NULL; + } + return module; +} + + /*********************************************************************** * IoAcquireCancelSpinLock (NTOSKRNL.EXE.@) */ diff --git a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec index db15265..93f5965 100644 --- a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec +++ b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec @@ -1490,3 +1490,4 @@ # or 'wine_' (for user-visible functions) to avoid namespace conflicts. @ cdecl wine_ntoskrnl_main_loop(long) +@ cdecl wine_ntoskrnl_load_driver(wstr ptr) diff --git a/programs/winedevice/device.c b/programs/winedevice/device.c index a1508a7..67844f5 100644 --- a/programs/winedevice/device.c +++ b/programs/winedevice/device.c @@ -39,143 +39,12 @@ WINE_DEFAULT_DEBUG_CHANNEL(winedevice); WINE_DECLARE_DEBUG_CHANNEL(relay); extern NTSTATUS CDECL wine_ntoskrnl_main_loop( HANDLE stop_event ); +extern HMODULE CDECL wine_ntoskrnl_load_driver( LPCWSTR driver_name, DRIVER_OBJECT **driver_obj ); static WCHAR *driver_name; static SERVICE_STATUS_HANDLE service_handle; static HANDLE stop_event; -/* 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, LPCWSTR driver_name, DRIVER_OBJECT **p_driver_obj, - UNICODE_STRING *keyname ) -{ - unsigned int i; - DRIVER_OBJECT *driver_obj = NULL; - NTSTATUS status; - const IMAGE_NT_HEADERS *nt = RtlImageNtHeader( module ); - - if (!nt->OptionalHeader.AddressOfEntryPoint) return STATUS_SUCCESS; - - driver_obj = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof(DRIVER_OBJECT) + sizeof(DRIVER_EXTENSION) ); - if (driver_obj == NULL) - return STATUS_NO_MEMORY; - - driver_obj->Size = sizeof(*driver_obj); - /* FIXME: DriverSection is wrong, see http://stackoverflow.com/questions/9017952/driver-object-driversection */ - driver_obj->DriverSection = find_ldr_module( module ); - driver_obj->DriverInit = (PDRIVER_INITIALIZE)((char *)module + nt->OptionalHeader.AddressOfEntryPoint); - driver_obj->DriverExtension = (DRIVER_EXTENSION *)(driver_obj + 1); - - driver_obj->DriverExtension->DriverObject = driver_obj; - driver_obj->DriverExtension->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] ); - - if (status == STATUS_SUCCESS) - *p_driver_obj = driver_obj; - else - RtlFreeHeap( GetProcessHeap(), 0, driver_obj ); - return status; -} - /* call the driver unload function */ static void unload_driver( HMODULE module, DRIVER_OBJECT *driver_obj ) { @@ -194,99 +63,6 @@ static void unload_driver( HMODULE module, DRIVER_OBJECT *driver_obj ) FreeLibrary( module ); } -/* load the .sys module for a device driver */ -static HMODULE load_driver( LPCWSTR driver_name, DRIVER_OBJECT **driver_obj ) -{ - 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; - HKEY driver_hkey; - 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; - - if (init_driver( module, driver_name, driver_obj, &keypath ) != STATUS_SUCCESS) - { - FreeLibrary(module); - return NULL; - } - return module; -} - static DWORD WINAPI service_handler( DWORD ctrl, DWORD event_type, LPVOID event_data, LPVOID context ) { SERVICE_STATUS status; @@ -339,7 +115,7 @@ static void WINAPI ServiceMain( DWORD argc, LPWSTR *argv ) status.dwWaitHint = 10000; SetServiceStatus( service_handle, &status ); - driver_module = load_driver( driver_name, &driver_obj ); + driver_module = wine_ntoskrnl_load_driver( driver_name, &driver_obj ); if (driver_module) { status.dwCurrentState = SERVICE_RUNNING; --------------2.6.3--