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