wininet: Implement RetrieveUrlCacheEntryStreamW.
[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,
99                                CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE,
100                                &dwReg);
101     if (FAILED(hr))
102         return FALSE;
103
104     return TRUE;
105 }
106
107 /* Service entry point */
108 VOID WINAPI
109 ServiceMain(DWORD dwArgc, LPWSTR *lpszArgv)
110 {
111     HANDLE fileTxThread;
112     static const WCHAR qmgr_nameW[] = {'B','I','T','S',0};
113     DWORD threadId;
114     TRACE("\n");
115
116     stop_event = CreateEventW(NULL, TRUE, FALSE, NULL);
117     if (!stop_event) {
118         ERR("failed to create stop_event\n");
119         return;
120     }
121
122     status_handle = RegisterServiceCtrlHandlerExW(qmgr_nameW, ServiceHandler, NULL);
123     if (!status_handle) {
124         ERR("failed to register handler: %u\n", GetLastError());
125         return;
126     }
127
128     UpdateStatus(SERVICE_START_PENDING, NO_ERROR, 3000);
129     if (!StartCount()) {
130         ERR("failed starting service thread\n");
131         UpdateStatus(SERVICE_STOPPED, NO_ERROR, 0);
132         return;
133     }
134
135     globalMgr.jobEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
136     if (!globalMgr.jobEvent) {
137         ERR("Couldn't create event: error %d\n", GetLastError());
138         UpdateStatus(SERVICE_STOPPED, NO_ERROR, 0);
139         return;
140     }
141
142     fileTxThread = CreateThread(NULL, 0, fileTransfer, NULL, 0, &threadId);
143     if (!fileTxThread)
144     {
145         ERR("Failed starting file transfer thread\n");
146         UpdateStatus(SERVICE_STOPPED, NO_ERROR, 0);
147         return;
148     }
149
150     UpdateStatus(SERVICE_RUNNING, NO_ERROR, 0);
151
152     WaitForSingleObject(fileTxThread, INFINITE);
153     UpdateStatus(SERVICE_STOPPED, NO_ERROR, 0);
154     CloseHandle(stop_event);
155     TRACE("service stoped\n");
156
157     CoUninitialize();
158 }