xref: /reactos/dll/win32/qmgr/service.c (revision 02e84521)
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 "winsvc.h"
23 #include "qmgr.h"
24 #include "wine/debug.h"
25 
26 WINE_DEFAULT_DEBUG_CHANNEL(qmgr);
27 
28 HANDLE stop_event = NULL;
29 
30 static SERVICE_STATUS_HANDLE status_handle;
31 static SERVICE_STATUS status;
32 
33 static VOID
34 UpdateStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint)
35 {
36     status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
37     status.dwCurrentState = dwCurrentState;
38     if (dwCurrentState == SERVICE_START_PENDING)
39         status.dwControlsAccepted = 0;
40     else
41         status.dwControlsAccepted
42             = (SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE
43                | SERVICE_ACCEPT_SHUTDOWN);
44     status.dwWin32ExitCode = 0;
45     status.dwServiceSpecificExitCode = 0;
46     status.dwCheckPoint = 0;
47     status.dwWaitHint = dwWaitHint;
48 
49     if (!SetServiceStatus(status_handle, &status)) {
50         ERR("failed to set service status\n");
51         SetEvent(stop_event);
52     }
53 }
54 
55 /* Handle incoming ControlService signals */
56 static DWORD WINAPI
57 ServiceHandler(DWORD ctrl, DWORD event_type, LPVOID event_data, LPVOID context)
58 {
59     switch (ctrl) {
60     case SERVICE_CONTROL_STOP:
61     case SERVICE_CONTROL_SHUTDOWN:
62         TRACE("shutting down service\n");
63         UpdateStatus(SERVICE_STOP_PENDING, NO_ERROR, 0);
64         SetEvent(stop_event);
65         break;
66     default:
67         FIXME("ignoring handle service ctrl %x\n", ctrl);
68         UpdateStatus(status.dwCurrentState, NO_ERROR, 0);
69         break;
70     }
71 
72     return NO_ERROR;
73 }
74 
75 /* Main thread of the service */
76 static BOOL
77 StartCount(void)
78 {
79     HRESULT hr;
80     DWORD dwReg;
81 
82     TRACE("\n");
83 
84     hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
85     if (FAILED(hr))
86         return FALSE;
87 
88     hr = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_NONE,
89                               RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE,
90                               NULL);
91     if (FAILED(hr))
92         return FALSE;
93 
94     hr = CoRegisterClassObject(&CLSID_BackgroundCopyManager,
95                                (IUnknown *) &BITS_ClassFactory.IClassFactory_iface,
96                                CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &dwReg);
97     if (FAILED(hr))
98         return FALSE;
99 
100     return TRUE;
101 }
102 
103 /* Service entry point */
104 VOID WINAPI
105 ServiceMain(DWORD dwArgc, LPWSTR *lpszArgv)
106 {
107     HANDLE fileTxThread;
108     static const WCHAR qmgr_nameW[] = {'B','I','T','S',0};
109     DWORD threadId;
110     TRACE("\n");
111 
112     stop_event = CreateEventW(NULL, TRUE, FALSE, NULL);
113     if (!stop_event) {
114         ERR("failed to create stop_event\n");
115         return;
116     }
117 
118     status_handle = RegisterServiceCtrlHandlerExW(qmgr_nameW, ServiceHandler, NULL);
119     if (!status_handle) {
120         ERR("failed to register handler: %u\n", GetLastError());
121         return;
122     }
123 
124     UpdateStatus(SERVICE_START_PENDING, NO_ERROR, 3000);
125     if (!StartCount()) {
126         ERR("failed starting service thread\n");
127         UpdateStatus(SERVICE_STOPPED, NO_ERROR, 0);
128         return;
129     }
130 
131     globalMgr.jobEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
132     if (!globalMgr.jobEvent) {
133         ERR("Couldn't create event: error %d\n", GetLastError());
134         UpdateStatus(SERVICE_STOPPED, NO_ERROR, 0);
135         return;
136     }
137 
138     fileTxThread = CreateThread(NULL, 0, fileTransfer, NULL, 0, &threadId);
139     if (!fileTxThread)
140     {
141         ERR("Failed starting file transfer thread\n");
142         UpdateStatus(SERVICE_STOPPED, NO_ERROR, 0);
143         return;
144     }
145 
146     UpdateStatus(SERVICE_RUNNING, NO_ERROR, 0);
147 
148     WaitForSingleObject(fileTxThread, INFINITE);
149     UpdateStatus(SERVICE_STOPPED, NO_ERROR, 0);
150     CloseHandle(stop_event);
151     TRACE("service stopped\n");
152 
153     CoUninitialize();
154 }
155