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