diff --git a/include/wine/svcctl.idl b/include/wine/svcctl.idl index 895ee2eeede..f261702a72e 100644 --- a/include/wine/svcctl.idl +++ b/include/wine/svcctl.idl @@ -114,6 +114,10 @@ typedef struct _SERVICE_FAILURE_ACTIONSW { [size_is(cActions)] SC_ACTION *lpsaActions; } SERVICE_FAILURE_ACTIONSW,*LPSERVICE_FAILURE_ACTIONSW; +typedef struct _SERVICE_PRESHUTDOWN_INFO { + DWORD dwPreshutdownTimeout; +} SERVICE_PRESHUTDOWN_INFO,*LPSERVICE_PRESHUTDOWN_INFO; + #define SERVICE_CONFIG_DESCRIPTION 1 #define SERVICE_CONFIG_FAILURE_ACTIONS 2 #define SERVICE_CONFIG_DELAYED_AUTO_START_INFO 3 @@ -134,6 +138,7 @@ typedef [switch_type(DWORD)] union { [case (SERVICE_CONFIG_DESCRIPTION)] SERVICE_DESCRIPTIONW descr; [case (SERVICE_CONFIG_FAILURE_ACTIONS)] SERVICE_FAILURE_ACTIONSW actions; + [case (SERVICE_CONFIG_PRESHUTDOWN_INFO)] SERVICE_PRESHUTDOWN_INFO preshutdown; } SERVICE_CONFIG2W; /* Compatible with Windows function 0x00 */ diff --git a/programs/services/rpc.c b/programs/services/rpc.c index 2d853c04800..66bd17b076a 100644 --- a/programs/services/rpc.c +++ b/programs/services/rpc.c @@ -737,6 +737,14 @@ DWORD __cdecl svcctl_ChangeServiceConfig2W( SC_RPC_HANDLE hService, DWORD level, wine_dbgstr_w(config->actions.lpRebootMsg), wine_dbgstr_w(config->actions.lpCommand) ); break; + case SERVICE_CONFIG_PRESHUTDOWN_INFO: + WINE_TRACE( "changing service %p preshutdown timeout to %d\n", + service, config->preshutdown.dwPreshutdownTimeout ); + service_lock_exclusive( service->service_entry ); + service->service_entry->preshutdown_timeout = config->preshutdown.dwPreshutdownTimeout; + save_service_config( service->service_entry ); + service_unlock( service->service_entry ); + break; default: WINE_FIXME("level %u not implemented\n", level); err = ERROR_INVALID_LEVEL; @@ -781,6 +789,18 @@ DWORD __cdecl svcctl_QueryServiceConfig2W( SC_RPC_HANDLE hService, DWORD level, } break; + case SERVICE_CONFIG_PRESHUTDOWN_INFO: + service_lock_shared(service->service_entry); + + *needed = sizeof(SERVICE_PRESHUTDOWN_INFO); + if (size >= *needed) + ((LPSERVICE_PRESHUTDOWN_INFO)buffer)->dwPreshutdownTimeout = + service->service_entry->preshutdown_timeout; + else err = ERROR_INSUFFICIENT_BUFFER; + + service_unlock(service->service_entry); + break; + default: WINE_FIXME("level %u not implemented\n", level); err = ERROR_INVALID_LEVEL; diff --git a/programs/services/services.c b/programs/services/services.c index 94b4747996d..ba6b6972d72 100644 --- a/programs/services/services.c +++ b/programs/services/services.c @@ -41,6 +41,7 @@ struct scmdatabase *active_database; DWORD service_pipe_timeout = 10000; DWORD service_kill_timeout = 20000; +static DWORD default_preshutdown_timeout = 180000; static void *env = NULL; static const int is_win64 = (sizeof(void *) > sizeof(int)); @@ -64,6 +65,7 @@ static const WCHAR SZ_DEPEND_ON_GROUP[] = {'D','e','p','e','n','d','O','n','G' static const WCHAR SZ_OBJECT_NAME[] = {'O','b','j','e','c','t','N','a','m','e',0}; static const WCHAR SZ_TAG[] = {'T','a','g',0}; static const WCHAR SZ_DESCRIPTION[] = {'D','e','s','c','r','i','p','t','i','o','n',0}; +static const WCHAR SZ_PRESHUTDOWN[] = {'P','r','e','s','h','u','t','d','o','w','n','T','i','m','e','o','u','t',0}; DWORD service_create(LPCWSTR name, struct service_entry **entry) @@ -80,6 +82,7 @@ DWORD service_create(LPCWSTR name, struct service_entry **entry) (*entry)->control_pipe = INVALID_HANDLE_VALUE; (*entry)->status.dwCurrentState = SERVICE_STOPPED; (*entry)->status.dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED; + (*entry)->preshutdown_timeout = default_preshutdown_timeout; /* all other fields are zero */ return ERROR_SUCCESS; } @@ -130,6 +133,8 @@ static DWORD load_service_config(HKEY hKey, struct service_entry *entry) return err; if ((err = load_reg_dword(hKey, SZ_TAG, &entry->config.dwTagId)) != 0) return err; + if ((err = load_reg_dword(hKey, SZ_PRESHUTDOWN, &entry->preshutdown_timeout)) != 0) + return err; WINE_TRACE("Image path = %s\n", wine_dbgstr_w(entry->config.lpBinaryPathName) ); WINE_TRACE("Group = %s\n", wine_dbgstr_w(entry->config.lpLoadOrderGroup) ); @@ -206,9 +211,10 @@ DWORD save_service_config(struct service_entry *entry) goto cleanup; if ((err = RegSetValueExW(hKey, SZ_ERROR, 0, REG_DWORD, (LPBYTE)&entry->config.dwErrorControl, sizeof(DWORD))) != 0) goto cleanup; - if ((err = RegSetValueExW(hKey, SZ_TYPE, 0, REG_DWORD, (LPBYTE)&entry->config.dwServiceType, sizeof(DWORD))) != 0) goto cleanup; + if ((err = RegSetValueExW(hKey, SZ_PRESHUTDOWN, 0, REG_DWORD, (LPBYTE)&entry->preshutdown_timeout, sizeof(DWORD))) != 0) + goto cleanup; if (entry->config.dwTagId) err = RegSetValueExW(hKey, SZ_TAG, 0, REG_DWORD, (LPBYTE)&entry->config.dwTagId, sizeof(DWORD)); diff --git a/programs/services/services.h b/programs/services/services.h index 448ddfaffbb..d5fcf77a3aa 100644 --- a/programs/services/services.h +++ b/programs/services/services.h @@ -39,6 +39,7 @@ struct service_entry LPWSTR name; SERVICE_STATUS_PROCESS status; QUERY_SERVICE_CONFIGW config; + DWORD preshutdown_timeout; LPWSTR description; LPWSTR dependOnServices; LPWSTR dependOnGroups;