/* * ServiceMain function for qmgr running within svchost * * Copyright 2007 (C) Google (Roy Shea) * * 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 "windef.h" #include "winsvc.h" #include "qmgr.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(qmgr); HANDLE stop_event = NULL; static SERVICE_STATUS_HANDLE status_handle; static SERVICE_STATUS status; static VOID UpdateStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint) { status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; status.dwCurrentState = dwCurrentState; if (dwCurrentState == SERVICE_START_PENDING) status.dwControlsAccepted = 0; else status.dwControlsAccepted = (SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE | SERVICE_ACCEPT_SHUTDOWN); status.dwWin32ExitCode = 0; status.dwServiceSpecificExitCode = 0; status.dwCheckPoint = 0; status.dwWaitHint = dwWaitHint; if (!SetServiceStatus(status_handle, &status)) { ERR("failed to set service status\n"); SetEvent(stop_event); } } /* Handle incoming ControlService signals */ static DWORD WINAPI ServiceHandler(DWORD ctrl, DWORD event_type, LPVOID event_data, LPVOID context) { switch (ctrl) { case SERVICE_CONTROL_STOP: case SERVICE_CONTROL_SHUTDOWN: TRACE("shutting down service\n"); UpdateStatus(SERVICE_STOP_PENDING, NO_ERROR, 0); SetEvent(stop_event); break; default: FIXME("ignoring handle service ctrl %x\n", ctrl); UpdateStatus(status.dwCurrentState, NO_ERROR, 0); break; } return NO_ERROR; } /* Main thread of the service */ static BOOL StartCount(void) { HRESULT hr; DWORD dwReg; TRACE("\n"); hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); if (FAILED(hr)) return FALSE; hr = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_NONE, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL); if (FAILED(hr)) return FALSE; hr = CoRegisterClassObject(&CLSID_BackgroundCopyManager, (IUnknown *) &BITS_ClassFactory.IClassFactory_iface, CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &dwReg); if (FAILED(hr)) return FALSE; return TRUE; } /* Service entry point */ VOID WINAPI ServiceMain(DWORD dwArgc, LPWSTR *lpszArgv) { HANDLE fileTxThread; static const WCHAR qmgr_nameW[] = {'B','I','T','S',0}; DWORD threadId; TRACE("\n"); stop_event = CreateEventW(NULL, TRUE, FALSE, NULL); if (!stop_event) { ERR("failed to create stop_event\n"); return; } status_handle = RegisterServiceCtrlHandlerExW(qmgr_nameW, ServiceHandler, NULL); if (!status_handle) { ERR("failed to register handler: %u\n", GetLastError()); return; } UpdateStatus(SERVICE_START_PENDING, NO_ERROR, 3000); if (!StartCount()) { ERR("failed starting service thread\n"); UpdateStatus(SERVICE_STOPPED, NO_ERROR, 0); return; } globalMgr.jobEvent = CreateEventW(NULL, TRUE, FALSE, NULL); if (!globalMgr.jobEvent) { ERR("Couldn't create event: error %d\n", GetLastError()); UpdateStatus(SERVICE_STOPPED, NO_ERROR, 0); return; } fileTxThread = CreateThread(NULL, 0, fileTransfer, NULL, 0, &threadId); if (!fileTxThread) { ERR("Failed starting file transfer thread\n"); UpdateStatus(SERVICE_STOPPED, NO_ERROR, 0); return; } UpdateStatus(SERVICE_RUNNING, NO_ERROR, 0); WaitForSingleObject(fileTxThread, INFINITE); UpdateStatus(SERVICE_STOPPED, NO_ERROR, 0); CloseHandle(stop_event); TRACE("service stopped\n"); CoUninitialize(); }