diff --git a/rostests/winetests/advapi32/cred.c b/rostests/winetests/advapi32/cred.c index 6d7b758c195..1bb2545e47b 100644 --- a/rostests/winetests/advapi32/cred.c +++ b/rostests/winetests/advapi32/cred.c @@ -97,8 +97,12 @@ static void test_CredWriteA(void) SetLastError(0xdeadbeef); ret = pCredWriteA(&new_cred, 0); - ok(!ret && ( GetLastError() == ERROR_BAD_USERNAME || GetLastError() == ERROR_NO_SUCH_LOGON_SESSION /* Vista */ ), - "CredWrite with username without domain should return ERROR_BAD_USERNAME or ERROR_NO_SUCH_LOGON_SESSION not %d\n", GetLastError()); + ok(!ret, "CredWrite with username without domain should have failed\n"); + ok(GetLastError() == ERROR_BAD_USERNAME || + GetLastError() == ERROR_NO_SUCH_LOGON_SESSION || /* Vista */ + broken(GetLastError() == ERROR_IO_PENDING), + "CredWrite with username without domain should return ERROR_BAD_USERNAME" + "or ERROR_NO_SUCH_LOGON_SESSION not %d\n", GetLastError()); new_cred.UserName = NULL; SetLastError(0xdeadbeef); @@ -175,10 +179,12 @@ static void test_generic(void) { if (!strcmp(creds[i]->TargetName, TEST_TARGET_NAME)) { - ok(creds[i]->Type == CRED_TYPE_GENERIC, "expected creds[%d]->Type CRED_TYPE_GENERIC but got %d\n", i, creds[i]->Type); + ok(creds[i]->Type == CRED_TYPE_GENERIC || + creds[i]->Type == CRED_TYPE_DOMAIN_PASSWORD, /* Vista */ + "expected creds[%d]->Type CRED_TYPE_GENERIC or CRED_TYPE_DOMAIN_PASSWORD but got %d\n", i, creds[i]->Type); ok(!creds[i]->Flags, "expected creds[%d]->Flags 0 but got 0x%x\n", i, creds[i]->Flags); ok(!strcmp(creds[i]->Comment, "Comment"), "expected creds[%d]->Comment \"Comment\" but got \"%s\"\n", i, creds[i]->Comment); - check_blob(__LINE__, CRED_TYPE_GENERIC, creds[i]); + check_blob(__LINE__, creds[i]->Type, creds[i]); ok(creds[i]->Persist, "expected creds[%d]->Persist CRED_PERSIST_ENTERPRISE but got %d\n", i, creds[i]->Persist); ok(!strcmp(creds[i]->UserName, "winetest"), "expected creds[%d]->UserName \"winetest\" but got \"%s\"\n", i, creds[i]->UserName); found = TRUE; @@ -216,6 +222,12 @@ static void test_domain_password(DWORD cred_type) new_cred.TargetAlias = NULL; new_cred.UserName = (char *)"test\\winetest"; ret = pCredWriteA(&new_cred, 0); + if (!ret && GetLastError() == ERROR_NO_SUCH_LOGON_SESSION) + { + skip("CRED_TYPE_DOMAIN_PASSWORD credentials are not supported " + "or are disabled. Skipping\n"); + return; + } ok(ret, "CredWriteA failed with error %d\n", GetLastError()); ret = pCredEnumerateA(NULL, 0, &count, &creds); diff --git a/rostests/winetests/advapi32/crypt.c b/rostests/winetests/advapi32/crypt.c index 8ad2b6b258c..1d2cfa2d971 100644 --- a/rostests/winetests/advapi32/crypt.c +++ b/rostests/winetests/advapi32/crypt.c @@ -903,7 +903,7 @@ static void test_machine_guid(void) /* Create and release a provider */ ret = pCryptAcquireContextA(&hCryptProv, szKeySet, NULL, PROV_RSA_FULL, 0); ok(ret, "CryptAcquireContextA failed: %08x\n", GetLastError()); - CryptReleaseContext(hCryptProv, 0); + pCryptReleaseContext(hCryptProv, 0); if (restoreGuid) RegSetValueExA(key, "MachineGuid", 0, REG_SZ, (const BYTE *)originalGuid, diff --git a/rostests/winetests/advapi32/crypt_lmhash.c b/rostests/winetests/advapi32/crypt_lmhash.c index b90e02ccd15..63ab2c0da4d 100644 --- a/rostests/winetests/advapi32/crypt_lmhash.c +++ b/rostests/winetests/advapi32/crypt_lmhash.c @@ -348,18 +348,24 @@ static void test_SystemFunction005(void) out.Length = 0; out.MaximumLength = 0; r = pSystemFunction005(&out, &key, &res); - ok(r == STATUS_SUCCESS, "function failed\n"); + ok(r == STATUS_SUCCESS || + r == STATUS_INVALID_PARAMETER_1, /* Vista */ + "Expected STATUS_SUCCESS or STATUS_INVALID_PARAMETER_1, got %08x\n", r); ok(res.Length == in.Length, "Length wrong\n"); ok(!memcmp(res.Buffer, in.Buffer, in.Length), "data wrong\n"); res.MaximumLength = 0; r = pSystemFunction005(&out, &key, &res); - ok(r == STATUS_BUFFER_TOO_SMALL, "function failed\n"); + ok(r == STATUS_BUFFER_TOO_SMALL || + r == STATUS_INVALID_PARAMETER_1, /* Vista */ + "Expected STATUS_BUFFER_TOO_SMALL or STATUS_INVALID_PARAMETER_1, got %08x\n", r); key.Length = 1; r = pSystemFunction005(&out, &key, &res); - ok(r == STATUS_UNKNOWN_REVISION, "function failed\n"); + ok(r == STATUS_UNKNOWN_REVISION || + r == STATUS_INVALID_PARAMETER_1, /* Vista */ + "Expected STATUS_UNKNOWN_REVISION or STATUS_INVALID_PARAMETER_1, got %08x\n", r); key.Length = 0; r = pSystemFunction005(&out, &key, &res); diff --git a/rostests/winetests/advapi32/lsa.c b/rostests/winetests/advapi32/lsa.c index 4035416cdc5..90fbe1031b1 100644 --- a/rostests/winetests/advapi32/lsa.c +++ b/rostests/winetests/advapi32/lsa.c @@ -30,10 +30,11 @@ #include "sddl.h" #include "winnls.h" #include "objbase.h" -#define INITGUID -#include "guiddef.h" +#include "initguid.h" #include "wine/test.h" +DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0); + static HMODULE hadvapi32; static NTSTATUS (WINAPI *pLsaClose)(LSA_HANDLE); static NTSTATUS (WINAPI *pLsaFreeMemory)(PVOID); @@ -95,7 +96,6 @@ static void test_lsa(void) status = pLsaQueryInformationPolicy(handle, PolicyPrimaryDomainInformation, (PVOID*)&primary_domain_info); ok(status == STATUS_SUCCESS, "LsaQueryInformationPolicy(PolicyPrimaryDomainInformation) failed, returned 0x%08x\n", status); if (status == STATUS_SUCCESS) { - ok(primary_domain_info->Sid==0,"Sid should be NULL on the local computer\n"); if (primary_domain_info->Sid) { LPSTR strsid; if (pConvertSidToStringSidA(primary_domain_info->Sid, &strsid)) @@ -115,6 +115,8 @@ static void test_lsa(void) else trace("invalid sid\n"); } + else + trace("Running on a standalone system.\n"); pLsaFreeMemory((LPVOID)primary_domain_info); } @@ -129,8 +131,6 @@ static void test_lsa(void) ok(status == STATUS_SUCCESS || status == STATUS_INVALID_PARAMETER, "LsaQueryInformationPolicy(PolicyDnsDomainInformation) failed, returned 0x%08x\n", status); if (status == STATUS_SUCCESS) { - ok(IsEqualGUID(&dns_domain_info->DomainGuid, &GUID_NULL), "DomainGUID should be GUID_NULL on local computer\n"); - ok(dns_domain_info->Sid==0,"Sid should be NULL on the local computer\n"); if (dns_domain_info->Sid || !IsEqualGUID(&dns_domain_info->DomainGuid, &GUID_NULL)) { LPSTR strsid = NULL; LPSTR name = NULL; @@ -169,6 +169,8 @@ static void test_lsa(void) LocalFree( guidstr ); LocalFree( strsid ); } + else + trace("Running on a standalone system.\n"); pLsaFreeMemory((LPVOID)dns_domain_info); } diff --git a/rostests/winetests/advapi32/registry.c b/rostests/winetests/advapi32/registry.c index fe3d3ff7c3a..95608c6503a 100644 --- a/rostests/winetests/advapi32/registry.c +++ b/rostests/winetests/advapi32/registry.c @@ -159,9 +159,8 @@ static const char *wine_debugstr_wn( const WCHAR *str, int n ) #define ADVAPI32_GET_PROC(func) \ - p ## func = (void*)GetProcAddress(hadvapi32, #func); \ - if(!p ## func) \ - trace("GetProcAddress(%s) failed\n", #func); + p ## func = (void*)GetProcAddress(hadvapi32, #func); + static void InitFunctionPtrs(void) { @@ -263,7 +262,11 @@ static void test_hkey_main_Value_W(LPCWSTR name, LPCWSTR string, ret = RegQueryValueExW(hkey_main, name, NULL, &type, NULL, &cbData); GLE = GetLastError(); ok(ret == ERROR_SUCCESS, "RegQueryValueExW failed: %d, GLE=%d\n", ret, GLE); - if(GLE == ERROR_CALL_NOT_IMPLEMENTED) return; + if(GLE == ERROR_CALL_NOT_IMPLEMENTED) + { + win_skip("RegQueryValueExW() is not implemented\n"); + return; + } ok(type == REG_SZ, "RegQueryValueExW returned type %d\n", type); ok(cbData == full_byte_len, @@ -328,13 +331,21 @@ static void test_set_value(void) test_hkey_main_Value_A(NULL, substring2A, sizeof(substring2A)); test_hkey_main_Value_W(NULL, substring2W, sizeof(substring2W)); - /* only REG_SZ is supported */ + /* only REG_SZ is supported on NT*/ ret = RegSetValueA(hkey_main, NULL, REG_BINARY, string2A, sizeof(string2A)); - ok(ret == ERROR_INVALID_PARAMETER, "RegSetValueA should have returned ERROR_INVALID_PARAMETER instead of %d\n", ret); + /* NT: ERROR_INVALID_PARAMETER, 9x: ERROR_SUCCESS */ + ok(ret == ERROR_INVALID_PARAMETER || broken(ret == ERROR_SUCCESS), + "got %d (expected ERROR_INVALID_PARAMETER or ERROR_SUCCESS)\n", ret); + ret = RegSetValueA(hkey_main, NULL, REG_EXPAND_SZ, string2A, sizeof(string2A)); - ok(ret == ERROR_INVALID_PARAMETER, "RegSetValueA should have returned ERROR_INVALID_PARAMETER instead of %d\n", ret); + /* NT: ERROR_INVALID_PARAMETER, 9x: ERROR_SUCCESS */ + ok(ret == ERROR_INVALID_PARAMETER || broken(ret == ERROR_SUCCESS), + "got %d (expected ERROR_INVALID_PARAMETER or ERROR_SUCCESS)\n", ret); + ret = RegSetValueA(hkey_main, NULL, REG_MULTI_SZ, string2A, sizeof(string2A)); - ok(ret == ERROR_INVALID_PARAMETER, "RegSetValueA should have returned ERROR_INVALID_PARAMETER instead of %d\n", ret); + /* NT: ERROR_INVALID_PARAMETER, 9x: ERROR_SUCCESS */ + ok(ret == ERROR_INVALID_PARAMETER || broken(ret == ERROR_SUCCESS), + "got %d (expected ERROR_INVALID_PARAMETER or ERROR_SUCCESS)\n", ret); /* Test RegSetValueExA with a 'zero-byte' string (as Office 2003 does). * Surprisingly enough we're supposed to get zero bytes out of it. @@ -433,7 +444,7 @@ static void create_test_entries(void) "RegSetValueExA failed\n"); ok(!RegSetValueExA(hkey_main,"TP1_SZ",0,REG_SZ, (const BYTE *)sTestpath1, strlen(sTestpath1)+1), "RegSetValueExA failed\n"); - ok(!RegSetValueExA(hkey_main,"TP1_ZB_SZ",0,REG_SZ, NULL, 0), + ok(!RegSetValueExA(hkey_main,"TP1_ZB_SZ",0,REG_SZ, (const BYTE *)"", 0), "RegSetValueExA failed\n"); ok(!RegSetValueExA(hkey_main,"TP2_EXP_SZ",0,REG_EXPAND_SZ, (const BYTE *)sTestpath2, strlen(sTestpath2)+1), "RegSetValueExA failed\n"); @@ -556,7 +567,7 @@ static void test_enum_value(void) res = RegSetValueExW( test_key, testW, 0, REG_SZ, (const BYTE *)foobarW, 7*sizeof(WCHAR) ); if (res==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED) { - skip("RegSetValueExW is not implemented\n"); + win_skip("RegSetValueExW is not implemented\n"); goto cleanup; } ok( res == 0, "RegSetValueExW failed error %d\n", res ); @@ -675,7 +686,7 @@ static void test_get_value(void) if(!pRegGetValueA) { - skip("RegGetValue not available on this platform\n"); + win_skip("RegGetValue not available on this platform\n"); return; } @@ -775,7 +786,7 @@ static void test_get_value(void) ret = pRegGetValueA(hkey_main, NULL, "TP1_SZ", RRF_RT_REG_SZ, &type, NULL, &size); ok(ret == ERROR_SUCCESS, "ret=%d\n", ret); /* v5.2.3790.1830 (2003 SP1) returns sTestpath1 length + 2 here. */ - ok(size == strlen(sTestpath1)+1 || size == strlen(sTestpath1)+2, + ok(size == strlen(sTestpath1)+1 || broken(size == strlen(sTestpath1)+2), "strlen(sTestpath1)=%d size=%d\n", lstrlenA(sTestpath1), size); ok(type == REG_SZ, "type=%d\n", type); @@ -816,7 +827,7 @@ static void test_get_value(void) ret = pRegGetValueA(hkey_main, NULL, "TP1_EXP_SZ", RRF_RT_REG_SZ, &type, buf, &size); ok(ret == ERROR_SUCCESS, "ret=%d\n", ret); /* At least v5.2.3790.1830 (2003 SP1) returns the unexpanded sTestpath1 length + 1 here. */ - ok((size == strlen(expanded)+1) || (size == strlen(sTestpath1)+1), + ok(size == strlen(expanded)+1 || broken(size == strlen(sTestpath1)+1), "strlen(expanded)=%d, strlen(sTestpath1)=%d, size=%d\n", lstrlenA(expanded), lstrlenA(sTestpath1), size); ok(type == REG_SZ, "type=%d\n", type); ok(!strcmp(expanded, buf), "expanded=\"%s\" buf=\"%s\"\n", expanded, buf); @@ -826,7 +837,7 @@ static void test_get_value(void) ret = pRegGetValueA(hkey_main, NULL, "TP2_EXP_SZ", RRF_RT_REG_SZ, &type, buf, &size); ok(ret == ERROR_SUCCESS, "ret=%d\n", ret); /* At least v5.2.3790.1830 (2003 SP1) returns the unexpanded sTestpath2 length + 1 here. */ - ok((size == strlen(expanded2)+1) || (size == strlen(sTestpath2)+1), + ok(size == strlen(expanded2)+1 || broken(size == strlen(sTestpath2)+1), "strlen(expanded2)=%d, strlen(sTestpath1)=%d, size=%d\n", lstrlenA(expanded2), lstrlenA(sTestpath2), size); ok(type == REG_SZ, "type=%d\n", type); ok(!strcmp(expanded2, buf), "expanded2=\"%s\" buf=\"%s\"\n", expanded2, buf); @@ -844,7 +855,7 @@ static void test_get_value(void) ret = pRegGetValueA(hkey_main, NULL, "TP1_EXP_SZ", RRF_RT_REG_EXPAND_SZ|RRF_NOEXPAND, NULL, NULL, &size); ok(ret == ERROR_SUCCESS, "ret=%d\n", ret); /* v5.2.3790.1830 (2003 SP1) returns sTestpath1 length + 2 here. */ - ok(size == strlen(sTestpath1)+1 || size == strlen(sTestpath1)+2, + ok(size == strlen(sTestpath1)+1 || broken(size == strlen(sTestpath1)+2), "strlen(sTestpath1)=%d size=%d\n", lstrlenA(sTestpath1), size); /* Query REG_EXPAND_SZ using RRF_RT_REG_SZ|RRF_NOEXPAND (type mismatch) */ @@ -854,6 +865,16 @@ static void test_get_value(void) /* Query REG_EXPAND_SZ using RRF_RT_REG_EXPAND_SZ (not allowed without RRF_NOEXPAND) */ ret = pRegGetValueA(hkey_main, NULL, "TP1_EXP_SZ", RRF_RT_REG_EXPAND_SZ, NULL, NULL, NULL); ok(ret == ERROR_INVALID_PARAMETER, "ret=%d\n", ret); + + /* Query REG_EXPAND_SZ using RRF_RT_ANY */ + buf[0] = 0; type = 0xdeadbeef; size = sizeof(buf); + ret = pRegGetValueA(hkey_main, NULL, "TP1_EXP_SZ", RRF_RT_ANY, &type, buf, &size); + ok(ret == ERROR_SUCCESS, "ret=%d\n", ret); + /* At least v5.2.3790.1830 (2003 SP1) returns the unexpanded sTestpath1 length + 1 here. */ + ok(size == strlen(expanded)+1 || broken(size == strlen(sTestpath1)+1), + "strlen(expanded)=%d, strlen(sTestpath1)=%d, size=%d\n", lstrlenA(expanded), lstrlenA(sTestpath1), size); + ok(type == REG_SZ, "type=%d\n", type); + ok(!strcmp(expanded, buf), "expanded=\"%s\" buf=\"%s\"\n", expanded, buf); } static void test_reg_open_key(void) @@ -935,6 +956,19 @@ static void test_reg_open_key(void) ok(ret == ERROR_BAD_PATHNAME || /* NT/2k/XP */ ret == ERROR_FILE_NOT_FOUND /* Win9x,ME */ , "expected ERROR_BAD_PATHNAME or ERROR_FILE_NOT_FOUND, got %d\n", ret); + + /* WOW64 flags */ + hkResult = NULL; + ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software", 0, KEY_READ|KEY_WOW64_32KEY, &hkResult); + ok((ret == ERROR_SUCCESS && hkResult != NULL) || broken(ret == ERROR_ACCESS_DENIED /* NT4, win2k */), + "RegOpenKeyEx with KEY_WOW64_32KEY failed (err=%u)\n", ret); + RegCloseKey(hkResult); + + hkResult = NULL; + ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software", 0, KEY_READ|KEY_WOW64_64KEY, &hkResult); + ok((ret == ERROR_SUCCESS && hkResult != NULL) || broken(ret == ERROR_ACCESS_DENIED /* NT4, win2k */), + "RegOpenKeyEx with KEY_WOW64_64KEY failed (err=%u)\n", ret); + RegCloseKey(hkResult); } static void test_reg_create_key(void) @@ -960,6 +994,19 @@ static void test_reg_create_key(void) ok(!ret, "RegCreateKeyExA failed with error %d\n", ret); RegDeleteKey(hkey1, NULL); } + + /* WOW64 flags - open an existing key */ + hkey1 = NULL; + ret = RegCreateKeyExA(HKEY_LOCAL_MACHINE, "Software", 0, NULL, 0, KEY_READ|KEY_WOW64_32KEY, NULL, &hkey1, NULL); + ok((ret == ERROR_SUCCESS && hkey1 != NULL) || broken(ret == ERROR_ACCESS_DENIED /* NT4, win2k */), + "RegOpenKeyEx with KEY_WOW64_32KEY failed (err=%u)\n", ret); + RegCloseKey(hkey1); + + hkey1 = NULL; + ret = RegCreateKeyExA(HKEY_LOCAL_MACHINE, "Software", 0, NULL, 0, KEY_READ|KEY_WOW64_64KEY, NULL, &hkey1, NULL); + ok((ret == ERROR_SUCCESS && hkey1 != NULL) || broken(ret == ERROR_ACCESS_DENIED /* NT4, win2k */), + "RegOpenKeyEx with KEY_WOW64_64KEY failed (err=%u)\n", ret); + RegCloseKey(hkey1); } static void test_reg_close_key(void) @@ -1124,7 +1171,7 @@ static void test_regconnectregistry( void) schnd = OpenSCManagerA( compName, NULL, GENERIC_READ); if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) { - skip("OpenSCManagerA is not implemented\n"); + win_skip("OpenSCManagerA is not implemented\n"); return; } @@ -1157,7 +1204,9 @@ static void test_reg_query_value(void) SetLastError(0xdeadbeef); size = MAX_PATH; ret = RegQueryValueA((HKEY)0xcafebabe, "subkey", val, &size); - ok(ret == ERROR_INVALID_HANDLE || ret == ERROR_BADKEY, /* Windows 98 returns BADKEY */ + ok(ret == ERROR_INVALID_HANDLE || + ret == ERROR_BADKEY || /* Windows 98 returns BADKEY */ + ret == ERROR_ACCESS_DENIED, /* non-admin winxp */ "Expected ERROR_INVALID_HANDLE or ERROR_BADKEY, got %d\n", ret); ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError()); @@ -1218,7 +1267,7 @@ static void test_reg_query_value(void) ret = RegQueryValueW(subkey, NULL, valW, &size); if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) { - skip("RegQueryValueW is not implemented\n"); + win_skip("RegQueryValueW is not implemented\n"); goto cleanup; } ok(ret == ERROR_MORE_DATA, "Expected ERROR_MORE_DATA, got %d\n", ret); @@ -1266,7 +1315,7 @@ static void test_reg_delete_tree(void) LONG size, ret; if(!pRegDeleteTreeA) { - skip("Skipping RegDeleteTreeA tests, function not present\n"); + win_skip("Skipping RegDeleteTreeA tests, function not present\n"); return; } diff --git a/rostests/winetests/advapi32/security.c b/rostests/winetests/advapi32/security.c index d393f110b26..99dbce88d92 100644 --- a/rostests/winetests/advapi32/security.c +++ b/rostests/winetests/advapi32/security.c @@ -101,6 +101,8 @@ static NTSTATUS (WINAPI *pNtQueryObject)(HANDLE,OBJECT_INFORMATION_CLASS,PVOID,U static DWORD (WINAPI *pSetEntriesInAclW)(ULONG, PEXPLICIT_ACCESSW, PACL, PACL*); static BOOL (WINAPI *pSetSecurityDescriptorControl)(PSECURITY_DESCRIPTOR, SECURITY_DESCRIPTOR_CONTROL, SECURITY_DESCRIPTOR_CONTROL); +static DWORD (WINAPI *pGetSecurityInfo)(HANDLE, SE_OBJECT_TYPE, SECURITY_INFORMATION, + PSID*, PSID*, PACL*, PACL*, PSECURITY_DESCRIPTOR*); static HMODULE hmod; static int myARGC; @@ -149,6 +151,7 @@ static void init(void) pMakeSelfRelativeSD = (void *)GetProcAddress(hmod, "MakeSelfRelativeSD"); pSetEntriesInAclW = (void *)GetProcAddress(hmod, "SetEntriesInAclW"); pSetSecurityDescriptorControl = (void *)GetProcAddress(hmod, "SetSecurityDescriptorControl"); + pGetSecurityInfo = (void *)GetProcAddress(hmod, "GetSecurityInfo"); myARGC = winetest_get_mainargs( &myARGV ); } @@ -586,8 +589,9 @@ static void test_lookupPrivilegeName(void) luid.LowPart = SE_CREATE_TOKEN_PRIVILEGE; cchName = sizeof(buf); ret = pLookupPrivilegeNameA("b0gu5.Nam3", &luid, buf, &cchName); - ok( !ret && GetLastError() == RPC_S_SERVER_UNAVAILABLE, - "LookupPrivilegeNameA didn't fail with RPC_S_SERVER_UNAVAILABLE: %d\n", + ok( !ret && (GetLastError() == RPC_S_SERVER_UNAVAILABLE || + GetLastError() == RPC_S_INVALID_NET_ADDR) /* w2k8 */, + "LookupPrivilegeNameA didn't fail with RPC_S_SERVER_UNAVAILABLE or RPC_S_INVALID_NET_ADDR: %d\n", GetLastError()); } @@ -644,8 +648,9 @@ static void test_lookupPrivilegeValue(void) /* check a bogus system name */ ret = pLookupPrivilegeValueA("b0gu5.Nam3", "SeCreateTokenPrivilege", &luid); - ok( !ret && GetLastError() == RPC_S_SERVER_UNAVAILABLE, - "LookupPrivilegeValueA didn't fail with RPC_S_SERVER_UNAVAILABLE: %d\n", + ok( !ret && (GetLastError() == RPC_S_SERVER_UNAVAILABLE || + GetLastError() == RPC_S_INVALID_NET_ADDR) /* w2k8 */, + "LookupPrivilegeValueA didn't fail with RPC_S_SERVER_UNAVAILABLE or RPC_S_INVALID_NET_ADDR: %d\n", GetLastError()); /* check a NULL string */ ret = pLookupPrivilegeValueA(NULL, 0, &luid); @@ -1642,7 +1647,8 @@ static void test_LookupAccountName(void) ok(!ret, "Expected 0, got %d\n", ret); todo_wine { - ok(GetLastError() == ERROR_NONE_MAPPED, + ok(GetLastError() == ERROR_NONE_MAPPED || + broken(GetLastError() == ERROR_TRUSTED_RELATIONSHIP_FAILURE), "Expected ERROR_NONE_MAPPED, got %d\n", GetLastError()); ok(sid_size == 0, "Expected 0, got %d\n", sid_size); ok(domain_size == 0, "Expected 0, got %d\n", domain_size); @@ -1699,8 +1705,10 @@ static void test_security_descriptor(void) } } -#define TEST_GRANTED_ACCESS(a,b) test_granted_access(a,b,__LINE__) -static void test_granted_access(HANDLE handle, ACCESS_MASK access, int line) +#define TEST_GRANTED_ACCESS(a,b) test_granted_access(a,b,0,__LINE__) +#define TEST_GRANTED_ACCESS2(a,b,c) test_granted_access(a,b,c,__LINE__) +static void test_granted_access(HANDLE handle, ACCESS_MASK access, + ACCESS_MASK alt, int line) { OBJECT_BASIC_INFORMATION obj_info; NTSTATUS status; @@ -1714,8 +1722,13 @@ static void test_granted_access(HANDLE handle, ACCESS_MASK access, int line) status = pNtQueryObject( handle, ObjectBasicInformation, &obj_info, sizeof(obj_info), NULL ); ok_(__FILE__, line)(!status, "NtQueryObject with err: %08x\n", status); - ok_(__FILE__, line)(obj_info.GrantedAccess == access, "Granted access should " - "be 0x%08x, instead of 0x%08x\n", access, obj_info.GrantedAccess); + if (alt) + ok_(__FILE__, line)(obj_info.GrantedAccess == access || + obj_info.GrantedAccess == alt, "Granted access should be 0x%08x " + "or 0x%08x, instead of 0x%08x\n", access, alt, obj_info.GrantedAccess); + else + ok_(__FILE__, line)(obj_info.GrantedAccess == access, "Granted access should " + "be 0x%08x, instead of 0x%08x\n", access, obj_info.GrantedAccess); } #define CHECK_SET_SECURITY(o,i,e) \ @@ -1827,7 +1840,8 @@ static void test_process_security(void) /* Doesn't matter what ACL say we should get full access for ourselves */ ok(CreateProcessA( NULL, buffer, &psa, NULL, FALSE, 0, NULL, NULL, &startup, &info ), "CreateProcess with err:%d\n", GetLastError()); - TEST_GRANTED_ACCESS( info.hProcess, PROCESS_ALL_ACCESS ); + TEST_GRANTED_ACCESS2( info.hProcess, PROCESS_ALL_ACCESS, + STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL ); winetest_wait_child_process( info.hProcess ); CloseHandle( info.hProcess ); @@ -1876,7 +1890,8 @@ static void test_process_security_child(void) ok(DuplicateHandle( GetCurrentProcess(), GetCurrentProcess(), GetCurrentProcess(), &handle, 0, TRUE, DUPLICATE_SAME_ACCESS ), "duplicating handle err:%d\n", GetLastError()); - TEST_GRANTED_ACCESS( handle, PROCESS_ALL_ACCESS ); + TEST_GRANTED_ACCESS2( handle, PROCESS_ALL_ACCESS, + STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL ); CloseHandle( handle ); @@ -1884,7 +1899,8 @@ static void test_process_security_child(void) ok(DuplicateHandle( GetCurrentProcess(), GetCurrentProcess(), GetCurrentProcess(), &handle, PROCESS_ALL_ACCESS, TRUE, 0 ), "duplicating handle err:%d\n", GetLastError()); - TEST_GRANTED_ACCESS( handle, PROCESS_ALL_ACCESS ); + TEST_GRANTED_ACCESS2( handle, PROCESS_ALL_ACCESS, + PROCESS_ALL_ACCESS | PROCESS_QUERY_LIMITED_INFORMATION ); ok(DuplicateHandle( GetCurrentProcess(), handle, GetCurrentProcess(), &handle1, PROCESS_VM_READ, TRUE, 0 ), "duplicating handle err:%d\n", GetLastError()); @@ -2482,6 +2498,61 @@ static void test_acls(void) ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "InitializeAcl(-1) failed with error %d\n", GetLastError()); } +static void test_GetSecurityInfo(void) +{ + HANDLE obj; + PSECURITY_DESCRIPTOR sd; + PSID owner, group; + PACL dacl; + DWORD ret; + + if (!pGetSecurityInfo) + { + win_skip("GetSecurityInfo is not available\n"); + return; + } + + /* Create something. Files have lots of associated security info. */ + obj = CreateFile(myARGV[0], GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (obj == INVALID_HANDLE_VALUE) + { + skip("Couldn't create an object for GetSecurityInfo test\n"); + return; + } + + ret = pGetSecurityInfo(obj, SE_FILE_OBJECT, + OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, + &owner, &group, &dacl, NULL, &sd); + if (ret == ERROR_CALL_NOT_IMPLEMENTED) + { + win_skip("GetSecurityInfo is not implemented\n"); + CloseHandle(obj); + return; + } + ok(ret == ERROR_SUCCESS, "GetSecurityInfo returned %d\n", ret); + ok(sd != NULL, "GetSecurityInfo\n"); + ok(owner != NULL, "GetSecurityInfo\n"); + ok(group != NULL, "GetSecurityInfo\n"); + ok(dacl != NULL, "GetSecurityInfo\n"); + ok(IsValidAcl(dacl), "GetSecurityInfo\n"); + + LocalFree(sd); + + /* If we don't ask for the security descriptor, Windows will still give us + the other stuff, leaving us no way to free it. */ + ret = pGetSecurityInfo(obj, SE_FILE_OBJECT, + OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, + &owner, &group, &dacl, NULL, NULL); + ok(ret == ERROR_SUCCESS, "GetSecurityInfo returned %d\n", ret); + ok(owner != NULL, "GetSecurityInfo\n"); + ok(group != NULL, "GetSecurityInfo\n"); + ok(dacl != NULL, "GetSecurityInfo\n"); + ok(IsValidAcl(dacl), "GetSecurityInfo\n"); + + CloseHandle(obj); +} + START_TEST(security) { init(); @@ -2510,4 +2581,5 @@ START_TEST(security) test_ConvertSecurityDescriptorToString(); test_PrivateObjectSecurity(); test_acls(); + test_GetSecurityInfo(); } diff --git a/rostests/winetests/advapi32/service.c b/rostests/winetests/advapi32/service.c index 8ffe2e8c242..da62b0b5e8b 100644 --- a/rostests/winetests/advapi32/service.c +++ b/rostests/winetests/advapi32/service.c @@ -33,6 +33,26 @@ static const CHAR spooler[] = "Spooler"; /* Should be available on all platforms */ +static BOOL (WINAPI *pChangeServiceConfig2A)(SC_HANDLE,DWORD,LPVOID); +static BOOL (WINAPI *pEnumServicesStatusExA)(SC_HANDLE, SC_ENUM_TYPE, DWORD, + DWORD, LPBYTE, DWORD, LPDWORD, + LPDWORD, LPDWORD, LPCSTR); +static BOOL (WINAPI *pQueryServiceConfig2A)(SC_HANDLE,DWORD,LPBYTE,DWORD,LPDWORD); +static BOOL (WINAPI *pQueryServiceConfig2W)(SC_HANDLE,DWORD,LPBYTE,DWORD,LPDWORD); +static BOOL (WINAPI *pQueryServiceStatusEx)(SC_HANDLE, SC_STATUS_TYPE, LPBYTE, + DWORD, LPDWORD); + +static void init_function_pointers(void) +{ + HMODULE hadvapi32 = GetModuleHandleA("advapi32.dll"); + + pChangeServiceConfig2A = (void*)GetProcAddress(hadvapi32, "ChangeServiceConfig2A"); + pEnumServicesStatusExA= (void*)GetProcAddress(hadvapi32, "EnumServicesStatusExA"); + pQueryServiceConfig2A= (void*)GetProcAddress(hadvapi32, "QueryServiceConfig2A"); + pQueryServiceConfig2W= (void*)GetProcAddress(hadvapi32, "QueryServiceConfig2W"); + pQueryServiceStatusEx= (void*)GetProcAddress(hadvapi32, "QueryServiceStatusEx"); +} + static void test_open_scm(void) { SC_HANDLE scm_handle; @@ -66,7 +86,8 @@ static void test_open_scm(void) scm_handle = OpenSCManagerA("DOESNOTEXIST", SERVICES_ACTIVE_DATABASEA, SC_MANAGER_CONNECT); ok(!scm_handle, "Expected failure\n"); todo_wine - ok(GetLastError() == RPC_S_SERVER_UNAVAILABLE, "Expected RPC_S_SERVER_UNAVAILABLE, got %d\n", GetLastError()); + ok(GetLastError() == RPC_S_SERVER_UNAVAILABLE || GetLastError() == RPC_S_INVALID_NET_ADDR /* w2k8 */, + "Expected RPC_S_SERVER_UNAVAILABLE or RPC_S_INVALID_NET_ADDR, got %d\n", GetLastError()); CloseServiceHandle(scm_handle); /* Just in case */ /* Proper call with an empty hostname */ @@ -145,7 +166,17 @@ static void test_open_svc(void) GetServiceDisplayNameA(scm_handle, spooler, NULL, &displaysize); /* Get the displayname */ GetServiceDisplayNameA(scm_handle, spooler, displayname, &displaysize); - /* Try to open the service with this displayname */ + /* Try to open the service with this displayname, unless the displayname equals + * the servicename as that would defeat the purpose of this test. + */ + if (!lstrcmpi(spooler, displayname)) + { + skip("displayname equals servicename\n"); + CloseServiceHandle(scm_handle); + return; + } + + SetLastError(0xdeadbeef); svc_handle = OpenServiceA(scm_handle, displayname, GENERIC_READ); ok(!svc_handle, "Expected failure\n"); ok(GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST, "Expected ERROR_SERVICE_DOES_NOT_EXIST, got %d\n", GetLastError()); @@ -773,6 +804,810 @@ static void test_get_servicekeyname(void) CloseServiceHandle(scm_handle); } +static void test_query_svc(void) +{ + SC_HANDLE scm_handle, svc_handle; + BOOL ret; + SERVICE_STATUS status; + SERVICE_STATUS_PROCESS *statusproc; + DWORD bufsize, needed; + + /* All NULL or wrong */ + SetLastError(0xdeadbeef); + ret = QueryServiceStatus(NULL, NULL); + ok(!ret, "Expected failure\n"); + ok(GetLastError() == ERROR_INVALID_HANDLE, + "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); + + scm_handle = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT); + + /* Check if 'Spooler' exists. + * Open with not enough rights to query the status. + */ + svc_handle = OpenServiceA(scm_handle, spooler, STANDARD_RIGHTS_READ); + if (!svc_handle) + { + skip("Spooler service doesn't exist\n"); + CloseServiceHandle(scm_handle); + return; + } + + SetLastError(0xdeadbeef); + ret = QueryServiceStatus(svc_handle, NULL); + ok(!ret, "Expected failure\n"); + todo_wine + ok(GetLastError() == ERROR_INVALID_ADDRESS || + GetLastError() == ERROR_INVALID_PARAMETER /* NT4 */, + "Unexpected last error %d\n", GetLastError()); + + SetLastError(0xdeadbeef); + ret = QueryServiceStatus(svc_handle, &status); + ok(!ret, "Expected failure\n"); + ok(GetLastError() == ERROR_ACCESS_DENIED, + "Expected ERROR_ACCESS_DENIED, got %d\n", GetLastError()); + + /* Open the service with just enough rights. + * (Verified with 'SERVICE_ALL_ACCESS &~ SERVICE_QUERY_STATUS') + */ + CloseServiceHandle(svc_handle); + svc_handle = OpenServiceA(scm_handle, spooler, SERVICE_QUERY_STATUS); + + SetLastError(0xdeadbeef); + ret = QueryServiceStatus(svc_handle, &status); + ok(ret, "Expected success\n"); + ok(GetLastError() == ERROR_SUCCESS /* W2K3 */ || + GetLastError() == 0xdeadbeef /* NT4, XP and Vista */ || + GetLastError() == ERROR_IO_PENDING /* W2K */, + "Unexpected last error %d\n", GetLastError()); + + CloseServiceHandle(svc_handle); + + /* More or less the same tests for QueryServiceStatusEx */ + + /* Open service with not enough rights to query the status */ + svc_handle = OpenServiceA(scm_handle, spooler, STANDARD_RIGHTS_READ); + + /* All NULL or wrong, this proves that info level is checked first */ + SetLastError(0xdeadbeef); + ret = pQueryServiceStatusEx(NULL, 1, NULL, 0, NULL); + ok(!ret, "Expected failure\n"); + todo_wine + ok(GetLastError() == ERROR_INVALID_LEVEL, + "Expected ERROR_INVALID_LEVEL, got %d\n", GetLastError()); + + /* Passing a NULL parameter for the needed buffer size + * will crash on anything but NT4. + */ + + /* Only info level is correct. It looks like the buffer/size is checked second */ + SetLastError(0xdeadbeef); + ret = pQueryServiceStatusEx(NULL, 0, NULL, 0, &needed); + /* NT4 checks the handle first */ + if (GetLastError() != ERROR_INVALID_HANDLE) + { + ok(!ret, "Expected failure\n"); + ok(needed == sizeof(SERVICE_STATUS_PROCESS), + "Needed buffersize is wrong : %d\n", needed); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError()); + } + + /* Pass a correct buffer and buffersize but a NULL handle */ + statusproc = HeapAlloc(GetProcessHeap(), 0, needed); + bufsize = needed; + SetLastError(0xdeadbeef); + ret = pQueryServiceStatusEx(NULL, 0, (BYTE*)statusproc, bufsize, &needed); + ok(!ret, "Expected failure\n"); + ok(GetLastError() == ERROR_INVALID_HANDLE, + "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); + HeapFree(GetProcessHeap(), 0, statusproc); + + /* Correct handle and info level */ + SetLastError(0xdeadbeef); + ret = pQueryServiceStatusEx(svc_handle, 0, NULL, 0, &needed); + /* NT4 doesn't return the needed size */ + if (GetLastError() != ERROR_INVALID_PARAMETER) + { + ok(!ret, "Expected failure\n"); + todo_wine + { + ok(needed == sizeof(SERVICE_STATUS_PROCESS), + "Needed buffersize is wrong : %d\n", needed); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError()); + } + } + + /* All parameters are OK but we don't have enough rights */ + statusproc = HeapAlloc(GetProcessHeap(), 0, sizeof(SERVICE_STATUS_PROCESS)); + bufsize = sizeof(SERVICE_STATUS_PROCESS); + SetLastError(0xdeadbeef); + ret = pQueryServiceStatusEx(svc_handle, 0, (BYTE*)statusproc, bufsize, &needed); + ok(!ret, "Expected failure\n"); + ok(GetLastError() == ERROR_ACCESS_DENIED, + "Expected ERROR_ACCESS_DENIED, got %d\n", GetLastError()); + HeapFree(GetProcessHeap(), 0, statusproc); + + /* Open the service with just enough rights. */ + CloseServiceHandle(svc_handle); + svc_handle = OpenServiceA(scm_handle, spooler, SERVICE_QUERY_STATUS); + + /* Everything should be fine now. */ + statusproc = HeapAlloc(GetProcessHeap(), 0, sizeof(SERVICE_STATUS_PROCESS)); + bufsize = sizeof(SERVICE_STATUS_PROCESS); + SetLastError(0xdeadbeef); + ret = pQueryServiceStatusEx(svc_handle, 0, (BYTE*)statusproc, bufsize, &needed); + ok(ret, "Expected success\n"); + ok(GetLastError() == ERROR_SUCCESS /* W2K3 */ || + GetLastError() == 0xdeadbeef /* NT4, XP and Vista */ || + GetLastError() == ERROR_IO_PENDING /* W2K */, + "Unexpected last error %d\n", GetLastError()); + if (statusproc->dwCurrentState == SERVICE_RUNNING) + ok(statusproc->dwProcessId != 0, + "Expect a process id for this running service\n"); + else + ok(statusproc->dwProcessId == 0, + "Expect no process id for this stopped service\n"); + HeapFree(GetProcessHeap(), 0, statusproc); + + CloseServiceHandle(svc_handle); + CloseServiceHandle(scm_handle); +} + +static void test_enum_svc(void) +{ + SC_HANDLE scm_handle; + BOOL ret; + DWORD bufsize, needed, returned, resume; + DWORD tempneeded, tempreturned; + DWORD servicecountactive, servicecountinactive; + ENUM_SERVICE_STATUS *services; + ENUM_SERVICE_STATUS_PROCESS *exservices; + INT i; + + /* All NULL or wrong */ + SetLastError(0xdeadbeef); + ret = EnumServicesStatusA(NULL, 1, 0, NULL, 0, NULL, NULL, NULL); + ok(!ret, "Expected failure\n"); + todo_wine + ok(GetLastError() == ERROR_INVALID_HANDLE, + "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); + + /* Open the service control manager with not enough rights at first */ + scm_handle = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT); + + /* Valid handle but rest is still NULL or wrong */ + SetLastError(0xdeadbeef); + ret = EnumServicesStatusA(scm_handle, 1, 0, NULL, 0, NULL, NULL, NULL); + ok(!ret, "Expected failure\n"); + todo_wine + ok(GetLastError() == ERROR_INVALID_ADDRESS || + GetLastError() == ERROR_INVALID_PARAMETER /* NT4 */, + "Unexpected last error %d\n", GetLastError()); + + /* Don't specify the two required pointers */ + returned = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = EnumServicesStatusA(scm_handle, 0, 0, NULL, 0, NULL, &returned, NULL); + ok(!ret, "Expected failure\n"); + ok(returned == 0xdeadbeef, "Expected no change to the number of services variable\n"); + todo_wine + ok(GetLastError() == ERROR_INVALID_ADDRESS || + GetLastError() == ERROR_INVALID_PARAMETER /* NT4 */, + "Unexpected last error %d\n", GetLastError()); + + /* Don't specify the two required pointers */ + needed = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = EnumServicesStatusA(scm_handle, 0, 0, NULL, 0, &needed, NULL, NULL); + ok(!ret, "Expected failure\n"); + ok(needed == 0xdeadbeef, "Expected no change to the needed buffer variable\n"); + todo_wine + ok(GetLastError() == ERROR_INVALID_ADDRESS || + GetLastError() == ERROR_INVALID_PARAMETER /* NT4 */, + "Unexpected last error %d\n", GetLastError()); + + /* No valid servicetype and servicestate */ + needed = 0xdeadbeef; + returned = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = EnumServicesStatusA(scm_handle, 0, 0, NULL, 0, &needed, &returned, NULL); + ok(!ret, "Expected failure\n"); + todo_wine + { + ok(needed == 0, "Expected needed buffer size to be set to 0, got %d\n", needed); + ok(returned == 0, "Expected number of services to be set to 0, got %d\n", returned); + ok(GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + } + + /* No valid servicetype and servicestate */ + needed = 0xdeadbeef; + returned = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = EnumServicesStatusA(scm_handle, SERVICE_WIN32, 0, NULL, 0, &needed, &returned, NULL); + ok(!ret, "Expected failure\n"); + todo_wine + { + ok(needed == 0, "Expected needed buffer size to be set to 0, got %d\n", needed); + ok(returned == 0, "Expected number of services to be set to 0, got %d\n", returned); + ok(GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + } + + /* No valid servicetype and servicestate */ + needed = 0xdeadbeef; + returned = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = EnumServicesStatusA(scm_handle, 0, SERVICE_STATE_ALL, NULL, 0, + &needed, &returned, NULL); + ok(!ret, "Expected failure\n"); + todo_wine + { + ok(needed == 0, "Expected needed buffer size to be set to 0, got %d\n", needed); + ok(returned == 0, "Expected number of services to be set to 0, got %d\n", returned); + ok(GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + } + + /* All parameters are correct but our access rights are wrong */ + needed = 0xdeadbeef; + returned = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = EnumServicesStatusA(scm_handle, SERVICE_WIN32, SERVICE_STATE_ALL, NULL, 0, + &needed, &returned, NULL); + ok(!ret, "Expected failure\n"); + todo_wine + { + ok(needed == 0, "Expected needed buffer size to be set to 0, got %d\n", needed); + ok(returned == 0, "Expected number of services to be set to 0, got %d\n", returned); + } + ok(GetLastError() == ERROR_ACCESS_DENIED, + "Expected ERROR_ACCESS_DENIED, got %d\n", GetLastError()); + + /* Open the service control manager with the needed rights */ + CloseServiceHandle(scm_handle); + scm_handle = OpenSCManagerA(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE); + + /* All parameters are correct. Request the needed buffer size */ + needed = 0xdeadbeef; + returned = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = EnumServicesStatusA(scm_handle, SERVICE_WIN32, SERVICE_STATE_ALL, NULL, 0, + &needed, &returned, NULL); + ok(!ret, "Expected failure\n"); + todo_wine + { + ok(needed != 0xdeadbeef && needed > 0, "Expected the needed buffer size for this one service\n"); + ok(returned == 0, "Expected no service returned, got %d\n", returned); + ok(GetLastError() == ERROR_MORE_DATA, + "Expected ERROR_MORE_DATA, got %d\n", GetLastError()); + } + + /* Store the needed bytes */ + tempneeded = needed; + + /* Allocate the correct needed bytes */ + services = HeapAlloc(GetProcessHeap(), 0, needed); + bufsize = needed; + needed = 0xdeadbeef; + returned = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = EnumServicesStatusA(scm_handle, SERVICE_WIN32, SERVICE_STATE_ALL, + services, bufsize, &needed, &returned, NULL); + todo_wine + { + ok(ret, "Expected success\n"); + ok(needed == 0, "Expected needed buffer to be 0 as we are done\n"); + ok(returned != 0xdeadbeef && returned > 0, "Expected some returned services\n"); + ok(GetLastError() == ERROR_SUCCESS /* W2K3 */ || + GetLastError() == 0xdeadbeef /* NT4, XP and Vista */ || + GetLastError() == ERROR_IO_PENDING /* W2K */, + "Unexpected last error %d\n", GetLastError()); + } + HeapFree(GetProcessHeap(), 0, services); + + /* Store the number of returned services */ + tempreturned = returned; + + /* Allocate less than the needed bytes and don't specify a resume handle */ + services = HeapAlloc(GetProcessHeap(), 0, tempneeded - 1); + bufsize = tempneeded - 1; + needed = 0xdeadbeef; + returned = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = EnumServicesStatusA(scm_handle, SERVICE_WIN32, SERVICE_STATE_ALL, + services, bufsize, &needed, &returned, NULL); + ok(!ret, "Expected failure\n"); + todo_wine + { + ok(needed != 0xdeadbeef && needed > 0, "Expected the needed buffer size for this one service\n"); + ok(returned == (tempreturned - 1), "Expected one service less to be returned\n"); + ok(GetLastError() == ERROR_MORE_DATA, + "Expected ERROR_MORE_DATA, got %d\n", GetLastError()); + } + HeapFree(GetProcessHeap(), 0, services); + + /* Allocate less than the needed bytes, this time with a correct resume handle */ + services = HeapAlloc(GetProcessHeap(), 0, tempneeded - 1); + bufsize = tempneeded - 1; + needed = 0xdeadbeef; + returned = 0xdeadbeef; + resume = 0; + SetLastError(0xdeadbeef); + ret = EnumServicesStatusA(scm_handle, SERVICE_WIN32, SERVICE_STATE_ALL, + services, bufsize, &needed, &returned, &resume); + ok(!ret, "Expected failure\n"); + todo_wine + { + ok(needed != 0xdeadbeef && needed > 0, "Expected the needed buffer size for this one service\n"); + ok(returned == (tempreturned - 1), "Expected one service less to be returned\n"); + ok(resume, "Expected a resume handle\n"); + ok(GetLastError() == ERROR_MORE_DATA, + "Expected ERROR_MORE_DATA, got %d\n", GetLastError()); + } + HeapFree(GetProcessHeap(), 0, services); + + /* Fetch that last service but pass a bigger buffer size */ + services = HeapAlloc(GetProcessHeap(), 0, tempneeded); + bufsize = tempneeded; + needed = 0xdeadbeef; + returned = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = EnumServicesStatusA(scm_handle, SERVICE_WIN32, SERVICE_STATE_ALL, + services, bufsize, &needed, &returned, &resume); + todo_wine + { + ok(ret, "Expected success\n"); + ok(needed == 0, "Expected needed buffer to be 0 as we are done\n"); + ok(returned == 1, "Expected only 1 service to be returned\n"); + ok(GetLastError() == ERROR_SUCCESS /* W2K3 */ || + GetLastError() == 0xdeadbeef /* NT4, XP and Vista */ || + GetLastError() == ERROR_IO_PENDING /* W2K */, + "Unexpected last error %d\n", GetLastError()); + } + ok(resume == 0, "Expected the resume handle to be 0\n"); + HeapFree(GetProcessHeap(), 0, services); + + /* See if things add up */ + + /* Vista only shows the drivers with a state of SERVICE_RUNNING as active + * and doesn't count the others as inactive. This means that Vista could + * show a total that is greater than the sum of active and inactive + * drivers. + * The number of active and inactive drivers is greatly influenced by the + * time when tests are run, immediately after boot or later for example. + * + * Both reasons make calculations for drivers not so useful + */ + + /* Get the number of active win32 services */ + EnumServicesStatusA(scm_handle, SERVICE_WIN32, SERVICE_ACTIVE, NULL, 0, + &needed, &returned, NULL); + services = HeapAlloc(GetProcessHeap(), 0, needed); + EnumServicesStatusA(scm_handle, SERVICE_WIN32, SERVICE_ACTIVE, services, + needed, &needed, &returned, NULL); + HeapFree(GetProcessHeap(), 0, services); + + servicecountactive = returned; + + /* Get the number of inactive win32 services */ + EnumServicesStatusA(scm_handle, SERVICE_WIN32, SERVICE_INACTIVE, NULL, 0, + &needed, &returned, NULL); + services = HeapAlloc(GetProcessHeap(), 0, needed); + EnumServicesStatusA(scm_handle, SERVICE_WIN32, SERVICE_INACTIVE, services, + needed, &needed, &returned, NULL); + HeapFree(GetProcessHeap(), 0, services); + + servicecountinactive = returned; + + /* Get the number of win32 services */ + EnumServicesStatusA(scm_handle, SERVICE_WIN32, SERVICE_STATE_ALL, NULL, 0, + &needed, &returned, NULL); + services = HeapAlloc(GetProcessHeap(), 0, needed); + EnumServicesStatusA(scm_handle, SERVICE_WIN32, SERVICE_STATE_ALL, services, + needed, &needed, &returned, NULL); + HeapFree(GetProcessHeap(), 0, services); + + /* Check if total is the same as active and inactive win32 services */ + todo_wine + ok(returned == (servicecountactive + servicecountinactive), + "Something wrong in the calculation\n"); + + /* Get all drivers and services + * + * Fetch the status of the last call as failing could make the following tests crash + * on Wine (we don't return anything yet). + */ + EnumServicesStatusA(scm_handle, SERVICE_DRIVER | SERVICE_WIN32, SERVICE_STATE_ALL, + NULL, 0, &needed, &returned, NULL); + services = HeapAlloc(GetProcessHeap(), 0, needed); + ret = EnumServicesStatusA(scm_handle, SERVICE_DRIVER | SERVICE_WIN32, SERVICE_STATE_ALL, + services, needed, &needed, &returned, NULL); + + /* Loop through all those returned drivers and services */ + for (i = 0; ret && i < returned; i++) + { + SERVICE_STATUS status = services[i].ServiceStatus; + + /* lpServiceName and lpDisplayName should always be filled */ + ok(lstrlenA(services[i].lpServiceName) > 0, "Expected a service name\n"); + ok(lstrlenA(services[i].lpDisplayName) > 0, "Expected a display name\n"); + + /* Decrement the counters to see if the functions calls return the same + * numbers as the contents of these structures. + */ + if (status.dwServiceType & (SERVICE_WIN32_OWN_PROCESS | SERVICE_WIN32_SHARE_PROCESS)) + { + if (status.dwCurrentState == SERVICE_RUNNING) + servicecountactive--; + else + servicecountinactive--; + } + } + HeapFree(GetProcessHeap(), 0, services); + + todo_wine + { + ok(servicecountactive == 0, "Active services mismatch\n"); + ok(servicecountinactive == 0, "Inactive services mismatch\n"); + } + + CloseServiceHandle(scm_handle); + + /* More or less the same for EnumServicesStatusExA */ + + /* All NULL or wrong */ + SetLastError(0xdeadbeef); + ret = pEnumServicesStatusExA(NULL, 1, 0, 0, NULL, 0, NULL, NULL, NULL, NULL); + ok(!ret, "Expected failure\n"); + todo_wine + ok(GetLastError() == ERROR_INVALID_LEVEL, + "Expected ERROR_INVALID_LEVEL, got %d\n", GetLastError()); + + /* All NULL or wrong, just the info level is correct */ + SetLastError(0xdeadbeef); + ret = pEnumServicesStatusExA(NULL, 0, 0, 0, NULL, 0, NULL, NULL, NULL, NULL); + ok(!ret, "Expected failure\n"); + todo_wine + ok(GetLastError() == ERROR_INVALID_HANDLE, + "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); + + /* Open the service control manager with not enough rights at first */ + scm_handle = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT); + + /* Valid handle and info level but rest is still NULL or wrong */ + SetLastError(0xdeadbeef); + ret = pEnumServicesStatusExA(scm_handle, 0, 0, 0, NULL, 0, NULL, NULL, NULL, NULL); + ok(!ret, "Expected failure\n"); + todo_wine + ok(GetLastError() == ERROR_INVALID_ADDRESS || + GetLastError() == ERROR_INVALID_PARAMETER /* NT4 */, + "Unexpected last error %d\n", GetLastError()); + + /* Don't specify the two required pointers */ + needed = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = pEnumServicesStatusExA(scm_handle, 0, 0, 0, NULL, 0, &needed, NULL, NULL, NULL); + ok(!ret, "Expected failure\n"); + ok(needed == 0xdeadbeef, "Expected no change to the needed buffer variable\n"); + todo_wine + ok(GetLastError() == ERROR_INVALID_ADDRESS || + GetLastError() == ERROR_INVALID_PARAMETER /* NT4 */, + "Unexpected last error %d\n", GetLastError()); + + /* Don't specify the two required pointers */ + returned = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = pEnumServicesStatusExA(scm_handle, 0, 0, 0, NULL, 0, NULL, &returned, NULL, NULL); + ok(!ret, "Expected failure\n"); + todo_wine + { + ok(returned == 0xdeadbeef, "Expected no change to the number of services variable\n"); + ok(GetLastError() == ERROR_INVALID_ADDRESS || + GetLastError() == ERROR_INVALID_PARAMETER /* NT4 */, + "Unexpected last error %d\n", GetLastError()); + } + + /* No valid servicetype and servicestate */ + needed = 0xdeadbeef; + returned = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = pEnumServicesStatusExA(scm_handle, 0, 0, 0, NULL, 0, &needed, &returned, NULL, NULL); + ok(!ret, "Expected failure\n"); + ok(returned == 0, "Expected number of service to be set to 0, got %d\n", returned); + todo_wine + { + ok(needed == 0, "Expected needed buffer size to be set to 0, got %d\n", needed); + ok(GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + } + + /* No valid servicestate */ + needed = 0xdeadbeef; + returned = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32, 0, NULL, 0, + &needed, &returned, NULL, NULL); + ok(!ret, "Expected failure\n"); + ok(returned == 0, "Expected number of service to be set to 0, got %d\n", returned); + todo_wine + { + ok(needed == 0, "Expected needed buffer size to be set to 0, got %d\n", needed); + ok(GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + } + + /* No valid servicetype */ + needed = 0xdeadbeef; + returned = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = pEnumServicesStatusExA(scm_handle, 0, 0, SERVICE_STATE_ALL, NULL, 0, + &needed, &returned, NULL, NULL); + ok(!ret, "Expected failure\n"); + ok(returned == 0, "Expected number of service to be set to 0, got %d\n", returned); + todo_wine + { + ok(needed == 0, "Expected needed buffer size to be set to 0, got %d\n", needed); + ok(GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + } + + /* No valid servicetype and servicestate and unknown service group */ + needed = 0xdeadbeef; + returned = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = pEnumServicesStatusExA(scm_handle, 0, 0, 0, NULL, 0, &needed, + &returned, NULL, "deadbeef_group"); + ok(!ret, "Expected failure\n"); + ok(returned == 0, "Expected number of service to be set to 0, got %d\n", returned); + todo_wine + { + ok(needed == 0, "Expected needed buffer size to be set to 0, got %d\n", needed); + ok(GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + } + + /* All parameters are correct but our access rights are wrong */ + needed = 0xdeadbeef; + returned = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32, SERVICE_STATE_ALL, + NULL, 0, &needed, &returned, NULL, NULL); + ok(!ret, "Expected failure\n"); + todo_wine + ok(needed == 0, "Expected needed buffer size to be set to 0, got %d\n", needed); + ok(returned == 0, "Expected number of service to be set to 0, got %d\n", returned); + ok(GetLastError() == ERROR_ACCESS_DENIED, + "Expected ERROR_ACCESS_DENIED, got %d\n", GetLastError()); + + /* All parameters are correct, access rights are wrong but the + * group name won't be checked yet. + */ + needed = 0xdeadbeef; + returned = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32, SERVICE_STATE_ALL, + NULL, 0, &needed, &returned, NULL, "deadbeef_group"); + ok(!ret, "Expected failure\n"); + todo_wine + ok(needed == 0, "Expected needed buffer size to be set to 0, got %d\n", needed); + ok(returned == 0, "Expected number of service to be set to 0, got %d\n", returned); + ok(GetLastError() == ERROR_ACCESS_DENIED, + "Expected ERROR_ACCESS_DENIED, got %d\n", GetLastError()); + + /* Open the service control manager with the needed rights */ + CloseServiceHandle(scm_handle); + scm_handle = OpenSCManagerA(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE); + + /* All parameters are correct and the group will be checked */ + needed = 0xdeadbeef; + returned = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32, SERVICE_STATE_ALL, + NULL, 0, &needed, &returned, NULL, "deadbeef_group"); + ok(!ret, "Expected failure\n"); + ok(returned == 0, "Expected number of service to be set to 0, got %d\n", returned); + todo_wine + { + ok(needed == 0, "Expected needed buffer size to be set to 0, got %d\n", needed); + ok(GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST, + "Expected ERROR_SERVICE_DOES_NOT_EXIST, got %d\n", GetLastError()); + } + + /* TODO: Create a test that makes sure we enumerate all services that don't + * belong to a group. (specifying ""). + */ + + /* All parameters are correct. Request the needed buffer size */ + needed = 0xdeadbeef; + returned = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32, SERVICE_STATE_ALL, + NULL, 0, &needed, &returned, NULL, NULL); + ok(!ret, "Expected failure\n"); + ok(returned == 0, "Expected no service returned, got %d\n", returned); + todo_wine + { + ok(needed != 0xdeadbeef && needed > 0, "Expected the needed buffer size\n"); + ok(GetLastError() == ERROR_MORE_DATA, + "Expected ERROR_MORE_DATA, got %d\n", GetLastError()); + } + + /* Store the needed bytes */ + tempneeded = needed; + + /* Allocate the correct needed bytes */ + exservices = HeapAlloc(GetProcessHeap(), 0, needed); + bufsize = needed; + needed = 0xdeadbeef; + returned = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32, SERVICE_STATE_ALL, + (BYTE*)exservices, bufsize, &needed, &returned, NULL, NULL); + todo_wine + { + ok(ret, "Expected success\n"); + ok(needed == 0, "Expected needed buffer to be 0 as we are done\n"); + ok(returned == tempreturned, "Expected the same number of service from this function\n"); + ok(GetLastError() == ERROR_SUCCESS /* W2K3 */ || + GetLastError() == 0xdeadbeef /* NT4, XP and Vista */ || + GetLastError() == ERROR_IO_PENDING /* W2K */, + "Unexpected last error %d\n", GetLastError()); + } + HeapFree(GetProcessHeap(), 0, exservices); + + /* Store the number of returned services */ + tempreturned = returned; + + /* Allocate less than the needed bytes and don't specify a resume handle */ + exservices = HeapAlloc(GetProcessHeap(), 0, tempneeded - 1); + bufsize = tempneeded - 1; + needed = 0xdeadbeef; + returned = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32, SERVICE_STATE_ALL, + (BYTE*)exservices, bufsize, &needed, &returned, NULL, NULL); + ok(!ret, "Expected failure\n"); + todo_wine + { + ok(needed != 0xdeadbeef && needed > 0, "Expected the needed buffer size\n"); + ok(returned == (tempreturned - 1), "Expected one service less to be returned\n"); + ok(GetLastError() == ERROR_MORE_DATA, + "Expected ERROR_MORE_DATA, got %d\n", GetLastError()); + } + HeapFree(GetProcessHeap(), 0, exservices); + + /* Allocate less than the needed bytes, this time with a correct resume handle */ + exservices = HeapAlloc(GetProcessHeap(), 0, tempneeded - 1); + bufsize = tempneeded - 1; + needed = 0xdeadbeef; + returned = 0xdeadbeef; + resume = 0; + SetLastError(0xdeadbeef); + ret = pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32, SERVICE_STATE_ALL, + (BYTE*)exservices, bufsize, &needed, &returned, &resume, NULL); + ok(!ret, "Expected failure\n"); + todo_wine + { + ok(needed != 0xdeadbeef && needed > 0, "Expected the needed buffer size\n"); + ok(returned == (tempreturned - 1), "Expected one service less to be returned\n"); + ok(resume, "Expected a resume handle\n"); + ok(GetLastError() == ERROR_MORE_DATA, + "Expected ERROR_MORE_DATA, got %d\n", GetLastError()); + } + HeapFree(GetProcessHeap(), 0, exservices); + + /* Fetch that last service but pass a bigger buffer size */ + exservices = HeapAlloc(GetProcessHeap(), 0, tempneeded); + bufsize = tempneeded; + needed = 0xdeadbeef; + returned = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32, SERVICE_STATE_ALL, + (BYTE*)exservices, bufsize, &needed, &returned, &resume, NULL); + todo_wine + { + ok(ret, "Expected success\n"); + ok(needed == 0, "Expected needed buffer to be 0 as we are done\n"); + ok(returned == 1, "Expected only 1 service to be returned\n"); + ok(GetLastError() == ERROR_SUCCESS /* W2K3 */ || + GetLastError() == 0xdeadbeef /* NT4, XP and Vista */ || + GetLastError() == ERROR_IO_PENDING /* W2K */, + "Unexpected last error %d\n", GetLastError()); + } + ok(resume == 0, "Expected the resume handle to be 0\n"); + HeapFree(GetProcessHeap(), 0, exservices); + + /* See if things add up */ + + /* Get the number of active win32 services */ + pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32, SERVICE_ACTIVE, + NULL, 0, &needed, &returned, NULL, NULL); + exservices = HeapAlloc(GetProcessHeap(), 0, needed); + pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32, SERVICE_ACTIVE, + (BYTE*)exservices, needed, &needed, &returned, NULL, NULL); + HeapFree(GetProcessHeap(), 0, exservices); + + servicecountactive = returned; + + /* Get the number of inactive win32 services */ + pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32, SERVICE_INACTIVE, + NULL, 0, &needed, &returned, NULL, NULL); + exservices = HeapAlloc(GetProcessHeap(), 0, needed); + pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32, SERVICE_INACTIVE, + (BYTE*)exservices, needed, &needed, &returned, NULL, NULL); + HeapFree(GetProcessHeap(), 0, exservices); + + servicecountinactive = returned; + + /* Get the number of win32 services */ + pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32, SERVICE_STATE_ALL, + NULL, 0, &needed, &returned, NULL, NULL); + exservices = HeapAlloc(GetProcessHeap(), 0, needed); + pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32, SERVICE_STATE_ALL, + (BYTE*)exservices, needed, &needed, &returned, NULL, NULL); + HeapFree(GetProcessHeap(), 0, exservices); + + /* Check if total is the same as active and inactive win32 services */ + ok(returned == (servicecountactive + servicecountinactive), + "Something wrong in the calculation\n"); + + /* Get all drivers and services */ + pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32 | SERVICE_DRIVER, + SERVICE_STATE_ALL, NULL, 0, &needed, &returned, NULL, NULL); + exservices = HeapAlloc(GetProcessHeap(), 0, needed); + pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32 | SERVICE_DRIVER, + SERVICE_STATE_ALL, (BYTE*)exservices, needed, &needed, &returned, NULL, NULL); + + /* Loop through all those returned drivers and services */ + for (i = 0; i < returned; i++) + { + SERVICE_STATUS_PROCESS status = exservices[i].ServiceStatusProcess; + + + /* lpServiceName and lpDisplayName should always be filled */ + ok(lstrlenA(exservices[i].lpServiceName) > 0, "Expected a service name\n"); + ok(lstrlenA(exservices[i].lpDisplayName) > 0, "Expected a display name\n"); + + /* Decrement the counters to see if the functions calls return the + * same numbers as the contents of these structures. + * Check some process id specifics. + */ + if (status.dwServiceType & (SERVICE_FILE_SYSTEM_DRIVER | SERVICE_KERNEL_DRIVER)) + { + /* We shouldn't have a process id for drivers */ + ok(status.dwProcessId == 0, + "This driver shouldn't have an associated process id\n"); + } + + if (status.dwServiceType & (SERVICE_WIN32_OWN_PROCESS | SERVICE_WIN32_SHARE_PROCESS)) + { + if (status.dwCurrentState == SERVICE_RUNNING) + { + /* We expect a process id for every running service */ + ok(status.dwProcessId > 0, "Expected a process id for this running service (%s)\n", + exservices[i].lpServiceName); + + servicecountactive--; + } + else + { + /* We shouldn't have a process id for inactive services */ + ok(status.dwProcessId == 0, "This service shouldn't have an associated process id\n"); + + servicecountinactive--; + } + } + } + HeapFree(GetProcessHeap(), 0, exservices); + + ok(servicecountactive == 0, "Active services mismatch\n"); + ok(servicecountinactive == 0, "Inactive services mismatch\n"); + + CloseServiceHandle(scm_handle); +} + static void test_close(void) { SC_HANDLE handle; @@ -947,13 +1782,7 @@ static void test_queryconfig2(void) static const CHAR dependencies[] = "Master1\0Master2\0+MasterGroup1\0"; static const CHAR password [] = ""; static const CHAR description [] = "Description"; - HMODULE dllhandle = GetModuleHandleA("advapi32.dll"); - BOOL (WINAPI *pChangeServiceConfig2A)(SC_HANDLE,DWORD,LPVOID) - = (void*)GetProcAddress(dllhandle, "ChangeServiceConfig2A"); - BOOL (WINAPI *pQueryServiceConfig2A)(SC_HANDLE,DWORD,LPBYTE,DWORD,LPDWORD) - = (void*)GetProcAddress(dllhandle, "QueryServiceConfig2A"); - BOOL (WINAPI *pQueryServiceConfig2W)(SC_HANDLE,DWORD,LPBYTE,DWORD,LPDWORD) - = (void*)GetProcAddress(dllhandle, "QueryServiceConfig2W"); + if(!pQueryServiceConfig2A) { skip("function QueryServiceConfig2A not present\n"); @@ -1239,12 +2068,16 @@ START_TEST(service) } CloseServiceHandle(scm_handle); + init_function_pointers(); + /* First some parameter checking */ test_open_scm(); test_open_svc(); test_create_delete_svc(); test_get_displayname(); test_get_servicekeyname(); + test_query_svc(); + test_enum_svc(); test_close(); /* Test the creation, querying and deletion of a service */ test_sequence();