kernel32: Fix file test compilation with PSDK headers.
[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 <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         status.dwControlsAccepted = 0;
52     else
53     {
54         status.dwControlsAccepted = SERVICE_ACCEPT_STOP |
55                                     SERVICE_ACCEPT_PAUSE_CONTINUE |
56                                     SERVICE_ACCEPT_SHUTDOWN;
57     }
58
59     if (dwServiceSpecificExitCode == 0)
60     {
61         status.dwWin32ExitCode = dwWin32ExitCode;
62     }
63     else
64     {
65         status.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
66     }
67
68     status.dwServiceSpecificExitCode = dwServiceSpecificExitCode;
69     status.dwCheckPoint = 0;
70     status.dwWaitHint = 0;
71
72     if (!SetServiceStatus(hstatus, &status))
73     {
74         fprintf(stderr, "Failed to set service status\n");
75         KillService();
76         return FALSE;
77     }
78
79     return TRUE;
80 }
81
82 static void WINAPI ServiceCtrlHandler(DWORD code)
83 {
84     WINE_TRACE("%d\n", code);
85
86     switch (code)
87     {
88         case SERVICE_CONTROL_SHUTDOWN:
89         case SERVICE_CONTROL_STOP:
90             UpdateSCMStatus(SERVICE_STOP_PENDING, NO_ERROR, 0);
91             KillService();
92             return;
93         default:
94             fprintf(stderr, "Unhandled service control code: %d\n", code);
95             break;
96     }
97
98     UpdateSCMStatus(SERVICE_RUNNING, NO_ERROR, 0);
99 }
100
101 static DWORD WINAPI ServiceExecutionThread(LPVOID param)
102 {
103     while (TRUE)
104     {
105         /* do nothing */
106     }
107
108     return 0;
109 }
110
111 static BOOL StartServiceThread(void)
112 {
113     DWORD id;
114
115     thread = CreateThread(0, 0, ServiceExecutionThread, 0, 0, &id);
116     if (!thread)
117     {
118         fprintf(stderr, "Failed to create thread\n");
119         return FALSE;
120     }
121
122     return TRUE;
123 }
124
125 static void WINAPI ServiceMain(DWORD argc, LPSTR *argv)
126 {
127     hstatus = RegisterServiceCtrlHandlerA("MSIServer", ServiceCtrlHandler);
128     if (!hstatus)
129     {
130         fprintf(stderr, "Failed to register service ctrl handler\n");
131         return;
132     }
133
134     UpdateSCMStatus(SERVICE_START_PENDING, NO_ERROR, 0);
135
136     kill_event = CreateEventW(0, TRUE, FALSE, 0);
137     if (!kill_event)
138     {
139         fprintf(stderr, "Failed to create event\n");
140         KillService();
141         return;
142     }
143
144     if (!StartServiceThread())
145     {
146         KillService();
147         return;
148     }
149
150     UpdateSCMStatus(SERVICE_RUNNING, NO_ERROR, 0);
151
152     WaitForSingleObject(kill_event, INFINITE);
153     KillService();
154 }
155
156 DWORD DoService(void)
157 {
158     char service_name[] = "MSIServer";
159
160     const SERVICE_TABLE_ENTRYA service[] =
161     {
162         {service_name, ServiceMain},
163         {NULL, NULL},
164     };
165
166     WINE_TRACE("Starting MSIServer service\n");
167
168     if (!StartServiceCtrlDispatcherA(service))
169     {
170         fprintf(stderr, "Failed to start MSIServer service\n");
171         return 1;
172     }
173
174     return 0;
175 }