From: Hervé Poussineau Date: Wed, 21 Dec 2005 12:28:55 +0000 (+0000) Subject: - Fix horribly broken implementation of SetupInstallServicesFromInfSectionExW, which... X-Git-Tag: backups/expat-rbuild@40467~843 X-Git-Url: https://git.reactos.org/?p=reactos.git;a=commitdiff_plain;h=62d79cb1cdb52dd61df0d32b0cdca79666f9f18d - Fix horribly broken implementation of SetupInstallServicesFromInfSectionExW, which should install a whole Services section and not a particular service. - Simplify handling of Include and Needs directives svn path=/trunk/; revision=20283 --- diff --git a/reactos/lib/setupapi/devinst.c b/reactos/lib/setupapi/devinst.c index 7369f4e8ab6..c3130033977 100644 --- a/reactos/lib/setupapi/devinst.c +++ b/reactos/lib/setupapi/devinst.c @@ -3174,182 +3174,6 @@ static HKEY CreateClassKey(HINF hInf) } -static BOOL -InstallServicesSection( - IN HINF hInf, - IN PCWSTR SectionName, - IN HDEVINFO DeviceInfoSet OPTIONAL, - IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL, - OUT PCWSTR* pAssociatedService OPTIONAL, - OUT PBOOL pRebootRequired OPTIONAL) -{ - INFCONTEXT ContextService; - INFCONTEXT ContextInclude; - DWORD RequiredSize; - INT Flags; - BOOL ret = FALSE; - - /* Parse 'Include' line */ - if (SetupFindFirstLineW(hInf, SectionName, L"Include", &ContextInclude)) - { - DWORD Index = 1; - while (TRUE) - { - static WCHAR szBuffer[MAX_PATH]; - PWSTR pBuffer = NULL; - DWORD required; - - ret = SetupGetStringFieldW(&ContextInclude, Index, szBuffer, MAX_PATH, &required); - if (!ret && GetLastError() == ERROR_INVALID_PARAMETER) - break; - else if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER) - { - pBuffer = MyMalloc(required); - ret = SetupGetStringFieldW(&ContextInclude, Index, pBuffer, required, &required); - } - if (ret) - ret = SetupOpenAppendInfFileW(pBuffer ? pBuffer : szBuffer, hInf, NULL); - - MyFree(pBuffer); - if (!ret) - goto done; - Index++; - } - } - - /* Parse 'Needs' line */ - if (SetupFindFirstLineW(hInf, SectionName, L"Needs", &ContextInclude)) - { - DWORD Index = 1; - while (TRUE) - { - static WCHAR szBuffer[MAX_PATH]; - PWSTR pBuffer = NULL; - DWORD required; - - ret = SetupGetStringFieldW(&ContextInclude, Index, szBuffer, MAX_PATH, &required); - if (!ret && GetLastError() == ERROR_INVALID_PARAMETER) - break; - else if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER) - { - pBuffer = MyMalloc(required); - ret = SetupGetStringFieldW(&ContextInclude, Index, pBuffer, required, &required); - } - if (ret) - { - ret = InstallServicesSection(hInf, pBuffer ? pBuffer : szBuffer, - DeviceInfoSet, DeviceInfoData, pAssociatedService, pRebootRequired); - } - - MyFree(pBuffer); - if (!ret) - goto done; - Index++; - } - } - - ret = SetupFindFirstLineW(hInf, SectionName, NULL, &ContextService); - while (ret) - { - LPWSTR ServiceName = NULL; - LPWSTR ServiceSection = NULL; - - ret = SetupGetStringFieldW( - &ContextService, - 1, /* Field index */ - NULL, 0, - &RequiredSize); - if (!ret) - goto nextservice; - if (RequiredSize > 0) - { - /* We got the needed size for the buffer */ - ServiceName = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR)); - if (!ServiceName) - { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - goto nextservice; - } - ret = SetupGetStringFieldW( - &ContextService, - 1, /* Field index */ - ServiceName, RequiredSize, - &RequiredSize); - if (!ret) - goto nextservice; - } - ret = SetupGetIntField( - &ContextService, - 2, /* Field index */ - &Flags); - if (!ret) - { - /* The field may be empty. Ignore the error */ - Flags = 0; - } - ret = SetupGetStringFieldW( - &ContextService, - 3, /* Field index */ - NULL, 0, - &RequiredSize); - if (!ret) - { - if (GetLastError() == ERROR_INVALID_PARAMETER) - { - /* This first is probably missing. It is not - * required, so ignore the error */ - RequiredSize = 0; - ret = TRUE; - } - else - goto nextservice; - } - if (RequiredSize > 0) - { - /* We got the needed size for the buffer */ - ServiceSection = HeapAlloc(GetProcessHeap(), 0, RequiredSize * sizeof(WCHAR)); - if (!ServiceSection) - { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - goto nextservice; - } - ret = SetupGetStringFieldW( - &ContextService, - 3, /* Field index */ - ServiceSection, RequiredSize, - &RequiredSize); - if (!ret) - goto nextservice; - - SetLastError(ERROR_SUCCESS); - ret = SetupInstallServicesFromInfSectionExW( - hInf, - ServiceSection, Flags, DeviceInfoSet, DeviceInfoData, ServiceName, NULL); - } - if (ret && (Flags & SPSVCINST_ASSOCSERVICE)) - { - if (pAssociatedService) - { - *pAssociatedService = ServiceName; - ServiceName = NULL; - } - if (pRebootRequired && GetLastError() == ERROR_SUCCESS_REBOOT_REQUIRED) - *pRebootRequired = TRUE; - } -nextservice: - HeapFree(GetProcessHeap(), 0, ServiceName); - HeapFree(GetProcessHeap(), 0, ServiceSection); - if (!ret) - goto done; - ret = SetupFindNextLine(&ContextService, &ContextService); - } - - ret = TRUE; - -done: - return ret; -} - /*********************************************************************** * SetupDiInstallClassExW (SETUPAPI.@) */ @@ -3451,7 +3275,7 @@ BOOL WINAPI SetupDiInstallClassExW( /* Install .Services section */ lstrcatW(SectionName, DotServices); - ret = InstallServicesSection(hInf, SectionName, NULL, NULL, NULL, NULL); + ret = SetupInstallServicesFromInfSectionW(hInf, SectionName, 0); if (!ret) goto cleanup; @@ -5585,8 +5409,6 @@ SetupDiBuildDriverInfoList( SetLastError(ERROR_INVALID_HANDLE); else if (DriverType != SPDIT_CLASSDRIVER && DriverType != SPDIT_COMPATDRIVER) SetLastError(ERROR_INVALID_PARAMETER); - else if (DriverType == SPDIT_CLASSDRIVER && DeviceInfoData) - SetLastError(ERROR_INVALID_PARAMETER); else if (DriverType == SPDIT_COMPATDRIVER && !DeviceInfoData) SetLastError(ERROR_INVALID_PARAMETER); else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)) @@ -7404,7 +7226,6 @@ SetupDiInstallDevice( BOOL Result = FALSE; ULONG DoAction; DWORD RequiredSize; - LPCWSTR AssociatedService = NULL; LPWSTR pSectionName = NULL; WCHAR ClassName[MAX_CLASS_NAME_LEN]; GUID ClassGuid; @@ -7569,15 +7390,18 @@ SetupDiInstallDevice( /* Install .Services section */ wcscpy(pSectionName, DotServices); - Result = InstallServicesSection( + Result = SetupInstallServicesFromInfSectionExW( SelectedDriver->InfFileDetails->hInf, SectionName, + 0, DeviceInfoSet, DeviceInfoData, - &AssociatedService, - &RebootRequired); + NULL, + NULL); if (!Result) goto cleanup; + if (GetLastError() == ERROR_SUCCESS_REBOOT_REQUIRED) + RebootRequired = TRUE; /* Copy .inf file to Inf\ directory (if needed) */ Result = InfIsFromOEMLocation(SelectedDriver->InfFileDetails->FullInfFileName, &NeedtoCopyFile); @@ -7620,7 +7444,6 @@ SetupDiInstallDevice( TRACE("ClassGUID : '%S'\n", lpFullGuidString); TRACE("DeviceDesc : '%S'\n", SelectedDriver->Info.Description); TRACE("Mfg : '%S'\n", SelectedDriver->Info.MfgName); - TRACE("Service : '%S'\n", AssociatedService); rc = RegSetValueEx(hKey, REGSTR_VAL_CLASS, 0, REG_SZ, (const BYTE *)ClassName, (wcslen(ClassName) + 1) * sizeof(WCHAR)); if (rc == ERROR_SUCCESS) rc = RegSetValueEx(hKey, REGSTR_VAL_CLASSGUID, 0, REG_SZ, (const BYTE *)lpFullGuidString, (wcslen(lpFullGuidString) + 1) * sizeof(WCHAR)); @@ -7628,8 +7451,6 @@ SetupDiInstallDevice( rc = RegSetValueEx(hKey, REGSTR_VAL_DEVDESC, 0, REG_SZ, (const BYTE *)SelectedDriver->Info.Description, (wcslen(SelectedDriver->Info.Description) + 1) * sizeof(WCHAR)); if (rc == ERROR_SUCCESS) rc = RegSetValueEx(hKey, REGSTR_VAL_MFG, 0, REG_SZ, (const BYTE *)SelectedDriver->Info.MfgName, (wcslen(SelectedDriver->Info.MfgName) + 1) * sizeof(WCHAR)); - if (rc == ERROR_SUCCESS && AssociatedService && *AssociatedService) - rc = RegSetValueEx(hKey, REGSTR_VAL_SERVICE, 0, REG_SZ, (const BYTE *)AssociatedService, (wcslen(AssociatedService) + 1) * sizeof(WCHAR)); if (rc != ERROR_SUCCESS) { SetLastError(rc); @@ -7650,7 +7471,6 @@ cleanup: RegCloseKey(hKey); if (lpGuidString) RpcStringFreeW(&lpGuidString); - HeapFree(GetProcessHeap(), 0, (LPWSTR)AssociatedService); HeapFree(GetProcessHeap(), 0, lpFullGuidString); TRACE("Returning %d\n", ret); diff --git a/reactos/lib/setupapi/install.c b/reactos/lib/setupapi/install.c index 510a49214b4..5b329713df0 100644 --- a/reactos/lib/setupapi/install.c +++ b/reactos/lib/setupapi/install.c @@ -47,9 +47,28 @@ struct register_dll_info BOOL unregister; }; +/* info passed to callback functions dealing with Needs directives */ +struct needs_callback_info +{ + UINT type; + + HWND owner; + UINT flags; + HKEY key_root; + LPCWSTR src_root; + UINT copy_flags; + PVOID callback; + PVOID context; + HDEVINFO devinfo; + PSP_DEVINFO_DATA devinfo_data; + PVOID reserved1; + PVOID reserved2; +}; + typedef BOOL (*iterate_fields_func)( HINF hinf, PCWSTR field, void *arg ); /* Unicode constants */ +static const WCHAR AddService[] = {'A','d','d','S','e','r','v','i','c','e',0}; static const WCHAR CopyFiles[] = {'C','o','p','y','F','i','l','e','s',0}; static const WCHAR DelFiles[] = {'D','e','l','F','i','l','e','s',0}; static const WCHAR RenFiles[] = {'R','e','n','F','i','l','e','s',0}; @@ -784,73 +803,64 @@ BOOL WINAPI SetupInstallFromInfSectionA( HWND owner, HINF hinf, PCSTR section, U /*********************************************************************** - * SetupInstallFromInfSectionW (SETUPAPI.@) + * include_callback + * + * Called once for each Include entry in a given section. */ -BOOL WINAPI SetupInstallFromInfSectionW( HWND owner, HINF hinf, PCWSTR section, UINT flags, - HKEY key_root, PCWSTR src_root, UINT copy_flags, - PSP_FILE_CALLBACK_W callback, PVOID context, - HDEVINFO devinfo, PSP_DEVINFO_DATA devinfo_data ) +static BOOL include_callback( HINF hinf, PCWSTR field, void *arg ) { - INFCONTEXT include_context; + return SetupOpenAppendInfFileW( field, hinf, NULL ); +} - /* Parse 'Include' line */ - if (SetupFindFirstLineW( hinf, section, Include, &include_context )) - { - DWORD index = 1; - while (TRUE) - { - static WCHAR szBuffer[MAX_PATH]; - PWSTR pBuffer = NULL; - DWORD required; - BOOL ok; - - ok = SetupGetStringFieldW( &include_context, index, szBuffer, MAX_PATH, &required ); - if (!ok && GetLastError() == ERROR_INVALID_PARAMETER) - break; - else if (!ok && GetLastError() == ERROR_INSUFFICIENT_BUFFER) - { - pBuffer = MyMalloc(required); - ok = SetupGetStringFieldW( &include_context, index, pBuffer, required, &required ); - } - if (ok) - ok = SetupOpenAppendInfFileW( pBuffer ? pBuffer : szBuffer, hinf, NULL ); - MyFree(pBuffer); - if (!ok) return FALSE; - index++; - } - } +/*********************************************************************** + * needs_callback + * + * Called once for each Needs entry in a given section. + */ +static BOOL needs_callback( HINF hinf, PCWSTR field, void *arg ) +{ + struct needs_callback_info *info = arg; - /* Parse 'Needs' line */ - if (SetupFindFirstLineW( hinf, section, Needs, &include_context )) + switch (info->type) { - DWORD index = 1; - while (TRUE) - { - static WCHAR szBuffer[MAX_PATH]; - PWSTR pBuffer = NULL; - DWORD required; - BOOL ok; - - ok = SetupGetStringFieldW( &include_context, index, szBuffer, MAX_PATH, &required ); - if (!ok && GetLastError() == ERROR_INVALID_PARAMETER) - break; - else if (!ok && GetLastError() == ERROR_INSUFFICIENT_BUFFER) - { - pBuffer = MyMalloc(required); - ok = SetupGetStringFieldW( &include_context, index, pBuffer, required, &required ); - } - if (ok) - { - ok = SetupInstallFromInfSectionW( owner, hinf, pBuffer ? pBuffer : szBuffer, - flags, key_root, src_root, copy_flags, callback, context, devinfo, devinfo_data ); - } - - MyFree(pBuffer); - if (!ok) return FALSE; - index++; - } + case 0: + return SetupInstallFromInfSectionW(info->owner, hinf, field, info->flags, + info->key_root, info->src_root, info->copy_flags, info->callback, + info->context, info->devinfo, info->devinfo_data); + case 1: + return SetupInstallServicesFromInfSectionExW(hinf, field, info->flags, + info->devinfo, info->devinfo_data, info->reserved1, info->reserved2); + default: + ERR("Unknown info type %ld\n", info->type); + return FALSE; } +} + + +/*********************************************************************** + * SetupInstallFromInfSectionW (SETUPAPI.@) + */ +BOOL WINAPI SetupInstallFromInfSectionW( HWND owner, HINF hinf, PCWSTR section, UINT flags, + HKEY key_root, PCWSTR src_root, UINT copy_flags, + PSP_FILE_CALLBACK_W callback, PVOID context, + HDEVINFO devinfo, PSP_DEVINFO_DATA devinfo_data ) +{ + struct needs_callback_info needs_info; + + /* Parse 'Include' and 'Needs' directives */ + iterate_section_fields( hinf, section, Include, include_callback, NULL); + needs_info.type = 0; + needs_info.owner = owner; + needs_info.flags = flags; + needs_info.key_root = key_root; + needs_info.src_root = src_root; + needs_info.copy_flags = copy_flags; + needs_info.callback = callback; + needs_info.context = context; + needs_info.devinfo = devinfo; + needs_info.devinfo_data = devinfo_data; + iterate_section_fields( hinf, section, Needs, needs_callback, &needs_info); if (flags & SPINST_FILES) { @@ -1099,258 +1109,368 @@ static BOOL GetIntField( HINF hinf, PCWSTR section_name, PCWSTR key_name, INT *v } -/*********************************************************************** - * SetupInstallServicesFromInfSectionExW (SETUPAPI.@) - */ -BOOL WINAPI SetupInstallServicesFromInfSectionExW( HINF hinf, PCWSTR sectionname, DWORD flags, HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, PVOID reserved1, PVOID reserved2 ) +static BOOL GetStringField( PINFCONTEXT context, DWORD index, PWSTR *value) +{ + DWORD RequiredSize; + BOOL ret; + + ret = SetupGetStringFieldW( + context, + index, + NULL, 0, + &RequiredSize); + if (!ret) + return FALSE; + else if (RequiredSize == 0) + { + *value = NULL; + return TRUE; + } + + /* We got the needed size for the buffer */ + *value = MyMalloc(RequiredSize * sizeof(WCHAR)); + if (!*value) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return FALSE; + } + ret = SetupGetStringFieldW( + context, + index, + *value, RequiredSize, NULL); + if (!ret) + MyFree(*value); + + return ret; +} + + +static BOOL InstallOneService( + struct DeviceInfoSet *list, + IN HINF hInf, + IN LPCWSTR ServiceSection, + IN LPCWSTR ServiceName, + IN UINT ServiceFlags) { SC_HANDLE hSCManager = NULL; SC_HANDLE hService = NULL; LPDWORD GroupOrder = NULL; LPQUERY_SERVICE_CONFIG ServiceConfig = NULL; - struct DeviceInfoSet *list; BOOL ret = FALSE; - TRACE("%p, %s, 0x%lx, %p, %p, %p, %p\n", hinf, debugstr_w(sectionname), - flags, DeviceInfoSet, DeviceInfoData, reserved1, reserved2); + HKEY hGroupOrderListKey = INVALID_HANDLE_VALUE; + LPWSTR ServiceBinary = NULL; + LPWSTR LoadOrderGroup = NULL; + LPWSTR DisplayName = NULL; + LPWSTR Description = NULL; + LPWSTR Dependencies = NULL; + INT ServiceType, StartType, ErrorControl; + DWORD dwRegType; + DWORD tagId = (DWORD)-1; + BOOL useTag; + + if (!GetIntField(hInf, ServiceSection, L"ServiceType", &ServiceType)) + goto cleanup; + if (!GetIntField(hInf, ServiceSection, L"StartType", &StartType)) + goto cleanup; + if (!GetIntField(hInf, ServiceSection, L"ErrorControl", &ErrorControl)) + goto cleanup; + useTag = (ServiceType == SERVICE_BOOT_START || ServiceType == SERVICE_SYSTEM_START); - if (!DeviceInfoSet) - SetLastError(ERROR_INVALID_PARAMETER); - else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE) - SetLastError(ERROR_INVALID_HANDLE); - else if ((list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC) - SetLastError(ERROR_INVALID_HANDLE); - else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)) - SetLastError(ERROR_INVALID_USER_BUFFER); - else if (!reserved1) - { - /* FIXME: I don't know how to get the service name. ATM, just fail the call */ - /* Maybe find it in DeviceInfoSet/DeviceInfoData? */ - FIXME("Service name not specified!\n"); - SetLastError(ERROR_GEN_FAILURE); + hSCManager = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CREATE_SERVICE); + if (hSCManager == NULL) goto cleanup; - } - else - { - HKEY hGroupOrderListKey = INVALID_HANDLE_VALUE; - LPWSTR ServiceBinary = NULL; - LPWSTR LoadOrderGroup = NULL; - LPWSTR DisplayName = NULL; - LPWSTR Description = NULL; - LPWSTR Dependencies = NULL; - INT ServiceType, StartType, ErrorControl; - DWORD dwRegType; - DWORD tagId = (DWORD)-1; - BOOL useTag; - - if (!GetIntField(hinf, sectionname, L"ServiceType", &ServiceType)) - goto cleanup; - if (!GetIntField(hinf, sectionname, L"StartType", &StartType)) - goto cleanup; - if (!GetIntField(hinf, sectionname, L"ErrorControl", &ErrorControl)) - goto cleanup; - useTag = (ServiceType == SERVICE_BOOT_START || ServiceType == SERVICE_SYSTEM_START); - hSCManager = OpenSCManagerW(NULL, SERVICES_ACTIVE_DATABASE, SC_MANAGER_CREATE_SERVICE); - if (hSCManager == NULL) - goto cleanup; + if (!GetLineText(hInf, ServiceSection, L"ServiceBinary", &ServiceBinary)) + goto cleanup; - if (!GetLineText(hinf, sectionname, L"ServiceBinary", &ServiceBinary)) - goto cleanup; + /* Don't check return value, as these fields are optional and + * GetLineText initialize output parameter even on failure */ + GetLineText(hInf, ServiceSection, L"LoadOrderGroup", &LoadOrderGroup); + GetLineText(hInf, ServiceSection, L"DisplayName", &DisplayName); + GetLineText(hInf, ServiceSection, L"Description", &Description); + GetLineText(hInf, ServiceSection, L"Dependencies", &Dependencies); + + hService = OpenServiceW( + hSCManager, + ServiceName, + GENERIC_READ | GENERIC_WRITE); + if (hService == NULL && GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST) + goto cleanup; - /* Don't check return value, as these fields are optional and - * GetLineText initialize output parameter even on failure */ - GetLineText(hinf, sectionname, L"LoadOrderGroup", &LoadOrderGroup); - GetLineText(hinf, sectionname, L"DisplayName", &DisplayName); - GetLineText(hinf, sectionname, L"Description", &Description); - GetLineText(hinf, sectionname, L"Dependencies", &Dependencies); + if (hService && (ServiceFlags & SPSVCINST_DELETEEVENTLOGENTRY)) + { + ret = DeleteService(hService); + if (!ret && GetLastError() != ERROR_SERVICE_MARKED_FOR_DELETE) + goto cleanup; + } - hService = OpenServiceW( + if (hService == NULL) + { + /* Create new service */ + hService = CreateServiceW( hSCManager, - reserved1, - GENERIC_READ | GENERIC_WRITE); - if (hService == NULL && GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST) + ServiceName, + DisplayName, + 0, + ServiceType, + StartType, + ErrorControl, + ServiceBinary, + LoadOrderGroup, + useTag ? &tagId : NULL, + Dependencies, + NULL, NULL); + if (hService == NULL) goto cleanup; - - if (flags & (SPSVCINST_STOPSERVICE | SPSVCINST_DELETEEVENTLOGENTRY)) + } + else + { + DWORD bufferSize; + /* Read current configuration */ + if (!QueryServiceConfigW(hService, NULL, 0, &bufferSize)) { - if (hService == NULL) - { - SetLastError(ERROR_SERVICE_DOES_NOT_EXIST); + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) goto cleanup; - } - if (flags & SPSVCINST_STOPSERVICE) - { - SERVICE_STATUS ServiceStatus; - ret = ControlService(hService, SERVICE_CONTROL_STOP, &ServiceStatus); - if (!ret && GetLastError() != ERROR_SERVICE_NOT_ACTIVE) - goto cleanup; - if (ServiceStatus.dwCurrentState != SERVICE_STOP_PENDING && ServiceStatus.dwCurrentState != SERVICE_STOPPED) - { - SetLastError(ERROR_INSTALL_SERVICE_FAILURE); - goto cleanup; - } - } - if (flags & SPSVCINST_DELETEEVENTLOGENTRY) + ServiceConfig = MyMalloc(bufferSize); + if (!ServiceConfig) { - ret = DeleteService(hService); - if (!ret) - goto cleanup; + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + goto cleanup; } - ret = FALSE; + if (!QueryServiceConfigW(hService, ServiceConfig, bufferSize, &bufferSize)) + goto cleanup; } + tagId = ServiceConfig->dwTagId; + + /* Update configuration */ + ret = ChangeServiceConfigW( + hService, + ServiceType, + (ServiceFlags & SPSVCINST_NOCLOBBER_STARTTYPE) ? SERVICE_NO_CHANGE : StartType, + (ServiceFlags & SPSVCINST_NOCLOBBER_ERRORCONTROL) ? SERVICE_NO_CHANGE : ErrorControl, + ServiceBinary, + (ServiceFlags & SPSVCINST_NOCLOBBER_LOADORDERGROUP && ServiceConfig->lpLoadOrderGroup) ? NULL : LoadOrderGroup, + useTag ? &tagId : NULL, + (ServiceFlags & SPSVCINST_NOCLOBBER_DEPENDENCIES && ServiceConfig->lpDependencies) ? NULL : Dependencies, + NULL, NULL, + (ServiceFlags & SPSVCINST_NOCLOBBER_DISPLAYNAME && ServiceConfig->lpDisplayName) ? NULL : DisplayName); + if (!ret) + goto cleanup; + } - if (hService == NULL) + /* FIXME: use Description and SPSVCINST_NOCLOBBER_DESCRIPTION */ + + if (useTag) + { + /* Add the tag to SYSTEM\CurrentControlSet\Control\GroupOrderList key */ + LONG rc; + LPCWSTR lpLoadOrderGroup; + DWORD bufferSize; + + lpLoadOrderGroup = LoadOrderGroup; + if ((ServiceFlags & SPSVCINST_NOCLOBBER_LOADORDERGROUP) && ServiceConfig && ServiceConfig->lpLoadOrderGroup) + lpLoadOrderGroup = ServiceConfig->lpLoadOrderGroup; + + rc = RegOpenKey( + list ? list->HKLM : HKEY_LOCAL_MACHINE, + L"SYSTEM\\CurrentControlSet\\Control\\GroupOrderList", + &hGroupOrderListKey); + if (rc != ERROR_SUCCESS) { - /* Create new service */ - hService = CreateServiceW( - hSCManager, - reserved1, - DisplayName, - 0, - ServiceType, - StartType, - ErrorControl, - ServiceBinary, - LoadOrderGroup, - useTag ? &tagId : NULL, - Dependencies, - NULL, NULL); - if (hService == NULL) - goto cleanup; + SetLastError(rc); + goto cleanup; } - else + rc = RegQueryValueExW(hGroupOrderListKey, lpLoadOrderGroup, NULL, &dwRegType, NULL, &bufferSize); + if (rc == ERROR_FILE_NOT_FOUND) + bufferSize = sizeof(DWORD); + else if (rc != ERROR_SUCCESS) { - DWORD bufferSize; - /* Read current configuration */ - if (!QueryServiceConfigW(hService, NULL, 0, &bufferSize)) - { - if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) - goto cleanup; - ServiceConfig = HeapAlloc(GetProcessHeap(), 0, bufferSize); - if (!ServiceConfig) - { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); - goto cleanup; - } - if (!QueryServiceConfigW(hService, ServiceConfig, bufferSize, &bufferSize)) - goto cleanup; - } - tagId = ServiceConfig->dwTagId; - - /* Update configuration */ - ret = ChangeServiceConfigW( - hService, - ServiceType, - (flags & SPSVCINST_NOCLOBBER_STARTTYPE) ? SERVICE_NO_CHANGE : StartType, - (flags & SPSVCINST_NOCLOBBER_ERRORCONTROL) ? SERVICE_NO_CHANGE : ErrorControl, - ServiceBinary, - (flags & SPSVCINST_NOCLOBBER_LOADORDERGROUP && ServiceConfig->lpLoadOrderGroup) ? NULL : LoadOrderGroup, - useTag ? &tagId : NULL, - (flags & SPSVCINST_NOCLOBBER_DEPENDENCIES && ServiceConfig->lpDependencies) ? NULL : Dependencies, - NULL, NULL, - (flags & SPSVCINST_NOCLOBBER_DISPLAYNAME && ServiceConfig->lpDisplayName) ? NULL : DisplayName); - if (!ret) - goto cleanup; + SetLastError(rc); + goto cleanup; } - - /* FIXME: use Description and SPSVCINST_NOCLOBBER_DESCRIPTION */ - - if (useTag) + else if (dwRegType != REG_BINARY || bufferSize == 0 || bufferSize % sizeof(DWORD) != 0) { - /* Add the tag to SYSTEM\CurrentControlSet\Control\GroupOrderList key */ - LONG rc; - LPCWSTR lpLoadOrderGroup; - DWORD bufferSize; - - lpLoadOrderGroup = LoadOrderGroup; - if ((flags & SPSVCINST_NOCLOBBER_LOADORDERGROUP) && ServiceConfig && ServiceConfig->lpLoadOrderGroup) - lpLoadOrderGroup = ServiceConfig->lpLoadOrderGroup; - - rc = RegOpenKey(list->HKLM, L"SYSTEM\\CurrentControlSet\\Control\\GroupOrderList", &hGroupOrderListKey); + SetLastError(ERROR_GEN_FAILURE); + goto cleanup; + } + /* Allocate buffer to store existing data + the new tag */ + GroupOrder = MyMalloc(bufferSize + sizeof(DWORD)); + if (!GroupOrder) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + goto cleanup; + } + if (rc == ERROR_SUCCESS) + { + /* Read existing data */ + rc = RegQueryValueExW( + hGroupOrderListKey, + lpLoadOrderGroup, + NULL, + NULL, + (BYTE*)GroupOrder, + &bufferSize); if (rc != ERROR_SUCCESS) { SetLastError(rc); goto cleanup; } - rc = RegQueryValueExW(hGroupOrderListKey, lpLoadOrderGroup, NULL, &dwRegType, NULL, &bufferSize); - if (rc == ERROR_FILE_NOT_FOUND) - bufferSize = sizeof(DWORD); - else if (rc != ERROR_SUCCESS) - { - SetLastError(rc); - goto cleanup; - } - else if (dwRegType != REG_BINARY || bufferSize == 0 || bufferSize % sizeof(DWORD) != 0) - { - SetLastError(ERROR_GEN_FAILURE); + if (ServiceFlags & SPSVCINST_TAGTOFRONT) + memmove(&GroupOrder[2], &GroupOrder[1], bufferSize - sizeof(DWORD)); + } + else + { + GroupOrder[0] = 0; + } + GroupOrder[0]++; + if (ServiceFlags & SPSVCINST_TAGTOFRONT) + GroupOrder[1] = tagId; + else + GroupOrder[bufferSize / sizeof(DWORD)] = tagId; + + rc = RegSetValueExW( + hGroupOrderListKey, + lpLoadOrderGroup, + 0, + REG_BINARY, + (BYTE*)GroupOrder, + bufferSize + sizeof(DWORD)); + if (rc != ERROR_SUCCESS) + { + SetLastError(rc); + goto cleanup; + } + } + + ret = TRUE; + +cleanup: + if (hSCManager != NULL) + CloseServiceHandle(hSCManager); + if (hService != NULL) + CloseServiceHandle(hService); + if (hGroupOrderListKey != INVALID_HANDLE_VALUE) + RegCloseKey(hGroupOrderListKey); + MyFree(ServiceConfig); + MyFree(ServiceBinary); + MyFree(LoadOrderGroup); + MyFree(DisplayName); + MyFree(Description); + MyFree(Dependencies); + MyFree(GroupOrder); + + TRACE("Returning %d\n", ret); + return ret; +} + + +/*********************************************************************** + * SetupInstallServicesFromInfSectionExW (SETUPAPI.@) + */ +BOOL WINAPI SetupInstallServicesFromInfSectionExW( HINF hinf, PCWSTR sectionname, DWORD flags, HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData, PVOID reserved1, PVOID reserved2 ) +{ + struct DeviceInfoSet *list = NULL; + BOOL ret = FALSE; + + TRACE("%p, %s, 0x%lx, %p, %p, %p, %p\n", hinf, debugstr_w(sectionname), + flags, DeviceInfoSet, DeviceInfoData, reserved1, reserved2); + + if (!sectionname) + SetLastError(ERROR_INVALID_PARAMETER); + else if (flags & ~(SPSVCINST_TAGTOFRONT | SPSVCINST_DELETEEVENTLOGENTRY | SPSVCINST_NOCLOBBER_DISPLAYNAME | SPSVCINST_NOCLOBBER_STARTTYPE | SPSVCINST_NOCLOBBER_ERRORCONTROL | SPSVCINST_NOCLOBBER_LOADORDERGROUP | SPSVCINST_NOCLOBBER_DEPENDENCIES | SPSVCINST_STOPSERVICE)) + { + TRACE("Unknown flags: 0x%08lx\n", flags & ~(SPSVCINST_TAGTOFRONT | SPSVCINST_DELETEEVENTLOGENTRY | SPSVCINST_NOCLOBBER_DISPLAYNAME | SPSVCINST_NOCLOBBER_STARTTYPE | SPSVCINST_NOCLOBBER_ERRORCONTROL | SPSVCINST_NOCLOBBER_LOADORDERGROUP | SPSVCINST_NOCLOBBER_DEPENDENCIES | SPSVCINST_STOPSERVICE)); + SetLastError(ERROR_INVALID_FLAGS); + } + else if (DeviceInfoSet == (HDEVINFO)INVALID_HANDLE_VALUE) + SetLastError(ERROR_INVALID_HANDLE); + else if (DeviceInfoSet && (list = (struct DeviceInfoSet *)DeviceInfoSet)->magic != SETUP_DEV_INFO_SET_MAGIC) + SetLastError(ERROR_INVALID_HANDLE); + else if (DeviceInfoData && DeviceInfoData->cbSize != sizeof(SP_DEVINFO_DATA)) + SetLastError(ERROR_INVALID_USER_BUFFER); + else if (reserved1 != NULL || reserved2 != NULL) + SetLastError(ERROR_INVALID_PARAMETER); + else + { + struct needs_callback_info needs_info; + LPWSTR ServiceName = NULL; + LPWSTR ServiceSection = NULL; + UINT ServiceFlags; + INFCONTEXT ContextService; + BOOL bNeedReboot = FALSE; + + /* Parse 'Include' and 'Needs' directives */ + iterate_section_fields( hinf, sectionname, Include, include_callback, NULL); + needs_info.type = 1; + needs_info.flags = flags; + needs_info.devinfo = DeviceInfoSet; + needs_info.devinfo_data = DeviceInfoData; + needs_info.reserved1 = reserved1; + needs_info.reserved2 = reserved2; + iterate_section_fields( hinf, sectionname, Needs, needs_callback, &needs_info); + + if (flags & SPSVCINST_STOPSERVICE) + { + FIXME("Stopping the device not implemented\n"); + /* This may lead to require a reboot */ + /* bNeedReboot = TRUE; */ +#if 0 + SERVICE_STATUS ServiceStatus; + ret = ControlService(hService, SERVICE_CONTROL_STOP, &ServiceStatus); + if (!ret && GetLastError() != ERROR_SERVICE_NOT_ACTIVE) goto cleanup; - } - /* Allocate buffer to store existing data + the new tag */ - GroupOrder = HeapAlloc(GetProcessHeap(), 0, bufferSize + sizeof(DWORD)); - if (!GroupOrder) + if (ServiceStatus.dwCurrentState != SERVICE_STOP_PENDING && ServiceStatus.dwCurrentState != SERVICE_STOPPED) { - SetLastError(ERROR_NOT_ENOUGH_MEMORY); + SetLastError(ERROR_INSTALL_SERVICE_FAILURE); goto cleanup; } - if (rc == ERROR_SUCCESS) - { - /* Read existing data */ - rc = RegQueryValueExW( - hGroupOrderListKey, - lpLoadOrderGroup, - NULL, - NULL, - (BYTE*)GroupOrder, - &bufferSize); - if (rc != ERROR_SUCCESS) - { - SetLastError(rc); - goto cleanup; - } - if (flags & SPSVCINST_TAGTOFRONT) - memmove(&GroupOrder[2], &GroupOrder[1], bufferSize - sizeof(DWORD)); - } - else +#endif + flags &= ~SPSVCINST_STOPSERVICE; + } + + ret = SetupFindFirstLineW(hinf, sectionname, AddService, &ContextService); + while (ret) + { + if (!GetStringField(&ContextService, 1, &ServiceName)) + goto nextservice; + + ret = SetupGetIntField( + &ContextService, + 2, /* Field index */ + &ServiceFlags); + if (!ret) { - GroupOrder[0] = 0; + /* The field may be empty. Ignore the error */ + ServiceFlags = 0; } - GroupOrder[0]++; - if (flags & SPSVCINST_TAGTOFRONT) - GroupOrder[1] = tagId; - else - GroupOrder[bufferSize / sizeof(DWORD)] = tagId; - rc = RegSetValueExW( - hGroupOrderListKey, - lpLoadOrderGroup, - 0, - REG_BINARY, - (BYTE*)GroupOrder, - bufferSize + sizeof(DWORD)); - if (rc != ERROR_SUCCESS) + if (!GetStringField(&ContextService, 3, &ServiceSection)) + goto nextservice; + + ret = InstallOneService(list, hinf, ServiceSection, ServiceName, (ServiceFlags & ~SPSVCINST_ASSOCSERVICE) | flags); + if (!ret) + goto nextservice; + + if (ServiceFlags & SPSVCINST_ASSOCSERVICE) { - SetLastError(rc); - goto cleanup; + ret = SetupDiSetDeviceRegistryPropertyW(DeviceInfoSet, DeviceInfoData, SPDRP_SERVICE, (LPBYTE)ServiceName, (strlenW(ServiceName) + 1) * sizeof(WCHAR)); + if (!ret) + goto nextservice; } + +nextservice: + HeapFree(GetProcessHeap(), 0, ServiceName); + HeapFree(GetProcessHeap(), 0, ServiceSection); + ServiceName = ServiceSection = NULL; + ret = SetupFindNextMatchLineW(&ContextService, AddService, &ContextService); } + if (bNeedReboot) + SetLastError(ERROR_SUCCESS_REBOOT_REQUIRED); + else + SetLastError(ERROR_SUCCESS); ret = TRUE; - -cleanup: - if (hSCManager != NULL) - CloseServiceHandle(hSCManager); - if (hService != NULL) - CloseServiceHandle(hService); - if (hGroupOrderListKey != INVALID_HANDLE_VALUE) - RegCloseKey(hGroupOrderListKey); - HeapFree(GetProcessHeap(), 0, ServiceConfig); - HeapFree(GetProcessHeap(), 0, ServiceBinary); - HeapFree(GetProcessHeap(), 0, LoadOrderGroup); - HeapFree(GetProcessHeap(), 0, DisplayName); - HeapFree(GetProcessHeap(), 0, Description); - HeapFree(GetProcessHeap(), 0, Dependencies); - HeapFree(GetProcessHeap(), 0, GroupOrder); } TRACE("Returning %d\n", ret);