static DWORD service_start_process(struct service_entry *service_entry, HANDLE *process) { PROCESS_INFORMATION pi; STARTUPINFOW si; LPWSTR path = NULL; DWORD size; BOOL r; service_lock_exclusive(service_entry); if (service_entry->config.dwServiceType == SERVICE_KERNEL_DRIVER) { static const WCHAR winedeviceW[] = {'\\','w','i','n','e','d','e','v','i','c','e','.','e','x','e',' ',0}; DWORD len = GetSystemDirectoryW( NULL, 0 ) + sizeof(winedeviceW)/sizeof(WCHAR) + strlenW(service_entry->name); if (!(path = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return ERROR_NOT_ENOUGH_SERVER_MEMORY; GetSystemDirectoryW( path, len ); lstrcatW( path, winedeviceW ); lstrcatW( path, service_entry->name ); } else { size = ExpandEnvironmentStringsW(service_entry->config.lpBinaryPathName,NULL,0); path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR)); if (!path) return ERROR_NOT_ENOUGH_SERVER_MEMORY; ExpandEnvironmentStringsW(service_entry->config.lpBinaryPathName,path,size); } ZeroMemory(&si, sizeof(STARTUPINFOW)); si.cb = sizeof(STARTUPINFOW); if (!(service_entry->config.dwServiceType & SERVICE_INTERACTIVE_PROCESS)) { static WCHAR desktopW[] = {'_','_','w','i','n','e','s','e','r','v','i','c','e','_','w','i','n','s','t','a','t','i','o','n','\\','D','e','f','a','u','l','t',0}; si.lpDesktop = desktopW; } service_entry->status.dwCurrentState = SERVICE_START_PENDING; service_unlock(service_entry); r = CreateProcessW(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); HeapFree(GetProcessHeap(),0,path); if (!r) { service_lock_exclusive(service_entry); service_entry->status.dwCurrentState = SERVICE_STOPPED; service_unlock(service_entry); return GetLastError(); } service_entry->status.dwProcessId = pi.dwProcessId; *process = pi.hProcess; CloseHandle( pi.hThread ); return ERROR_SUCCESS; }
void release_service(struct service_entry *service) { if (InterlockedDecrement(&service->ref_count) == 0 && is_marked_for_delete(service)) { scmdatabase_lock_exclusive(service->db); service_lock_exclusive(service); scmdatabase_remove_service(service->db, service); service_unlock(service); scmdatabase_unlock(service->db); free_service_entry(service); } }
void service_terminate(struct service_entry *service) { service_lock_exclusive(service); TerminateProcess(service->process, 0); CloseHandle(service->process); service->process = NULL; CloseHandle(service->status_changed_event); service->status_changed_event = NULL; CloseHandle(service->control_mutex); service->control_mutex = NULL; CloseHandle(service->control_pipe); service->control_pipe = INVALID_HANDLE_VALUE; service->status.dwProcessId = 0; service->status.dwCurrentState = SERVICE_STOPPED; service_unlock(service); }
static DWORD service_start_process(struct service_entry *service_entry, HANDLE *process) { PROCESS_INFORMATION pi; STARTUPINFOW si; LPWSTR path = NULL; DWORD size; BOOL r; service_lock_exclusive(service_entry); if (!env) { HANDLE htok; if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY|TOKEN_DUPLICATE, &htok)) CreateEnvironmentBlock(&env, htok, FALSE); if (!env) WINE_ERR("failed to create services environment\n"); } size = ExpandEnvironmentStringsW(service_entry->config.lpBinaryPathName,NULL,0); path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR)); if (!path) { service_unlock(service_entry); return ERROR_NOT_ENOUGH_SERVER_MEMORY; } ExpandEnvironmentStringsW(service_entry->config.lpBinaryPathName,path,size); if (service_entry->config.dwServiceType == SERVICE_KERNEL_DRIVER) { static const WCHAR winedeviceW[] = {'\\','w','i','n','e','d','e','v','i','c','e','.','e','x','e',' ',0}; WCHAR system_dir[MAX_PATH]; DWORD type, len; GetSystemDirectoryW( system_dir, MAX_PATH ); if (is_win64) { if (!GetBinaryTypeW( path, &type )) { HeapFree( GetProcessHeap(), 0, path ); service_unlock(service_entry); return GetLastError(); } if (type == SCS_32BIT_BINARY) GetSystemWow64DirectoryW( system_dir, MAX_PATH ); } len = strlenW( system_dir ) + sizeof(winedeviceW)/sizeof(WCHAR) + strlenW(service_entry->name); HeapFree( GetProcessHeap(), 0, path ); if (!(path = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) { service_unlock(service_entry); return ERROR_NOT_ENOUGH_SERVER_MEMORY; } lstrcpyW( path, system_dir ); lstrcatW( path, winedeviceW ); lstrcatW( path, service_entry->name ); } ZeroMemory(&si, sizeof(STARTUPINFOW)); si.cb = sizeof(STARTUPINFOW); if (!(service_entry->config.dwServiceType & SERVICE_INTERACTIVE_PROCESS)) { static WCHAR desktopW[] = {'_','_','w','i','n','e','s','e','r','v','i','c','e','_','w','i','n','s','t','a','t','i','o','n','\\','D','e','f','a','u','l','t',0}; si.lpDesktop = desktopW; } service_entry->status.dwCurrentState = SERVICE_START_PENDING; service_unlock(service_entry); r = CreateProcessW(NULL, path, NULL, NULL, FALSE, CREATE_UNICODE_ENVIRONMENT, env, NULL, &si, &pi); HeapFree(GetProcessHeap(),0,path); if (!r) { service_lock_exclusive(service_entry); service_entry->status.dwCurrentState = SERVICE_STOPPED; service_unlock(service_entry); return GetLastError(); } service_entry->status.dwProcessId = pi.dwProcessId; service_entry->process = pi.hProcess; *process = pi.hProcess; CloseHandle( pi.hThread ); return ERROR_SUCCESS; }
DWORD service_start(struct service_entry *service, DWORD service_argc, LPCWSTR *service_argv) { DWORD err; LPWSTR name; HANDLE process_handle = NULL; err = scmdatabase_lock_startup(service->db); if (err != ERROR_SUCCESS) return err; if (service->control_pipe != INVALID_HANDLE_VALUE) { scmdatabase_unlock_startup(service->db); return ERROR_SERVICE_ALREADY_RUNNING; } service->control_mutex = CreateMutexW(NULL, TRUE, NULL); if (!service->status_changed_event) service->status_changed_event = CreateEventW(NULL, FALSE, FALSE, NULL); if (!service->overlapped_event) service->overlapped_event = CreateEventW(NULL, TRUE, FALSE, NULL); name = service_get_pipe_name(); service->control_pipe = CreateNamedPipeW(name, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE|PIPE_WAIT, 1, 256, 256, 10000, NULL ); HeapFree(GetProcessHeap(), 0, name); if (service->control_pipe==INVALID_HANDLE_VALUE) { WINE_ERR("failed to create pipe for %s, error = %d\n", wine_dbgstr_w(service->name), GetLastError()); err = GetLastError(); } else { err = service_start_process(service, &process_handle); if (err == ERROR_SUCCESS) { if (!service_send_start_message(service, process_handle, service_argv, service_argc)) err = ERROR_SERVICE_REQUEST_TIMEOUT; } if (err == ERROR_SUCCESS) err = service_wait_for_startup(service, process_handle); } if (err == ERROR_SUCCESS) ReleaseMutex(service->control_mutex); else { CloseHandle(service->overlapped_event); service->overlapped_event = NULL; CloseHandle(service->status_changed_event); service->status_changed_event = NULL; CloseHandle(service->control_mutex); service->control_mutex = NULL; if (service->control_pipe != INVALID_HANDLE_VALUE) CloseHandle(service->control_pipe); service->control_pipe = INVALID_HANDLE_VALUE; service->status.dwProcessId = 0; service_lock_exclusive(service); service->status.dwCurrentState = SERVICE_STOPPED; service_unlock(service); } scmdatabase_unlock_startup(service->db); WINE_TRACE("returning %d\n", err); return err; }