text: /*
   * 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 "objbase.h"
  #include "winsvc.h"
  #include "bits.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,
                                 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 stoped\n");
  
      CoUninitialize();
  }
  