return TRUE;
}
+/******************************************************************************
+ * QueryServiceConfig2A [ADVAPI32.@]
+ *
+ * Note
+ * observed unter win2k:
+ * The functions QueryServiceConfig2A and QueryServiceConfig2W return the same
+ * required buffer size (in byte) at least for dwLevel SERVICE_CONFIG_DESCRIPTION
+ */
+BOOL WINAPI QueryServiceConfig2A(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffer,
+ DWORD size, LPDWORD needed)
+{
+ BOOL ret;
+ LPBYTE bufferW = NULL;
+
+ if(buffer && size)
+ bufferW = HeapAlloc( GetProcessHeap(), 0, size);
+
+ ret = QueryServiceConfig2W(hService, dwLevel, bufferW, size, needed);
+ if(!ret) goto cleanup;
+
+ switch(dwLevel) {
+ case SERVICE_CONFIG_DESCRIPTION:
+ { LPSERVICE_DESCRIPTIONA configA = (LPSERVICE_DESCRIPTIONA) buffer;
+ LPSERVICE_DESCRIPTIONW configW = (LPSERVICE_DESCRIPTIONW) bufferW;
+ if (configW->lpDescription) {
+ DWORD sz;
+ configA->lpDescription = (LPSTR)(configA + 1);
+ sz = WideCharToMultiByte( CP_ACP, 0, configW->lpDescription, -1,
+ configA->lpDescription, size - sizeof(SERVICE_DESCRIPTIONA), NULL, NULL );
+ if (!sz) {
+ FIXME("WideCharToMultiByte failed for configW->lpDescription\n");
+ ret = FALSE;
+ configA->lpDescription = NULL;
+ }
+ }
+ else configA->lpDescription = NULL;
+ }
+ break;
+ default:
+ FIXME("conversation W->A not implemented for level %d\n", dwLevel);
+ ret = FALSE;
+ }
+
+cleanup:
+ HeapFree( GetProcessHeap(), 0, bufferW);
+ return ret;
+}
+
+/******************************************************************************
+ * QueryServiceConfig2W [ADVAPI32.@]
+ */
+BOOL WINAPI QueryServiceConfig2W(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffer,
+ DWORD size, LPDWORD needed)
+{
+ DWORD sz, type;
+ HKEY hKey;
+ LONG r;
+ struct sc_service *hsvc;
+
+ if(dwLevel != SERVICE_CONFIG_DESCRIPTION) {
+ if((dwLevel == SERVICE_CONFIG_DELAYED_AUTO_START_INFO) ||
+ (dwLevel == SERVICE_CONFIG_FAILURE_ACTIONS) ||
+ (dwLevel == SERVICE_CONFIG_FAILURE_ACTIONS_FLAG) ||
+ (dwLevel == SERVICE_CONFIG_PRESHUTDOWN_INFO) ||
+ (dwLevel == SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO) ||
+ (dwLevel == SERVICE_CONFIG_SERVICE_SID_INFO))
+ FIXME("Level %d not implemented\n", dwLevel);
+ SetLastError(ERROR_INVALID_LEVEL);
+ return FALSE;
+ }
+ if(!needed || (!buffer && size)) {
+ SetLastError(ERROR_INVALID_ADDRESS);
+ return FALSE;
+ }
+
+ TRACE("%p 0x%d %p 0x%d %p\n", hService, dwLevel, buffer, size, needed);
+
+ hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
+ if (!hsvc)
+ {
+ 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;
+ }
+ if(*needed > size)
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+
+ return (*needed <= size);
+}
+
/******************************************************************************
* EnumServicesStatusA [ADVAPI32.@]
*/
ok(!ret, "expected QueryServiceConfig2A to fail\n");
ok(ERROR_INVALID_ADDRESS == GetLastError(), "expected error ERROR_INVALID_ADDRESS, got %d\n", GetLastError());
+ needed = 0;
+ SetLastError(0xdeadbeef);
+ ret = pQueryServiceConfig2A(svc_handle, SERVICE_CONFIG_DESCRIPTION,buffer,sizeof(SERVICE_DESCRIPTIONA)-1,&needed);
+ ok(!ret, "expected QueryServiceConfig2A to fail\n");
+ ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(), "expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
+ ok(needed == sizeof(SERVICE_DESCRIPTIONA), "got %d\n", needed);
+
needed = 0;
pConfig->lpDescription = (LPSTR)0xdeadbeef;
ret = pQueryServiceConfig2A(svc_handle, SERVICE_CONFIG_DESCRIPTION,buffer,sizeof(SERVICE_DESCRIPTIONA),&needed);
} QUERY_SERVICE_CONFIGW, *LPQUERY_SERVICE_CONFIGW;
/* defines and structures for ChangeServiceConfig2 */
-#define SERVICE_CONFIG_DESCRIPTION 1
-#define SERVICE_CONFIG_FAILURE_ACTIONS 2
+#define SERVICE_CONFIG_DESCRIPTION 1
+#define SERVICE_CONFIG_FAILURE_ACTIONS 2
+#define SERVICE_CONFIG_DELAYED_AUTO_START_INFO 3
+#define SERVICE_CONFIG_FAILURE_ACTIONS_FLAG 4
+#define SERVICE_CONFIG_SERVICE_SID_INFO 5
+#define SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO 6
+#define SERVICE_CONFIG_PRESHUTDOWN_INFO 7
+
typedef struct _SERVICE_DESCRIPTIONA {
LPSTR lpDescription;
WINADVAPI BOOL WINAPI QueryServiceConfigA(SC_HANDLE,LPQUERY_SERVICE_CONFIGA,DWORD,LPDWORD);
WINADVAPI BOOL WINAPI QueryServiceConfigW(SC_HANDLE,LPQUERY_SERVICE_CONFIGW,DWORD,LPDWORD);
#define QueryServiceConfig WINELIB_NAME_AW(QueryServiceConfig)
+WINADVAPI BOOL WINAPI QueryServiceConfig2A(SC_HANDLE,DWORD,LPBYTE,DWORD,LPDWORD);
+WINADVAPI BOOL WINAPI QueryServiceConfig2W(SC_HANDLE,DWORD,LPBYTE,DWORD,LPDWORD);
+#define QueryServiceConfig2 WINELIB_NAME_AW(QueryServiceConfig2)
WINADVAPI BOOL WINAPI QueryServiceLockStatusA(SC_HANDLE,LPQUERY_SERVICE_LOCK_STATUSA,DWORD,LPDWORD);
WINADVAPI BOOL WINAPI QueryServiceLockStatusW(SC_HANDLE,LPQUERY_SERVICE_LOCK_STATUSW,DWORD,LPDWORD);
#define QueryServiceLockStatus WINELIB_NAME_AW(QueryServiceLockStatus)