diff --git a/dlls/advapi32/service.c b/dlls/advapi32/service.c index cf58e2c44d6..dd056b2281a 100644 --- a/dlls/advapi32/service.c +++ b/dlls/advapi32/service.c @@ -292,6 +292,7 @@ static DWORD map_exception_code(DWORD exception_code) switch (exception_code) { case RPC_X_NULL_REF_POINTER: + return ERROR_INVALID_ADDRESS; case RPC_X_ENUM_VALUE_OUT_OF_RANGE: case RPC_X_BYTE_COUNT_TOO_SMALL: return ERROR_INVALID_PARAMETER; @@ -1654,9 +1655,7 @@ cleanup: BOOL WINAPI QueryServiceConfig2W(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffer, DWORD size, LPDWORD needed) { - DWORD sz, type; - HKEY hKey; - LONG r; + DWORD err; struct sc_service *hsvc; if(dwLevel != SERVICE_CONFIG_DESCRIPTION) { @@ -1670,7 +1669,8 @@ BOOL WINAPI QueryServiceConfig2W(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffe SetLastError(ERROR_INVALID_LEVEL); return FALSE; } - if(!needed || (!buffer && size)) { + + if(!buffer && size) { SetLastError(ERROR_INVALID_ADDRESS); return FALSE; } @@ -1683,36 +1683,36 @@ BOOL WINAPI QueryServiceConfig2W(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffe SetLastError(ERROR_INVALID_HANDLE); return FALSE; } - hKey = hsvc->hkey; - switch(dwLevel) { - case SERVICE_CONFIG_DESCRIPTION: { - static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0}; - LPSERVICE_DESCRIPTIONW config = (LPSERVICE_DESCRIPTIONW) buffer; - LPBYTE strbuf = NULL; - *needed = sizeof (SERVICE_DESCRIPTIONW); - sz = size - *needed; - if(config && (*needed <= size)) - strbuf = (LPBYTE) (config + 1); - r = RegQueryValueExW( hKey, szDescription, 0, &type, strbuf, &sz ); - if((r == ERROR_SUCCESS) && ( type != REG_SZ)) { - FIXME("SERVICE_CONFIG_DESCRIPTION: don't know how to handle type %d\n", type); - return FALSE; - } - *needed += sz; - if(config) { - if(r == ERROR_SUCCESS) - config->lpDescription = (LPWSTR) (config + 1); - else - config->lpDescription = NULL; - } - } - break; + __TRY + { + err = svcctl_QueryServiceConfig2W(hsvc->hdr.server_handle, dwLevel, buffer, size, needed); } - if(*needed > size) - SetLastError(ERROR_INSUFFICIENT_BUFFER); + __EXCEPT(rpc_filter) + { + err = map_exception_code(GetExceptionCode()); + } + __ENDTRY - return (*needed <= size); + if (err != ERROR_SUCCESS) + { + SetLastError( err ); + return FALSE; + } + + switch (dwLevel) + { + case SERVICE_CONFIG_DESCRIPTION: + if (buffer) + { + SERVICE_DESCRIPTIONW *descr = (SERVICE_DESCRIPTIONW *)buffer; + if (descr->lpDescription) /* make it an absolute pointer */ + descr->lpDescription = (WCHAR *)(buffer + (ULONG_PTR)descr->lpDescription); + break; + } + } + + return TRUE; } /****************************************************************************** diff --git a/include/wine/svcctl.idl b/include/wine/svcctl.idl index 66abd30f954..d04da08bfcb 100644 --- a/include/wine/svcctl.idl +++ b/include/wine/svcctl.idl @@ -296,8 +296,14 @@ typedef [switch_type(DWORD)] union /* Not compatible with Windows function 0x26 */ DWORD svcctl_QueryServiceConfig2A(/* FIXME */); - /* Not compatible with Windows function 0x27 */ - DWORD svcctl_QueryServiceConfig2W(/* FIXME */); + /* Untested with Windows function 0x27 */ + DWORD svcctl_QueryServiceConfig2W( + [in] SC_RPC_HANDLE hService, + [in] DWORD InfoLevel, + [out,size_is(cbBufSize)] BYTE lpBuffer[], + [in] DWORD cbBufSize, + [out] LPDWORD pcbBytesNeeded + ); /* Untested with Windows function 0x28 */ DWORD svcctl_QueryServiceStatusEx( diff --git a/programs/services/rpc.c b/programs/services/rpc.c index 830ed9ccc65..b6014aab6fa 100644 --- a/programs/services/rpc.c +++ b/programs/services/rpc.c @@ -646,6 +646,48 @@ DWORD svcctl_ChangeServiceConfig2W( SC_RPC_HANDLE hService, DWORD level, SERVICE return err; } +DWORD svcctl_QueryServiceConfig2W( SC_RPC_HANDLE hService, DWORD level, + BYTE *buffer, DWORD size, LPDWORD needed ) +{ + struct sc_service_handle *service; + DWORD err; + + if ((err = validate_service_handle(hService, SERVICE_QUERY_STATUS, &service)) != 0) + return err; + + switch (level) + { + case SERVICE_CONFIG_DESCRIPTION: + { + SERVICE_DESCRIPTIONW *descr = (SERVICE_DESCRIPTIONW *)buffer; + + service_lock_shared(service->service_entry); + *needed = sizeof(*descr); + if (service->service_entry->description) + *needed += (strlenW(service->service_entry->description) + 1) * sizeof(WCHAR); + if (size >= *needed) + { + if (service->service_entry->description) + { + /* store a buffer offset instead of a pointer */ + descr->lpDescription = (WCHAR *)((BYTE *)(descr + 1) - buffer); + strcpyW( (WCHAR *)(descr + 1), service->service_entry->description ); + } + else descr->lpDescription = NULL; + } + else err = ERROR_INSUFFICIENT_BUFFER; + service_unlock(service->service_entry); + } + break; + + default: + WINE_FIXME("level %u not implemented\n", level); + err = ERROR_INVALID_LEVEL; + break; + } + return err; +} + DWORD svcctl_QueryServiceStatusEx( SC_RPC_HANDLE hService, SC_STATUS_TYPE InfoLevel, @@ -1141,13 +1183,6 @@ DWORD svcctl_QueryServiceConfig2A( return ERROR_CALL_NOT_IMPLEMENTED; } -DWORD svcctl_QueryServiceConfig2W( - void) -{ - WINE_FIXME("\n"); - return ERROR_CALL_NOT_IMPLEMENTED; -} - DWORD RPC_Init(void) {