diff --git a/programs/msiexec/Makefile.in b/programs/msiexec/Makefile.in index c2bd981581f..0d09c4c70db 100644 --- a/programs/msiexec/Makefile.in +++ b/programs/msiexec/Makefile.in @@ -7,7 +7,8 @@ APPMODE = -mconsole IMPORTS = msi ole32 advapi32 user32 kernel32 C_SRCS = \ - msiexec.c + msiexec.c \ + service.c RC_SRCS = rsrc.rc RC_BINSRC = rsrc.rc diff --git a/programs/msiexec/msiexec.c b/programs/msiexec/msiexec.c index e4ff579a814..71e81c89add 100644 --- a/programs/msiexec/msiexec.c +++ b/programs/msiexec/msiexec.c @@ -34,6 +34,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(msiexec); typedef HRESULT (WINAPI *DLLREGISTERSERVER)(void); typedef HRESULT (WINAPI *DLLUNREGISTERSERVER)(void); +DWORD DoService(void); + struct string_list { struct string_list *next; @@ -350,7 +352,7 @@ static DWORD DoRegServer(void) } GetSystemDirectory(path, MAX_PATH); - lstrcatA(path, "\\msiexec.exe"); + lstrcatA(path, "\\msiexec.exe /V"); service = CreateServiceA(scm, "MSIServer", "MSIServer", GENERIC_ALL, SERVICE_WIN32_SHARE_PROCESS, SERVICE_DEMAND_START, @@ -502,6 +504,7 @@ int main(int argc, char **argv) BOOL FunctionDllUnregisterServer = FALSE; BOOL FunctionRegServer = FALSE; BOOL FunctionUnregServer = FALSE; + BOOL FunctionServer = FALSE; BOOL FunctionUnknown = FALSE; LPWSTR PackageName = NULL; @@ -905,6 +908,10 @@ int main(int argc, char **argv) FunctionUnknown = TRUE; WINE_FIXME("Unknown parameter /D\n"); } + else if (msi_option_equal(argvW[i], "V")) + { + FunctionServer = TRUE; + } else StringListAppend(&property_list, argvW[i]); } @@ -957,6 +964,10 @@ int main(int argc, char **argv) { WINE_FIXME( "/unregserver not implemented yet, ignoring\n" ); } + else if (FunctionServer) + { + ReturnCode = DoService(); + } else if (FunctionUnknown) { WINE_FIXME( "Unknown function, ignoring\n" ); diff --git a/programs/msiexec/service.c b/programs/msiexec/service.c new file mode 100644 index 00000000000..64618b852f4 --- /dev/null +++ b/programs/msiexec/service.c @@ -0,0 +1,174 @@ +/* + * 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 +#include + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msiexec); + +static SERVICE_STATUS_HANDLE hstatus; + +static HANDLE thread; +static HANDLE kill_event; + +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 = CreateEvent(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_ENTRY service[] = + { + {service_name, ServiceMain}, + {NULL, NULL}, + }; + + WINE_TRACE("Starting MSIServer service\n"); + + if (!StartServiceCtrlDispatcher(service)) + { + fprintf(stderr, "Failed to start MSIServer service\n"); + return 1; + } + + return 0; +}