[MSIEXEC] Sync with Wine Staging 1.9.4. CORE-10912
[reactos.git] / reactos / base / system / msiexec / service.c
1 /*
2 * msiexec.exe implementation
3 *
4 * Copyright 2007 Google (James Hawkins)
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 "precomp.h"
22
23 static SERVICE_STATUS_HANDLE hstatus;
24
25 static HANDLE thread;
26 static HANDLE kill_event;
27
28 static void KillService(void)
29 {
30 WINE_TRACE("Killing service\n");
31 SetEvent(kill_event);
32 }
33
34 static BOOL UpdateSCMStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode,
35 DWORD dwServiceSpecificExitCode)
36 {
37 SERVICE_STATUS status;
38
39 status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
40 status.dwCurrentState = dwCurrentState;
41
42 if (dwCurrentState == SERVICE_START_PENDING
43 || dwCurrentState == SERVICE_STOP_PENDING
44 || dwCurrentState == SERVICE_STOPPED)
45 status.dwControlsAccepted = 0;
46 else
47 {
48 status.dwControlsAccepted = SERVICE_ACCEPT_STOP |
49 SERVICE_ACCEPT_PAUSE_CONTINUE |
50 SERVICE_ACCEPT_SHUTDOWN;
51 }
52
53 if (dwServiceSpecificExitCode == 0)
54 {
55 status.dwWin32ExitCode = dwWin32ExitCode;
56 }
57 else
58 {
59 status.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
60 }
61
62 status.dwServiceSpecificExitCode = dwServiceSpecificExitCode;
63 status.dwCheckPoint = 0;
64 status.dwWaitHint = 0;
65
66 if (!SetServiceStatus(hstatus, &status))
67 {
68 fprintf(stderr, "Failed to set service status\n");
69 KillService();
70 return FALSE;
71 }
72
73 return TRUE;
74 }
75
76 static void WINAPI ServiceCtrlHandler(DWORD code)
77 {
78 WINE_TRACE("%u\n", code);
79
80 switch (code)
81 {
82 case SERVICE_CONTROL_SHUTDOWN:
83 case SERVICE_CONTROL_STOP:
84 UpdateSCMStatus(SERVICE_STOP_PENDING, NO_ERROR, 0);
85 KillService();
86 break;
87 default:
88 fprintf(stderr, "Unhandled service control code: %u\n", code);
89 UpdateSCMStatus(SERVICE_RUNNING, NO_ERROR, 0);
90 break;
91 }
92 }
93
94 static DWORD WINAPI ServiceExecutionThread(LPVOID param)
95 {
96 WaitForSingleObject(kill_event, INFINITE);
97
98 return 0;
99 }
100
101 static BOOL StartServiceThread(void)
102 {
103 DWORD id;
104
105 thread = CreateThread(0, 0, ServiceExecutionThread, 0, 0, &id);
106 if (!thread)
107 {
108 fprintf(stderr, "Failed to create thread\n");
109 return FALSE;
110 }
111
112 return TRUE;
113 }
114
115 static void WINAPI ServiceMain(DWORD argc, LPSTR *argv)
116 {
117 hstatus = RegisterServiceCtrlHandlerA("MSIServer", ServiceCtrlHandler);
118 if (!hstatus)
119 {
120 fprintf(stderr, "Failed to register service ctrl handler\n");
121 return;
122 }
123
124 UpdateSCMStatus(SERVICE_START_PENDING, NO_ERROR, 0);
125
126 kill_event = CreateEventW(0, TRUE, FALSE, 0);
127 if (!kill_event)
128 {
129 fprintf(stderr, "Failed to create event\n");
130 KillService();
131 UpdateSCMStatus(SERVICE_STOPPED, NO_ERROR, 0);
132 return;
133 }
134
135 if (!StartServiceThread())
136 {
137 KillService();
138 UpdateSCMStatus(SERVICE_STOPPED, NO_ERROR, 0);
139 return;
140 }
141
142 UpdateSCMStatus(SERVICE_RUNNING, NO_ERROR, 0);
143 WaitForSingleObject(thread, INFINITE);
144 UpdateSCMStatus(SERVICE_STOPPED, NO_ERROR, 0);
145 }
146
147 DWORD DoService(void)
148 {
149 char service_name[] = "MSIServer";
150
151 const SERVICE_TABLE_ENTRYA service[] =
152 {
153 {service_name, ServiceMain},
154 {NULL, NULL},
155 };
156
157 WINE_TRACE("Starting MSIServer service\n");
158
159 if (!StartServiceCtrlDispatcherA(service))
160 {
161 fprintf(stderr, "Failed to start MSIServer service\n");
162 return 1;
163 }
164
165 return 0;
166 }