|  | /* | 
|  | * msiexec.exe implementation | 
|  | * | 
|  | * Copyright 2007 Google (James Hawkins) | 
|  | * | 
|  | * This library is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU Lesser General Public | 
|  | * License as published by the Free Software Foundation; either | 
|  | * version 2.1 of the License, or (at your option) any later version. | 
|  | * | 
|  | * This library is distributed in the hope that it will be useful, | 
|  | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|  | * Lesser General Public License for more details. | 
|  | * | 
|  | * You should have received a copy of the GNU Lesser General Public | 
|  | * License along with this library; if not, write to the Free Software | 
|  | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | 
|  | */ | 
|  |  | 
|  | #define WIN32_LEAN_AND_MEAN | 
|  |  | 
|  | #include <windows.h> | 
|  | #include <stdio.h> | 
|  |  | 
|  | #include "wine/debug.h" | 
|  |  | 
|  | WINE_DEFAULT_DEBUG_CHANNEL(msiexec); | 
|  |  | 
|  | static SERVICE_STATUS_HANDLE hstatus; | 
|  |  | 
|  | static HANDLE thread; | 
|  | static HANDLE kill_event; | 
|  |  | 
|  | static void KillService(void) | 
|  | { | 
|  | WINE_TRACE("Killing service\n"); | 
|  | SetEvent(kill_event); | 
|  | } | 
|  |  | 
|  | static BOOL UpdateSCMStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode, | 
|  | DWORD dwServiceSpecificExitCode) | 
|  | { | 
|  | SERVICE_STATUS status; | 
|  |  | 
|  | status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; | 
|  | status.dwCurrentState = dwCurrentState; | 
|  |  | 
|  | if (dwCurrentState == SERVICE_START_PENDING) | 
|  | status.dwControlsAccepted = 0; | 
|  | else | 
|  | { | 
|  | status.dwControlsAccepted = SERVICE_ACCEPT_STOP | | 
|  | SERVICE_ACCEPT_PAUSE_CONTINUE | | 
|  | SERVICE_ACCEPT_SHUTDOWN; | 
|  | } | 
|  |  | 
|  | if (dwServiceSpecificExitCode == 0) | 
|  | { | 
|  | status.dwWin32ExitCode = dwWin32ExitCode; | 
|  | } | 
|  | else | 
|  | { | 
|  | status.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR; | 
|  | } | 
|  |  | 
|  | status.dwServiceSpecificExitCode = dwServiceSpecificExitCode; | 
|  | status.dwCheckPoint = 0; | 
|  | status.dwWaitHint = 0; | 
|  |  | 
|  | if (!SetServiceStatus(hstatus, &status)) | 
|  | { | 
|  | fprintf(stderr, "Failed to set service status\n"); | 
|  | KillService(); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | static void WINAPI ServiceCtrlHandler(DWORD code) | 
|  | { | 
|  | WINE_TRACE("%d\n", code); | 
|  |  | 
|  | switch (code) | 
|  | { | 
|  | case SERVICE_CONTROL_SHUTDOWN: | 
|  | case SERVICE_CONTROL_STOP: | 
|  | UpdateSCMStatus(SERVICE_STOP_PENDING, NO_ERROR, 0); | 
|  | KillService(); | 
|  | return; | 
|  | default: | 
|  | fprintf(stderr, "Unhandled service control code: %d\n", code); | 
|  | break; | 
|  | } | 
|  |  | 
|  | UpdateSCMStatus(SERVICE_RUNNING, NO_ERROR, 0); | 
|  | } | 
|  |  | 
|  | static DWORD WINAPI ServiceExecutionThread(LPVOID param) | 
|  | { | 
|  | while (TRUE) | 
|  | { | 
|  | /* do nothing */ | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static BOOL StartServiceThread(void) | 
|  | { | 
|  | DWORD id; | 
|  |  | 
|  | thread = CreateThread(0, 0, ServiceExecutionThread, 0, 0, &id); | 
|  | if (!thread) | 
|  | { | 
|  | fprintf(stderr, "Failed to create thread\n"); | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | return TRUE; | 
|  | } | 
|  |  | 
|  | static void WINAPI ServiceMain(DWORD argc, LPSTR *argv) | 
|  | { | 
|  | hstatus = RegisterServiceCtrlHandlerA("MSIServer", ServiceCtrlHandler); | 
|  | if (!hstatus) | 
|  | { | 
|  | fprintf(stderr, "Failed to register service ctrl handler\n"); | 
|  | return; | 
|  | } | 
|  |  | 
|  | UpdateSCMStatus(SERVICE_START_PENDING, NO_ERROR, 0); | 
|  |  | 
|  | kill_event = CreateEventW(0, TRUE, FALSE, 0); | 
|  | if (!kill_event) | 
|  | { | 
|  | fprintf(stderr, "Failed to create event\n"); | 
|  | KillService(); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (!StartServiceThread()) | 
|  | { | 
|  | KillService(); | 
|  | return; | 
|  | } | 
|  |  | 
|  | UpdateSCMStatus(SERVICE_RUNNING, NO_ERROR, 0); | 
|  |  | 
|  | WaitForSingleObject(kill_event, INFINITE); | 
|  | KillService(); | 
|  | } | 
|  |  | 
|  | DWORD DoService(void) | 
|  | { | 
|  | char service_name[] = "MSIServer"; | 
|  |  | 
|  | const SERVICE_TABLE_ENTRYA service[] = | 
|  | { | 
|  | {service_name, ServiceMain}, | 
|  | {NULL, NULL}, | 
|  | }; | 
|  |  | 
|  | WINE_TRACE("Starting MSIServer service\n"); | 
|  |  | 
|  | if (!StartServiceCtrlDispatcherA(service)) | 
|  | { | 
|  | fprintf(stderr, "Failed to start MSIServer service\n"); | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } |