qmgr: COM cleanup of IBackgroundCopyJob2 interface.
[wine] / dlls / qmgr / service.c
1 /*
2  * ServiceMain function for qmgr running within svchost
3  *
4  * Copyright 2007 (C) Google (Roy Shea)
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "windef.h"
22 #include "objbase.h"
23 #include "winsvc.h"
24 #include "bits.h"
25
26 #include "qmgr.h"
27 #include "wine/debug.h"
28
29 WINE_DEFAULT_DEBUG_CHANNEL(qmgr);
30
31 HANDLE stop_event = NULL;
32
33 static SERVICE_STATUS_HANDLE status_handle;
34 static SERVICE_STATUS status;
35
36 static VOID
37 UpdateStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint)
38 {
39     status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
40     status.dwCurrentState = dwCurrentState;
41     if (dwCurrentState == SERVICE_START_PENDING)
42         status.dwControlsAccepted = 0;
43     else
44         status.dwControlsAccepted
45             = (SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE
46                | SERVICE_ACCEPT_SHUTDOWN);
47     status.dwWin32ExitCode = 0;
48     status.dwServiceSpecificExitCode = 0;
49     status.dwCheckPoint = 0;
50     status.dwWaitHint = dwWaitHint;
51
52     if (!SetServiceStatus(status_handle, &status)) {
53         ERR("failed to set service status\n");
54         SetEvent(stop_event);
55     }
56 }
57
58 /* Handle incoming ControlService signals */
59 static DWORD WINAPI
60 ServiceHandler(DWORD ctrl, DWORD event_type, LPVOID event_data, LPVOID context)
61 {
62     switch (ctrl) {
63     case SERVICE_CONTROL_STOP:
64     case SERVICE_CONTROL_SHUTDOWN:
65         TRACE("shutting down service\n");
66         UpdateStatus(SERVICE_STOP_PENDING, NO_ERROR, 0);
67         SetEvent(stop_event);
68         break;
69     default:
70         FIXME("ignoring handle service ctrl %x\n", ctrl);
71         UpdateStatus(status.dwCurrentState, NO_ERROR, 0);
72         break;
73     }
74
75     return NO_ERROR;
76 }
77
78 /* Main thread of the service */
79 static BOOL
80 StartCount(void)
81 {
82     HRESULT hr;
83     DWORD dwReg;
84
85     TRACE("\n");
86
87     hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
88     if (FAILED(hr))
89         return FALSE;
90
91     hr = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_NONE,
92                               RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE,
93                               NULL);
94     if (FAILED(hr))
95         return FALSE;
96
97     hr = CoRegisterClassObject(&CLSID_BackgroundCopyManager,
98                                (IUnknown *) &BITS_ClassFactory.IClassFactory_iface,
99                                CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &dwReg);
100     if (FAILED(hr))
101         return FALSE;
102
103     return TRUE;
104 }
105
106 /* Service entry point */
107 VOID WINAPI
108 ServiceMain(DWORD dwArgc, LPWSTR *lpszArgv)
109 {
110     HANDLE fileTxThread;
111     static const WCHAR qmgr_nameW[] = {'B','I','T','S',0};
112     DWORD threadId;
113     TRACE("\n");
114
115     stop_event = CreateEventW(NULL, TRUE, FALSE, NULL);
116     if (!stop_event) {
117         ERR("failed to create stop_event\n");
118         return;
119     }
120
121     status_handle = RegisterServiceCtrlHandlerExW(qmgr_nameW, ServiceHandler, NULL);
122     if (!status_handle) {
123         ERR("failed to register handler: %u\n", GetLastError());
124         return;
125     }
126
127     UpdateStatus(SERVICE_START_PENDING, NO_ERROR, 3000);
128     if (!StartCount()) {
129         ERR("failed starting service thread\n");
130         UpdateStatus(SERVICE_STOPPED, NO_ERROR, 0);
131         return;
132     }
133
134     globalMgr.jobEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
135     if (!globalMgr.jobEvent) {
136         ERR("Couldn't create event: error %d\n", GetLastError());
137         UpdateStatus(SERVICE_STOPPED, NO_ERROR, 0);
138         return;
139     }
140
141     fileTxThread = CreateThread(NULL, 0, fileTransfer, NULL, 0, &threadId);
142     if (!fileTxThread)
143     {
144         ERR("Failed starting file transfer thread\n");
145         UpdateStatus(SERVICE_STOPPED, NO_ERROR, 0);
146         return;
147     }
148
149     UpdateStatus(SERVICE_RUNNING, NO_ERROR, 0);
150
151     WaitForSingleObject(fileTxThread, INFINITE);
152     UpdateStatus(SERVICE_STOPPED, NO_ERROR, 0);
153     CloseHandle(stop_event);
154     TRACE("service stoped\n");
155
156     CoUninitialize();
157 }