diff --git a/dlls/msi/action.c b/dlls/msi/action.c index 436b06c47be..cd5bf4b748f 100644 --- a/dlls/msi/action.c +++ b/dlls/msi/action.c @@ -4164,6 +4164,132 @@ static UINT ACTION_InstallServices( MSIPACKAGE *package ) return rc; } +/* converts arg1[~]arg2[~]arg3 to a list of ptrs to the strings */ +static LPCWSTR *msi_service_args_to_vector(LPCWSTR name, LPWSTR args, DWORD *numargs) +{ + LPCWSTR *vector; + LPWSTR p, q; + DWORD sep_len; + + static const WCHAR separator[] = {'[','~',']',0}; + + *numargs = 0; + sep_len = sizeof(separator) / sizeof(WCHAR) - 1; + + if (!args) + return NULL; + + vector = msi_alloc(sizeof(LPWSTR)); + if (!vector) + return NULL; + + p = args; + do + { + (*numargs)++; + vector[*numargs - 1] = p; + + if ((q = strstrW(p, separator))) + { + *q = '\0'; + + vector = msi_realloc(vector, (*numargs + 1) * sizeof(LPWSTR)); + if (!vector) + return NULL; + + p = q + sep_len; + } + } while (q); + + return vector; +} + +static MSICOMPONENT *msi_find_component( MSIPACKAGE *package, LPCWSTR component ) +{ + MSICOMPONENT *comp; + + LIST_FOR_EACH_ENTRY(comp, &package->components, MSICOMPONENT, entry) + { + if (!lstrcmpW(comp->Component, component)) + return comp; + } + + return NULL; +} + +static UINT ITERATE_StartService(MSIRECORD *rec, LPVOID param) +{ + MSIPACKAGE *package = (MSIPACKAGE *)param; + MSICOMPONENT *comp; + SC_HANDLE scm, service = NULL; + LPCWSTR name, *vector = NULL; + LPWSTR args; + DWORD event, numargs; + UINT r = ERROR_FUNCTION_FAILED; + + comp = msi_find_component(package, MSI_RecordGetString(rec, 6)); + if (!comp || comp->Action == INSTALLSTATE_UNKNOWN || comp->Action == INSTALLSTATE_ABSENT) + return ERROR_SUCCESS; + + name = MSI_RecordGetString(rec, 2); + event = MSI_RecordGetInteger(rec, 3); + args = strdupW(MSI_RecordGetString(rec, 4)); + + if (!(event & msidbServiceControlEventStart)) + return ERROR_SUCCESS; + + scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT); + if (!scm) + { + ERR("Failed to open the service control manager\n"); + goto done; + } + + service = OpenServiceW(scm, name, SERVICE_START); + if (!service) + { + ERR("Failed to open service '%s'\n", debugstr_w(name)); + goto done; + } + + vector = msi_service_args_to_vector(name, args, &numargs); + + if (!StartServiceW(service, numargs, vector)) + { + ERR("Failed to start service '%s'\n", debugstr_w(name)); + goto done; + } + + r = ERROR_SUCCESS; + +done: + CloseServiceHandle(service); + CloseServiceHandle(scm); + + msi_free(args); + msi_free(vector); + return r; +} + +static UINT ACTION_StartServices( MSIPACKAGE *package ) +{ + UINT rc; + MSIQUERY *view; + + static const WCHAR query[] = { + 'S','E','L','E','C','T',' ','*',' ','F','R','O','M',' ', + 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 }; + + rc = MSI_DatabaseOpenViewW(package->db, query, &view); + if (rc != ERROR_SUCCESS) + return ERROR_SUCCESS; + + rc = MSI_IterateRecords(view, NULL, ITERATE_StartService, package); + msiobj_release(&view->hdr); + + return rc; +} + static MSIFILE *msi_find_file( MSIPACKAGE *package, LPCWSTR filename ) { MSIFILE *file; @@ -4336,13 +4462,6 @@ static UINT ACTION_SelfUnregModules( MSIPACKAGE *package ) return msi_unimplemented_action_stub( package, "SelfUnregModules", table ); } -static UINT ACTION_StartServices( MSIPACKAGE *package ) -{ - static const WCHAR table[] = { - 'S','e','r','v','i','c','e','C','o','n','t','r','o','l',0 }; - return msi_unimplemented_action_stub( package, "StartServices", table ); -} - static UINT ACTION_StopServices( MSIPACKAGE *package ) { static const WCHAR table[] = { diff --git a/include/msidefs.h b/include/msidefs.h index 083005b95e0..b99537f9193 100644 --- a/include/msidefs.h +++ b/include/msidefs.h @@ -184,6 +184,16 @@ enum msidbLocatorType msidbLocatorType64bit = 0x010, }; +enum msidbServiceControlEvent +{ + msidbServiceControlEventStart = 0x00000001, + msidbServiceControlEventStop = 0x00000002, + msidbServiceControlEventDelete = 0x00000008, + msidbServiceControlEventUninstallStart = 0x00000010, + msidbServiceControlEventUninstallStop = 0x00000020, + msidbServiceControlEventUninstallDelete = 0x00000080, +}; + /* * Windows SDK braindamage alert *