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