winex11: Rudimentary drawing support for display balloon tool tips in systray.
[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 WCHAR qmgr_nameW[] = {'B','I','T','S',0};
34 static SERVICE_STATUS_HANDLE status_handle;
35 static SERVICE_STATUS status;
36
37 static VOID
38 UpdateStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint)
39 {
40     status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
41     status.dwCurrentState = dwCurrentState;
42     if (dwCurrentState == SERVICE_START_PENDING)
43         status.dwControlsAccepted = 0;
44     else
45         status.dwControlsAccepted
46             = (SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE
47                | SERVICE_ACCEPT_SHUTDOWN);
48     status.dwWin32ExitCode = 0;
49     status.dwServiceSpecificExitCode = 0;
50     status.dwCheckPoint = 0;
51     status.dwWaitHint = dwWaitHint;
52
53     if (!SetServiceStatus(status_handle, &status)) {
54         ERR("failed to set service status\n");
55         SetEvent(stop_event);
56     }
57 }
58
59 /* Handle incoming ControlService signals */
60 static DWORD WINAPI
61 ServiceHandler(DWORD ctrl, DWORD event_type, LPVOID event_data, LPVOID context)
62 {
63     switch (ctrl) {
64     case SERVICE_CONTROL_STOP:
65     case SERVICE_CONTROL_SHUTDOWN:
66         TRACE("shutting down service\n");
67         UpdateStatus(SERVICE_STOP_PENDING, NO_ERROR, 0);
68         SetEvent(stop_event);
69         break;
70     default:
71         FIXME("ignoring handle service ctrl %x\n", ctrl);
72         UpdateStatus(status.dwCurrentState, NO_ERROR, 0);
73         break;
74     }
75
76     return NO_ERROR;
77 }
78
79 /* Main thread of the service */
80 static BOOL
81 StartCount(void)
82 {
83     HRESULT hr;
84     DWORD dwReg;
85
86     TRACE("\n");
87
88     hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
89     if (!SUCCEEDED(hr))
90         return FALSE;
91
92     hr = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_NONE,
93                               RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE,
94                               NULL);
95     if (!SUCCEEDED(hr))
96         return FALSE;
97
98     hr = CoRegisterClassObject(&CLSID_BackgroundCopyManager,
99                                (IUnknown *) &BITS_ClassFactory,
100                                CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE,
101                                &dwReg);
102     if (!SUCCEEDED(hr))
103         return FALSE;
104
105     return TRUE;
106 }
107
108 /* Service entry point */
109 VOID WINAPI
110 ServiceMain(DWORD dwArgc, LPWSTR *lpszArgv)
111 {
112     HANDLE fileTxThread;
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 }