Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/programs/msiexec/service.c
4389 views
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 <winsvc.h>
25
26
#include "wine/debug.h"
27
#include "msiexec_internal.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
report_error("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("%ld\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
report_error("Unhandled service control code: %ld\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
report_error("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
report_error("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
report_error("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
report_error("Failed to start MSIServer service\n");
170
return 1;
171
}
172
173
return 0;
174
}
175
176