[ADVAPI32_WINETEST]

* Sync with Wine 1.3.29.

svn path=/trunk/; revision=53961
This commit is contained in:
Amine Khaldi 2011-10-03 15:18:15 +00:00
parent ab0304b942
commit ae8fa62fc7
10 changed files with 1680 additions and 482 deletions

View file

@ -156,10 +156,10 @@ static void test_CredReadDomainCredentialsA(void)
* does not check for NULL output pointers and try to zero them out early */
if(0)
{
ok(!pCredReadDomainCredentialsA(&info, 0, NULL, &creds) &&
GetLastError() == ERROR_INVALID_PARAMETER, "!\n");
ok(!pCredReadDomainCredentialsA(&info, 0, &count, NULL) &&
GetLastError() == ERROR_INVALID_PARAMETER, "!\n");
ret = pCredReadDomainCredentialsA(&info, 0, NULL, &creds);
ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "!\n");
ret = pCredReadDomainCredentialsA(&info, 0, &count, NULL);
ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "!\n");
}
SetLastError(0xdeadbeef);

View file

@ -238,6 +238,9 @@ static void test_incorrect_api_usage(void)
if (!result) return;
pCryptDestroyHash(hHash);
result = pCryptGenKey(0, CALG_RC4, 0, &hKey);
ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%d\n", GetLastError());
result = pCryptGenKey(hProv, CALG_RC4, 0, &hKey);
ok (result, "%d\n", GetLastError());
if (!result) return;
@ -414,6 +417,7 @@ static void test_verify_sig(void)
CRYPT_NEWKEYSET);
if (!ret && GetLastError() == NTE_EXISTS)
ret = pCryptAcquireContextA(&prov, szKeySet, NULL, PROV_RSA_FULL, 0);
ok(ret, "CryptAcquireContextA failed: %08x\n", GetLastError());
ret = pCryptImportKey(prov, (LPBYTE)privKey, sizeof(privKey), 0, 0, &key);
ok(ret, "CryptImportKey failed: %08x\n", GetLastError());
ret = pCryptCreateHash(prov, CALG_MD5, 0, 0, &hash);
@ -898,6 +902,7 @@ static void test_set_provider_ex(void)
/* call CryptGetDefaultProvider to see if they match */
result = pCryptGetDefaultProviderA(PROV_RSA_FULL, NULL, CRYPT_MACHINE_DEFAULT, NULL, &cbProvName);
ok(result, "%d\n", GetLastError());
if (!(pszProvName = LocalAlloc(LMEM_ZEROINIT, cbProvName)))
goto reset;
@ -945,7 +950,8 @@ static void test_machine_guid(void)
r);
/* Create and release a provider */
ret = pCryptAcquireContextA(&hCryptProv, szKeySet, NULL, PROV_RSA_FULL, 0);
ok(ret, "CryptAcquireContextA failed: %08x\n", GetLastError());
ok(ret || broken(!ret && GetLastError() == NTE_KEYSET_ENTRY_BAD /* NT4 */),
"CryptAcquireContextA failed: %08x\n", GetLastError());
pCryptReleaseContext(hCryptProv, 0);
if (restoreGuid)
@ -992,7 +998,6 @@ static void test_rc2_keylen(void)
sizeof(BLOBHEADER)+sizeof(DWORD)+key_blob.key_size,
0, CRYPT_IPSEC_HMAC_KEY, &hkey);
/* CRYPT_IPSEC_HMAC_KEY is not supported on W2K and lower */
todo_wine
ok(ret ||
broken(!ret && GetLastError() == NTE_BAD_FLAGS),
"CryptImportKey error %08x\n", GetLastError());
@ -1040,7 +1045,6 @@ static void test_rc2_keylen(void)
sizeof(BLOBHEADER)+sizeof(DWORD)+key_blob.key_size,
0, CRYPT_IPSEC_HMAC_KEY, &hkey);
/* CRYPT_IPSEC_HMAC_KEY is not supported on W2K and lower */
todo_wine
ok(ret ||
broken(!ret && GetLastError() == NTE_BAD_FLAGS),
"CryptImportKey error %08x\n", GetLastError());
@ -1065,7 +1069,6 @@ static void test_rc2_keylen(void)
ret = pCryptImportKey(provider, (BYTE*)&key_blob,
sizeof(BLOBHEADER)+sizeof(DWORD)+key_blob.key_size,
0, CRYPT_IPSEC_HMAC_KEY, &hkey);
todo_wine
ok(ret ||
broken(!ret && GetLastError() == NTE_BAD_FLAGS),
"CryptImportKey error %08x\n", GetLastError());
@ -1080,7 +1083,6 @@ static void test_rc2_keylen(void)
ret = pCryptImportKey(provider, (BYTE*)&key_blob,
sizeof(BLOBHEADER)+sizeof(DWORD)+key_blob.key_size,
0, CRYPT_IPSEC_HMAC_KEY, &hkey);
todo_wine
ok(ret ||
broken(!ret && GetLastError() == NTE_BAD_FLAGS),
"CryptImportKey error %08x\n", GetLastError());

View file

@ -34,56 +34,44 @@ struct ustring {
unsigned char *Buffer;
};
typedef NTSTATUS (WINAPI *fnSystemFunction001)(const BYTE *, const BYTE *, LPBYTE);
typedef NTSTATUS (WINAPI *fnSystemFunction002)(const BYTE *, const BYTE *, LPBYTE);
typedef NTSTATUS (WINAPI *fnSystemFunction003)(const BYTE *, LPBYTE);
typedef NTSTATUS (WINAPI *fnSystemFunction004)(const struct ustring *, const struct ustring *, struct ustring *);
typedef NTSTATUS (WINAPI *fnSystemFunction005)(const struct ustring *, const struct ustring *, struct ustring *);
typedef VOID (WINAPI *fnSystemFunction006)( PCSTR passwd, PSTR lmhash );
typedef NTSTATUS (WINAPI *fnSystemFunction008)(const BYTE *, const BYTE *, LPBYTE);
typedef NTSTATUS (WINAPI *fnSystemFunction009)(const BYTE *, const BYTE *, LPBYTE);
typedef int (WINAPI *descrypt)(unsigned char *, unsigned char *, unsigned char *);
typedef NTSTATUS (WINAPI *fnSystemFunction030)(const void*, const void*);
typedef NTSTATUS (WINAPI *fnSystemFunction032)(struct ustring *, const struct ustring *);
fnSystemFunction001 pSystemFunction001;
fnSystemFunction002 pSystemFunction002;
fnSystemFunction003 pSystemFunction003;
fnSystemFunction004 pSystemFunction004;
fnSystemFunction004 pSystemFunction005;
fnSystemFunction006 pSystemFunction006;
fnSystemFunction008 pSystemFunction008;
fnSystemFunction008 pSystemFunction009;
static NTSTATUS (WINAPI *pSystemFunction001)(const BYTE *, const BYTE *, LPBYTE);
static NTSTATUS (WINAPI *pSystemFunction002)(const BYTE *, const BYTE *, LPBYTE);
static NTSTATUS (WINAPI *pSystemFunction003)(const BYTE *, LPBYTE);
static NTSTATUS (WINAPI *pSystemFunction004)(const struct ustring *, const struct ustring *, struct ustring *);
static NTSTATUS (WINAPI *pSystemFunction005)(const struct ustring *, const struct ustring *, struct ustring *);
static VOID (WINAPI *pSystemFunction006)( PCSTR passwd, PSTR lmhash );
static NTSTATUS (WINAPI *pSystemFunction008)(const BYTE *, const BYTE *, LPBYTE);
static NTSTATUS (WINAPI *pSystemFunction009)(const BYTE *, const BYTE *, LPBYTE);
static NTSTATUS (WINAPI *pSystemFunction032)(struct ustring *, const struct ustring *);
/* encrypt two blocks */
descrypt pSystemFunction012;
descrypt pSystemFunction014;
descrypt pSystemFunction016;
descrypt pSystemFunction018;
descrypt pSystemFunction020;
descrypt pSystemFunction022;
static descrypt pSystemFunction012;
static descrypt pSystemFunction014;
static descrypt pSystemFunction016;
static descrypt pSystemFunction018;
static descrypt pSystemFunction020;
static descrypt pSystemFunction022;
/* decrypt two blocks */
descrypt pSystemFunction013;
descrypt pSystemFunction015;
descrypt pSystemFunction017;
descrypt pSystemFunction019;
descrypt pSystemFunction021;
descrypt pSystemFunction023;
static descrypt pSystemFunction013;
static descrypt pSystemFunction015;
static descrypt pSystemFunction017;
static descrypt pSystemFunction019;
static descrypt pSystemFunction021;
static descrypt pSystemFunction023;
/* encrypt two blocks with a 32bit key */
descrypt pSystemFunction024;
descrypt pSystemFunction025;
static descrypt pSystemFunction024;
static descrypt pSystemFunction025;
/* decrypt two blocks with a 32bit key */
descrypt pSystemFunction026;
descrypt pSystemFunction027;
static descrypt pSystemFunction026;
static descrypt pSystemFunction027;
typedef int (WINAPI *memcmpfunc)(unsigned char *, unsigned char *);
memcmpfunc pSystemFunction030;
memcmpfunc pSystemFunction031;
fnSystemFunction032 pSystemFunction032;
static memcmpfunc pSystemFunction030;
static memcmpfunc pSystemFunction031;
static void test_SystemFunction006(void)
{
@ -223,6 +211,7 @@ static void test_SystemFunction003(void)
memset(output, 0, sizeof output);
r = pSystemFunction002(data, key, output);
ok(r == STATUS_SUCCESS, "function failed\n");
ok( !memcmp(exp2, output, sizeof output), "decrypted message wrong\n");
}
@ -296,16 +285,19 @@ static void test_SystemFunction004(void)
memset(output, 0, sizeof output);
r = pSystemFunction002(out.Buffer, key.Buffer, output);
ok(r == STATUS_SUCCESS, "function failed\n");
ok(((unsigned int*)output)[0] == in.Length, "crypted length wrong\n");
ok(((unsigned int*)output)[1] == 1, "crypted value wrong\n");
memset(output, 0, sizeof output);
r = pSystemFunction002(out.Buffer+8, key.Buffer, output);
ok(r == STATUS_SUCCESS, "function failed\n");
ok(!memcmp(output, inbuf, sizeof output), "crypted data wrong\n");
memset(output, 0, sizeof output);
r = pSystemFunction002(out.Buffer+16, key.Buffer, output);
ok(r == STATUS_SUCCESS, "function failed\n");
ok(!memcmp(output, inbuf, sizeof output), "crypted data wrong\n");
}
@ -508,12 +500,6 @@ static void test_memcmpfunc(memcmpfunc fn)
return;
}
if (0)
{
/* crashes */
r = fn(NULL, NULL);
}
memset(arg1, 0, sizeof arg1);
memset(arg2, 0, sizeof arg2);
arg1[0x10] = 1;
@ -545,49 +531,49 @@ START_TEST(crypt_lmhash)
{
HMODULE module = GetModuleHandleA("advapi32.dll");
pSystemFunction001 = (fnSystemFunction001)GetProcAddress( module, "SystemFunction001" );
pSystemFunction001 = (void *)GetProcAddress( module, "SystemFunction001" );
if (pSystemFunction001)
test_SystemFunction001();
else
win_skip("SystemFunction001 is not available\n");
pSystemFunction002 = (fnSystemFunction002)GetProcAddress( module, "SystemFunction002" );
pSystemFunction002 = (void *)GetProcAddress( module, "SystemFunction002" );
if (pSystemFunction002)
test_SystemFunction002();
else
win_skip("SystemFunction002 is not available\n");
pSystemFunction003 = (fnSystemFunction003)GetProcAddress( module, "SystemFunction003" );
pSystemFunction003 = (void *)GetProcAddress( module, "SystemFunction003" );
if (pSystemFunction003)
test_SystemFunction003();
else
win_skip("SystemFunction002 is not available\n");
pSystemFunction004 = (fnSystemFunction004)GetProcAddress( module, "SystemFunction004" );
pSystemFunction004 = (void *)GetProcAddress( module, "SystemFunction004" );
if (pSystemFunction004)
test_SystemFunction004();
else
win_skip("SystemFunction004 is not available\n");
pSystemFunction005 = (fnSystemFunction005)GetProcAddress( module, "SystemFunction005" );
pSystemFunction005 = (void *)GetProcAddress( module, "SystemFunction005" );
if (pSystemFunction005)
test_SystemFunction005();
else
win_skip("SystemFunction005 is not available\n");
pSystemFunction006 = (fnSystemFunction006)GetProcAddress( module, "SystemFunction006" );
pSystemFunction006 = (void *)GetProcAddress( module, "SystemFunction006" );
if (pSystemFunction006)
test_SystemFunction006();
else
win_skip("SystemFunction006 is not available\n");
pSystemFunction008 = (fnSystemFunction008)GetProcAddress( module, "SystemFunction008" );
pSystemFunction008 = (void *)GetProcAddress( module, "SystemFunction008" );
if (pSystemFunction008)
test_SystemFunction008();
else
win_skip("SystemFunction008 is not available\n");
pSystemFunction009 = (fnSystemFunction009)GetProcAddress( module, "SystemFunction009" );
pSystemFunction009 = (void *)GetProcAddress( module, "SystemFunction009" );
if (pSystemFunction009)
test_SystemFunction009();
else
@ -641,7 +627,7 @@ START_TEST(crypt_lmhash)
test_memcmpfunc(pSystemFunction030);
test_memcmpfunc(pSystemFunction031);
pSystemFunction032 = (fnSystemFunction032)GetProcAddress( module, "SystemFunction032" );
pSystemFunction032 = (void *)GetProcAddress( module, "SystemFunction032" );
if (pSystemFunction032)
test_SystemFunction032();
else

View file

@ -36,18 +36,14 @@ typedef struct
unsigned char digest[16];
} MD4_CTX;
typedef VOID (WINAPI *fnMD4Init)( MD4_CTX *ctx );
typedef VOID (WINAPI *fnMD4Update)( MD4_CTX *ctx, const unsigned char *src, const int len );
typedef VOID (WINAPI *fnMD4Final)( MD4_CTX *ctx );
typedef int (WINAPI *fnSystemFunction007)(const UNICODE_STRING *, LPBYTE);
static VOID (WINAPI *pMD4Init)( MD4_CTX *ctx );
static VOID (WINAPI *pMD4Update)( MD4_CTX *ctx, const unsigned char *src, const int len );
static VOID (WINAPI *pMD4Final)( MD4_CTX *ctx );
static int (WINAPI *pSystemFunction007)(const UNICODE_STRING *, LPBYTE);
typedef int (WINAPI *md4hashfunc)(LPVOID, const LPBYTE, LPBYTE);
fnMD4Init pMD4Init;
fnMD4Update pMD4Update;
fnMD4Final pMD4Final;
fnSystemFunction007 pSystemFunction007;
md4hashfunc pSystemFunction010;
md4hashfunc pSystemFunction011;
static md4hashfunc pSystemFunction010;
static md4hashfunc pSystemFunction011;
#define ctxcmp( a, b ) memcmp( a, b, FIELD_OFFSET( MD4_CTX, in ) )
@ -149,16 +145,16 @@ START_TEST(crypt_md4)
module = GetModuleHandleA( "advapi32.dll" );
pMD4Init = (fnMD4Init)GetProcAddress( module, "MD4Init" );
pMD4Update = (fnMD4Update)GetProcAddress( module, "MD4Update" );
pMD4Final = (fnMD4Final)GetProcAddress( module, "MD4Final" );
pMD4Init = (void *)GetProcAddress( module, "MD4Init" );
pMD4Update = (void *)GetProcAddress( module, "MD4Update" );
pMD4Final = (void *)GetProcAddress( module, "MD4Final" );
if (pMD4Init && pMD4Update && pMD4Final)
test_md4_ctx();
else
win_skip("MD4Init and/or MD4Update and/or MD4Final are not available\n");
pSystemFunction007 = (fnSystemFunction007)GetProcAddress( module, "SystemFunction007" );
pSystemFunction007 = (void *)GetProcAddress( module, "SystemFunction007" );
if (pSystemFunction007)
test_SystemFunction007();
else

View file

@ -33,13 +33,9 @@ typedef struct
unsigned char digest[16];
} MD5_CTX;
typedef VOID (WINAPI *fnMD5Init)( MD5_CTX *ctx );
typedef VOID (WINAPI *fnMD5Update)( MD5_CTX *ctx, const unsigned char *src, const int len );
typedef VOID (WINAPI *fnMD5Final)( MD5_CTX *ctx );
fnMD5Init pMD5Init;
fnMD5Update pMD5Update;
fnMD5Final pMD5Final;
static VOID (WINAPI *pMD5Init)( MD5_CTX *ctx );
static VOID (WINAPI *pMD5Update)( MD5_CTX *ctx, const unsigned char *src, const int len );
static VOID (WINAPI *pMD5Final)( MD5_CTX *ctx );
#define ctxcmp( a, b ) memcmp( a, b, FIELD_OFFSET( MD5_CTX, in ) )
@ -79,9 +75,9 @@ static void test_md5_ctx(void)
module = GetModuleHandleA("advapi32.dll");
pMD5Init = (fnMD5Init)GetProcAddress( module, "MD5Init" );
pMD5Update = (fnMD5Update)GetProcAddress( module, "MD5Update" );
pMD5Final = (fnMD5Final)GetProcAddress( module, "MD5Final" );
pMD5Init = (void *)GetProcAddress( module, "MD5Init" );
pMD5Update = (void *)GetProcAddress( module, "MD5Update" );
pMD5Final = (void *)GetProcAddress( module, "MD5Final" );
if (!pMD5Init || !pMD5Update || !pMD5Final)
{

View file

@ -633,7 +633,7 @@ static BOOL create_new_eventlog(void)
HKEY key, eventkey;
BOOL bret = FALSE;
LONG lret;
int i;
DWORD i;
/* First create our eventlog */
lret = RegOpenKeyA(HKEY_LOCAL_MACHINE, eventlogsvc, &key);
@ -711,7 +711,7 @@ static void test_readwrite(void)
DWORD sidsize, count;
BOOL ret, sidavailable;
BOOL on_vista = FALSE; /* Used to indicate Vista, W2K8 or Win7 */
int i;
DWORD i;
char *localcomputer = NULL;
DWORD size;
@ -826,21 +826,24 @@ static void test_readwrite(void)
ret = ReportEvent(handle, read_write[i].evt_type, read_write[i].evt_cat,
read_write[i].evt_id, run_sidtests ? user : NULL,
read_write[i].evt_numstrings, 0, read_write[i].evt_strings, NULL);
ok(ret, "Expected ReportEvent success : %d\n", GetLastError());
count = 0xdeadbeef;
SetLastError(0xdeadbeef);
ret = GetNumberOfEventLogRecords(handle, &count);
ok(ret, "Expected success\n");
ok(ret, "Expected GetNumberOfEventLogRecords success : %d\n", GetLastError());
ok(count == (i + 1), "Expected %d records, got %d\n", i + 1, count);
oldest = 0xdeadbeef;
ret = GetOldestEventLogRecord(handle, &oldest);
ok(ret, "Expected success\n");
ok(ret, "Expected GetOldestEventLogRecord success : %d\n", GetLastError());
ok(oldest == 1 ||
(oldest > 1 && oldest != 0xdeadbeef), /* Vista SP1+, W2K8 and Win7 */
"Expected oldest to be 1 or higher, got %d\n", oldest);
if (oldest > 1 && oldest != 0xdeadbeef)
on_vista = TRUE;
SetLastError(0xdeadbeef);
if (i % 2)
ret = CloseEventLog(handle);
else
@ -1092,7 +1095,7 @@ static void cleanup_eventlog(void)
BOOL bret;
LONG lret;
HKEY key;
int i;
DWORD i;
char winesvc[MAX_PATH];
/* Delete the registry tree */
@ -1144,6 +1147,6 @@ START_TEST(eventlog)
{
test_readwrite();
test_autocreation();
cleanup_eventlog();
}
cleanup_eventlog();
}

View file

@ -249,13 +249,13 @@ static void test_LsaLookupNames2(void)
if (!pLsaLookupNames2)
{
win_skip("LsaLookupNames2 not avaliable\n");
win_skip("LsaLookupNames2 not available\n");
return;
}
if (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH)
{
skip("Non-english locale (skipping LsaLookupNames2 tests)\n");
skip("Non-English locale (skipping LsaLookupNames2 tests)\n");
return;
}

View file

@ -2,6 +2,7 @@
* Unit tests for registry functions
*
* Copyright (c) 2002 Alexandre Julliard
* Copyright (c) 2010 André Hentschel
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -28,6 +29,7 @@
#include "winreg.h"
#include "winsvc.h"
#include "winerror.h"
#include "aclapi.h"
static HKEY hkey_main;
static DWORD GLE;
@ -187,8 +189,7 @@ static void _test_hkey_main_Value_A(int line, LPCSTR name, LPCSTR string,
str_byte_len = (string ? lstrlenA(string) : 0) + 1;
lok(type == REG_SZ, "RegQueryValueExA/1 returned type %d\n", type);
lok(cbData == full_byte_len || cbData == str_byte_len /* Win9x */,
"cbData=%d instead of %d or %d\n", cbData, full_byte_len, str_byte_len);
lok(cbData == full_byte_len, "cbData=%d instead of %d or %d\n", cbData, full_byte_len, str_byte_len);
value = HeapAlloc(GetProcessHeap(), 0, cbData+1);
memset(value, 0xbd, cbData+1);
@ -199,8 +200,7 @@ static void _test_hkey_main_Value_A(int line, LPCSTR name, LPCSTR string,
if (!string)
{
/* When cbData == 0, RegQueryValueExA() should not modify the buffer */
lok(*value == 0xbd || (cbData == 1 && *value == '\0') /* Win9x */,
"RegQueryValueExA overflowed: cbData=%u *value=%02x\n", cbData, *value);
lok(*value == 0xbd, "RegQueryValueExA overflowed: cbData=%u *value=%02x\n", cbData, *value);
}
else
{
@ -301,19 +301,13 @@ static void test_set_value(void)
/* only REG_SZ is supported on NT*/
ret = RegSetValueA(hkey_main, NULL, REG_BINARY, string2A, sizeof(string2A));
/* 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);
ok(ret == ERROR_INVALID_PARAMETER, "got %d (expected ERROR_INVALID_PARAMETER)\n", ret);
ret = RegSetValueA(hkey_main, NULL, REG_EXPAND_SZ, string2A, sizeof(string2A));
/* 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);
ok(ret == ERROR_INVALID_PARAMETER, "got %d (expected ERROR_INVALID_PARAMETER)\n", ret);
ret = RegSetValueA(hkey_main, NULL, REG_MULTI_SZ, string2A, sizeof(string2A));
/* 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);
ok(ret == ERROR_INVALID_PARAMETER, "got %d (expected ERROR_INVALID_PARAMETER)\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.
@ -347,9 +341,6 @@ static void test_set_value(void)
test_hkey_main_Value_A(name2A, string2A, sizeof(string2A));
test_hkey_main_Value_W(name2W, string2W, sizeof(string2W));
/* 9x doesn't support W-calls, so don't test them then */
if(GLE == ERROR_CALL_NOT_IMPLEMENTED) return;
if (0)
{
/* Crashes on NT4, Windows 2000 and XP SP1 */
@ -462,7 +453,7 @@ static void test_enum_value(void)
res = RegEnumValueA( test_key, 0, value, &val_count, NULL, &type, (LPBYTE)data, &data_count );
ok( res == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %d\n", res );
ok( val_count == 2, "val_count set to %d\n", val_count );
ok( data_count == 7, "data_count set to %d instead of 7\n", data_count );
ok( data_count == 7 || broken( data_count == 8 ), "data_count set to %d instead of 7\n", data_count );
ok( type == REG_SZ, "type %d is not REG_SZ\n", type );
ok( !strcmp( value, "xxxxxxxxxx" ), "value set to '%s'\n", value );
ok( !strcmp( data, "xxxxxxxxxx" ), "data set to '%s'\n", data );
@ -475,14 +466,13 @@ static void test_enum_value(void)
strcpy( data, "xxxxxxxxxx" );
res = RegEnumValueA( test_key, 0, value, &val_count, NULL, &type, (LPBYTE)data, &data_count );
ok( res == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %d\n", res );
/* Win9x returns 2 as specified by MSDN but NT returns 3... */
ok( val_count == 2 || val_count == 3, "val_count set to %d\n", val_count );
ok( data_count == 7, "data_count set to %d instead of 7\n", data_count );
ok( val_count == 3, "val_count set to %d\n", val_count );
ok( data_count == 7 || broken( data_count == 8 ), "data_count set to %d instead of 7\n", data_count );
ok( type == REG_SZ, "type %d is not REG_SZ\n", type );
/* v5.1.2600.0 (XP Home and Professional) does not touch value or data in this case */
ok( !strcmp( value, "Te" ) || !strcmp( value, "xxxxxxxxxx" ),
"value set to '%s' instead of 'Te' or 'xxxxxxxxxx'\n", value );
ok( !strcmp( data, "foobar" ) || !strcmp( data, "xxxxxxx" ),
ok( !strcmp( data, "foobar" ) || !strcmp( data, "xxxxxxx" ) || broken( !strcmp( data, "xxxxxxxx" ) && data_count == 8 ),
"data set to '%s' instead of 'foobar' or 'xxxxxxx'\n", data );
/* overflow empty name */
@ -494,11 +484,11 @@ static void test_enum_value(void)
res = RegEnumValueA( test_key, 0, value, &val_count, NULL, &type, (LPBYTE)data, &data_count );
ok( res == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %d\n", res );
ok( val_count == 0, "val_count set to %d\n", val_count );
ok( data_count == 7, "data_count set to %d instead of 7\n", data_count );
ok( data_count == 7 || broken( data_count == 8 ), "data_count set to %d instead of 7\n", data_count );
ok( type == REG_SZ, "type %d is not REG_SZ\n", type );
ok( !strcmp( value, "xxxxxxxxxx" ), "value set to '%s'\n", value );
/* v5.1.2600.0 (XP Home and Professional) does not touch data in this case */
ok( !strcmp( data, "foobar" ) || !strcmp( data, "xxxxxxx" ),
ok( !strcmp( data, "foobar" ) || !strcmp( data, "xxxxxxx" ) || broken( !strcmp( data, "xxxxxxxx" ) && data_count == 8 ),
"data set to '%s' instead of 'foobar' or 'xxxxxxx'\n", data );
/* overflow data */
@ -617,20 +607,7 @@ static void test_query_value_ex(void)
size = 0xdeadbeef;
ret = RegQueryValueExA(HKEY_CLASSES_ROOT, "Nonexistent Value", NULL, &type, NULL, &size);
ok(ret == ERROR_FILE_NOT_FOUND, "expected ERROR_FILE_NOT_FOUND, got %d\n", ret);
/* the type parameter is cleared on Win9x, but is set to a random value on
* NT, so don't do that test there. The size parameter is left untouched on Win9x
* but cleared on NT+, this can be tested on all platforms.
*/
if (GetVersion() & 0x80000000)
{
ok(type == 0, "type should have been set to 0 instead of 0x%x\n", type);
ok(size == 0xdeadbeef, "size should have been left untouched (0xdeadbeef)\n");
}
else
{
trace("test_query_value_ex: type set to: 0x%08x\n", type);
ok(size == 0, "size should have been set to 0 instead of %d\n", size);
}
ok(size == 0, "size should have been set to 0 instead of %d\n", size);
size = sizeof(buffer);
ret = RegQueryValueExA(HKEY_CLASSES_ROOT, "Nonexistent Value", NULL, &type, buffer, &size);
@ -850,6 +827,14 @@ static void test_reg_open_key(void)
DWORD ret = 0;
HKEY hkResult = NULL;
HKEY hkPreserve = NULL;
HKEY hkRoot64 = NULL;
HKEY hkRoot32 = NULL;
BOOL bRet;
SID_IDENTIFIER_AUTHORITY sid_authority = {SECURITY_WORLD_SID_AUTHORITY};
PSID world_sid;
EXPLICIT_ACCESSA access;
PACL key_acl;
SECURITY_DESCRIPTOR *sd;
/* successful open */
ret = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Test", &hkResult);
@ -857,53 +842,48 @@ static void test_reg_open_key(void)
ok(hkResult != NULL, "expected hkResult != NULL\n");
hkPreserve = hkResult;
/* these tests fail on Win9x, but we want to be compatible with NT, so
* run them if we can */
if (!(GetVersion() & 0x80000000))
{
/* open same key twice */
ret = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Test", &hkResult);
ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
ok(hkResult != hkPreserve, "epxected hkResult != hkPreserve\n");
ok(hkResult != NULL, "hkResult != NULL\n");
RegCloseKey(hkResult);
/* open nonexistent key
* check that hkResult is set to NULL
*/
hkResult = hkPreserve;
ret = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Nonexistent", &hkResult);
ok(ret == ERROR_FILE_NOT_FOUND, "expected ERROR_FILE_NOT_FOUND, got %d\n", ret);
ok(hkResult == NULL, "expected hkResult == NULL\n");
/* open the same nonexistent key again to make sure the key wasn't created */
hkResult = hkPreserve;
ret = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Nonexistent", &hkResult);
ok(ret == ERROR_FILE_NOT_FOUND, "expected ERROR_FILE_NOT_FOUND, got %d\n", ret);
ok(hkResult == NULL, "expected hkResult == NULL\n");
/* send in NULL lpSubKey
* check that hkResult receives the value of hKey
*/
hkResult = hkPreserve;
ret = RegOpenKeyA(HKEY_CURRENT_USER, NULL, &hkResult);
ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
ok(hkResult == HKEY_CURRENT_USER, "expected hkResult == HKEY_CURRENT_USER\n");
/* send empty-string in lpSubKey */
hkResult = hkPreserve;
ret = RegOpenKeyA(HKEY_CURRENT_USER, "", &hkResult);
ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
ok(hkResult == HKEY_CURRENT_USER, "expected hkResult == HKEY_CURRENT_USER\n");
/* send in NULL lpSubKey and NULL hKey
* hkResult is set to NULL
*/
hkResult = hkPreserve;
ret = RegOpenKeyA(NULL, NULL, &hkResult);
ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
ok(hkResult == NULL, "expected hkResult == NULL\n");
}
/* open same key twice */
ret = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Test", &hkResult);
ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
ok(hkResult != hkPreserve, "expected hkResult != hkPreserve\n");
ok(hkResult != NULL, "hkResult != NULL\n");
RegCloseKey(hkResult);
/* open nonexistent key
* check that hkResult is set to NULL
*/
hkResult = hkPreserve;
ret = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Nonexistent", &hkResult);
ok(ret == ERROR_FILE_NOT_FOUND, "expected ERROR_FILE_NOT_FOUND, got %d\n", ret);
ok(hkResult == NULL, "expected hkResult == NULL\n");
/* open the same nonexistent key again to make sure the key wasn't created */
hkResult = hkPreserve;
ret = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Nonexistent", &hkResult);
ok(ret == ERROR_FILE_NOT_FOUND, "expected ERROR_FILE_NOT_FOUND, got %d\n", ret);
ok(hkResult == NULL, "expected hkResult == NULL\n");
/* send in NULL lpSubKey
* check that hkResult receives the value of hKey
*/
hkResult = hkPreserve;
ret = RegOpenKeyA(HKEY_CURRENT_USER, NULL, &hkResult);
ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
ok(hkResult == HKEY_CURRENT_USER, "expected hkResult == HKEY_CURRENT_USER\n");
/* send empty-string in lpSubKey */
hkResult = hkPreserve;
ret = RegOpenKeyA(HKEY_CURRENT_USER, "", &hkResult);
ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
ok(hkResult == HKEY_CURRENT_USER, "expected hkResult == HKEY_CURRENT_USER\n");
/* send in NULL lpSubKey and NULL hKey
* hkResult is set to NULL
*/
hkResult = hkPreserve;
ret = RegOpenKeyA(NULL, NULL, &hkResult);
ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
ok(hkResult == NULL, "expected hkResult == NULL\n");
/* only send NULL hKey
* the value of hkResult remains unchanged
@ -928,7 +908,6 @@ static void test_reg_open_key(void)
/* beginning backslash character */
ret = RegOpenKeyA(HKEY_CURRENT_USER, "\\Software\\Wine\\Test", &hkResult);
ok(ret == ERROR_BAD_PATHNAME || /* NT/2k/XP */
ret == ERROR_FILE_NOT_FOUND || /* Win9x,ME */
broken(ret == ERROR_SUCCESS), /* wow64 */
"expected ERROR_BAD_PATHNAME or ERROR_FILE_NOT_FOUND, got %d\n", ret);
if (!ret) RegCloseKey(hkResult);
@ -936,9 +915,8 @@ static void test_reg_open_key(void)
hkResult = NULL;
ret = RegOpenKeyExA(HKEY_CLASSES_ROOT, "\\clsid", 0, KEY_QUERY_VALUE, &hkResult);
ok(ret == ERROR_SUCCESS || /* 2k/XP */
ret == ERROR_BAD_PATHNAME || /* NT */
ret == ERROR_FILE_NOT_FOUND /* Win9x,ME */
, "expected ERROR_SUCCESS, ERROR_BAD_PATHNAME or ERROR_FILE_NOT_FOUND, got %d\n", ret);
ret == ERROR_BAD_PATHNAME, /* NT */
"expected ERROR_SUCCESS, ERROR_BAD_PATHNAME or ERROR_FILE_NOT_FOUND, got %d\n", ret);
RegCloseKey(hkResult);
/* WOW64 flags */
@ -953,12 +931,98 @@ static void test_reg_open_key(void)
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);
/* Try using WOW64 flags when opening a key with a DACL set to verify that
* the registry access check is performed correctly. Redirection isn't
* being tested, so the tests don't care about whether the process is
* running under WOW64. */
if (!pIsWow64Process)
{
win_skip("WOW64 flags are not recognized\n");
return;
}
ret = RegCreateKeyExA(HKEY_LOCAL_MACHINE, "Software\\Wine", 0, NULL, 0,
KEY_WOW64_32KEY | KEY_ALL_ACCESS, NULL, &hkRoot32, NULL);
ok(ret == ERROR_SUCCESS && hkRoot32 != NULL,
"RegCreateKeyEx with KEY_WOW64_32KEY failed (err=%u)\n", ret);
ret = RegCreateKeyExA(HKEY_LOCAL_MACHINE, "Software\\Wine", 0, NULL, 0,
KEY_WOW64_64KEY | KEY_ALL_ACCESS, NULL, &hkRoot64, NULL);
ok(ret == ERROR_SUCCESS && hkRoot64 != NULL,
"RegCreateKeyEx with KEY_WOW64_64KEY failed (err=%u)\n", ret);
bRet = AllocateAndInitializeSid(&sid_authority, 1, SECURITY_WORLD_RID,
0, 0, 0, 0, 0, 0, 0, &world_sid);
ok(bRet == TRUE,
"Expected AllocateAndInitializeSid to return TRUE, got %d, last error %u\n", bRet, GetLastError());
access.grfAccessPermissions = GENERIC_ALL | STANDARD_RIGHTS_ALL;
access.grfAccessMode = SET_ACCESS;
access.grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
access.Trustee.pMultipleTrustee = NULL;
access.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
access.Trustee.TrusteeForm = TRUSTEE_IS_SID;
access.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
access.Trustee.ptstrName = (char *)world_sid;
ret = SetEntriesInAclA(1, &access, NULL, &key_acl);
ok(ret == ERROR_SUCCESS,
"Expected SetEntriesInAclA to return ERROR_SUCCESS, got %u, last error %u\n", ret, GetLastError());
sd = HeapAlloc(GetProcessHeap(), 0, SECURITY_DESCRIPTOR_MIN_LENGTH);
bRet = InitializeSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION);
ok(bRet == TRUE,
"Expected InitializeSecurityDescriptor to return TRUE, got %d, last error %u\n", bRet, GetLastError());
bRet = SetSecurityDescriptorDacl(sd, TRUE, key_acl, FALSE);
ok(bRet == TRUE,
"Expected SetSecurityDescriptorDacl to return TRUE, got %d, last error %u\n", bRet, GetLastError());
/* The "sanctioned" methods of setting a registry ACL aren't implemented in Wine. */
bRet = SetKernelObjectSecurity(hkRoot64, DACL_SECURITY_INFORMATION, sd);
ok(bRet == TRUE,
"Expected SetKernelObjectSecurity to return TRUE, got %d, last error %u\n", bRet, GetLastError());
bRet = SetKernelObjectSecurity(hkRoot32, DACL_SECURITY_INFORMATION, sd);
ok(bRet == TRUE,
"Expected SetKernelObjectSecurity to return TRUE, got %d, last error %u\n", bRet, GetLastError());
hkResult = NULL;
ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\Wine", 0, KEY_WOW64_64KEY | KEY_READ, &hkResult);
ok(ret == ERROR_SUCCESS && hkResult != NULL,
"RegOpenKeyEx with KEY_WOW64_64KEY failed (err=%u)\n", ret);
RegCloseKey(hkResult);
hkResult = NULL;
ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\Wine", 0, KEY_WOW64_32KEY | KEY_READ, &hkResult);
ok(ret == ERROR_SUCCESS && hkResult != NULL,
"RegOpenKeyEx with KEY_WOW64_32KEY failed (err=%u)\n", ret);
RegCloseKey(hkResult);
HeapFree(GetProcessHeap(), 0, sd);
LocalFree(key_acl);
FreeSid(world_sid);
RegDeleteKeyA(hkRoot64, "");
RegCloseKey(hkRoot64);
RegDeleteKeyA(hkRoot32, "");
RegCloseKey(hkRoot32);
}
static void test_reg_create_key(void)
{
LONG ret;
HKEY hkey1, hkey2;
HKEY hkRoot64 = NULL;
HKEY hkRoot32 = NULL;
DWORD dwRet;
BOOL bRet;
SID_IDENTIFIER_AUTHORITY sid_authority = {SECURITY_WORLD_SID_AUTHORITY};
PSID world_sid;
EXPLICIT_ACCESSA access;
PACL key_acl;
SECURITY_DESCRIPTOR *sd;
ret = RegCreateKeyExA(hkey_main, "Subkey1", 0, NULL, 0, KEY_NOTIFY, NULL, &hkey1, NULL);
ok(!ret, "RegCreateKeyExA failed with error %d\n", ret);
/* should succeed: all versions of Windows ignore the access rights
@ -976,8 +1040,7 @@ static void test_reg_create_key(void)
ret = RegCreateKeyExA(hkey_main, "Volatile", 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey1, NULL);
ok(!ret, "RegCreateKeyExA failed with error %d\n", ret);
ret = RegCreateKeyExA(hkey1, "Subkey2", 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey2, NULL);
ok(ret == ERROR_CHILD_MUST_BE_VOLATILE || broken(!ret), /* win9x */
"RegCreateKeyExA failed with error %d\n", ret);
ok(ret == ERROR_CHILD_MUST_BE_VOLATILE, "RegCreateKeyExA failed with error %d\n", ret);
if (!ret) RegCloseKey( hkey2 );
ret = RegCreateKeyExA(hkey1, "Subkey2", 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey2, NULL);
ok(!ret, "RegCreateKeyExA failed with error %d\n", ret);
@ -1014,6 +1077,84 @@ static void test_reg_create_key(void)
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);
/* Try using WOW64 flags when opening a key with a DACL set to verify that
* the registry access check is performed correctly. Redirection isn't
* being tested, so the tests don't care about whether the process is
* running under WOW64. */
if (!pIsWow64Process)
{
win_skip("WOW64 flags are not recognized\n");
return;
}
ret = RegCreateKeyExA(HKEY_LOCAL_MACHINE, "Software\\Wine", 0, NULL, 0,
KEY_WOW64_32KEY | KEY_ALL_ACCESS, NULL, &hkRoot32, NULL);
ok(ret == ERROR_SUCCESS && hkRoot32 != NULL,
"RegCreateKeyEx with KEY_WOW64_32KEY failed (err=%d)\n", ret);
ret = RegCreateKeyExA(HKEY_LOCAL_MACHINE, "Software\\Wine", 0, NULL, 0,
KEY_WOW64_64KEY | KEY_ALL_ACCESS, NULL, &hkRoot64, NULL);
ok(ret == ERROR_SUCCESS && hkRoot64 != NULL,
"RegCreateKeyEx with KEY_WOW64_64KEY failed (err=%d)\n", ret);
bRet = AllocateAndInitializeSid(&sid_authority, 1, SECURITY_WORLD_RID,
0, 0, 0, 0, 0, 0, 0, &world_sid);
ok(bRet == TRUE,
"Expected AllocateAndInitializeSid to return TRUE, got %d, last error %u\n", bRet, GetLastError());
access.grfAccessPermissions = GENERIC_ALL | STANDARD_RIGHTS_ALL;
access.grfAccessMode = SET_ACCESS;
access.grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
access.Trustee.pMultipleTrustee = NULL;
access.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
access.Trustee.TrusteeForm = TRUSTEE_IS_SID;
access.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
access.Trustee.ptstrName = (char *)world_sid;
dwRet = SetEntriesInAclA(1, &access, NULL, &key_acl);
ok(ret == ERROR_SUCCESS,
"Expected SetEntriesInAclA to return ERROR_SUCCESS, got %u, last error %u\n", dwRet, GetLastError());
sd = HeapAlloc(GetProcessHeap(), 0, SECURITY_DESCRIPTOR_MIN_LENGTH);
bRet = InitializeSecurityDescriptor(sd, SECURITY_DESCRIPTOR_REVISION);
ok(bRet == TRUE,
"Expected InitializeSecurityDescriptor to return TRUE, got %d, last error %u\n", bRet, GetLastError());
bRet = SetSecurityDescriptorDacl(sd, TRUE, key_acl, FALSE);
ok(bRet == TRUE,
"Expected SetSecurityDescriptorDacl to return TRUE, got %d, last error %u\n", bRet, GetLastError());
/* The "sanctioned" methods of setting a registry ACL aren't implemented in Wine. */
bRet = SetKernelObjectSecurity(hkRoot64, DACL_SECURITY_INFORMATION, sd);
ok(bRet == TRUE,
"Expected SetKernelObjectSecurity to return TRUE, got %d, last error %u\n", bRet, GetLastError());
bRet = SetKernelObjectSecurity(hkRoot32, DACL_SECURITY_INFORMATION, sd);
ok(bRet == TRUE,
"Expected SetKernelObjectSecurity to return TRUE, got %d, last error %u\n", bRet, GetLastError());
hkey1 = NULL;
ret = RegCreateKeyExA(HKEY_LOCAL_MACHINE, "Software\\Wine", 0, NULL, 0,
KEY_WOW64_64KEY | KEY_READ, NULL, &hkey1, NULL);
ok(ret == ERROR_SUCCESS && hkey1 != NULL,
"RegOpenKeyEx with KEY_WOW64_64KEY failed (err=%u)\n", ret);
RegCloseKey(hkey1);
hkey1 = NULL;
ret = RegCreateKeyExA(HKEY_LOCAL_MACHINE, "Software\\Wine", 0, NULL, 0,
KEY_WOW64_32KEY | KEY_READ, NULL, &hkey1, NULL);
ok(ret == ERROR_SUCCESS && hkey1 != NULL,
"RegOpenKeyEx with KEY_WOW64_32KEY failed (err=%u)\n", ret);
RegCloseKey(hkey1);
HeapFree(GetProcessHeap(), 0, sd);
LocalFree(key_acl);
FreeSid(world_sid);
RegDeleteKeyA(hkRoot64, "");
RegCloseKey(hkRoot64);
RegDeleteKeyA(hkRoot32, "");
RegCloseKey(hkRoot32);
}
static void test_reg_close_key(void)
@ -1025,6 +1166,7 @@ static void test_reg_close_key(void)
* hkHandle remains changed after call to RegCloseKey
*/
ret = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Test", &hkHandle);
ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
ret = RegCloseKey(hkHandle);
ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
@ -1335,62 +1477,58 @@ static void test_string_termination(void)
ret = RegQueryValueExA(subkey, "stringtest", NULL, NULL, buffer, &outsize);
ok(ret == ERROR_MORE_DATA, "RegQueryValueExA returned: %d\n", ret);
/* Off-by-two RegSetValueExA -> no trailing '\0', except on Win9x */
/* Off-by-two RegSetValueExA -> no trailing '\0' */
insize=sizeof(string)-2;
ret = RegSetValueExA(subkey, "stringtest", 0, REG_SZ, (BYTE*)string, insize);
ok(ret == ERROR_SUCCESS, "RegSetValueExA failed: %d\n", ret);
outsize=0;
ret = RegQueryValueExA(subkey, "stringtest", NULL, NULL, NULL, &outsize);
ok(ret == ERROR_SUCCESS, "RegQueryValueExA failed: %d\n", ret);
ok(outsize == insize || broken(outsize == sizeof(string)) /* Win9x */,
"wrong size %u != %u\n", outsize, insize);
ok(outsize == insize, "wrong size %u != %u\n", outsize, insize);
if (outsize == insize)
{
/* RegQueryValueExA may return a string with no trailing '\0' */
outsize=insize;
memset(buffer, 0xbd, sizeof(buffer));
ret = RegQueryValueExA(subkey, "stringtest", NULL, NULL, buffer, &outsize);
ok(ret == ERROR_SUCCESS, "RegQueryValueExA failed: %d\n", ret);
ok(outsize == insize, "wrong size: %u != %u\n", outsize, insize);
ok(memcmp(buffer, string, outsize) == 0, "bad string: %s/%u != %s\n",
wine_debugstr_an((char*)buffer, outsize), outsize, string);
ok(buffer[insize] == 0xbd, "buffer overflow at %u %02x\n", insize, buffer[insize]);
/* RegQueryValueExA may return a string with no trailing '\0' */
outsize=insize;
memset(buffer, 0xbd, sizeof(buffer));
ret = RegQueryValueExA(subkey, "stringtest", NULL, NULL, buffer, &outsize);
ok(ret == ERROR_SUCCESS, "RegQueryValueExA failed: %d\n", ret);
ok(outsize == insize, "wrong size: %u != %u\n", outsize, insize);
ok(memcmp(buffer, string, outsize) == 0, "bad string: %s/%u != %s\n",
wine_debugstr_an((char*)buffer, outsize), outsize, string);
ok(buffer[insize] == 0xbd, "buffer overflow at %u %02x\n", insize, buffer[insize]);
/* RegQueryValueExA adds a trailing '\0' if there is room */
outsize=insize+1;
memset(buffer, 0xbd, sizeof(buffer));
ret = RegQueryValueExA(subkey, "stringtest", NULL, NULL, buffer, &outsize);
ok(ret == ERROR_SUCCESS, "RegQueryValueExA failed: %d\n", ret);
ok(outsize == insize, "wrong size: %u != %u\n", outsize, insize);
ok(memcmp(buffer, string, outsize) == 0, "bad string: %s/%u != %s\n",
wine_debugstr_an((char*)buffer, outsize), outsize, string);
ok(buffer[insize] == 0, "buffer overflow at %u %02x\n", insize, buffer[insize]);
/* RegQueryValueExA adds a trailing '\0' if there is room */
outsize=insize+1;
memset(buffer, 0xbd, sizeof(buffer));
ret = RegQueryValueExA(subkey, "stringtest", NULL, NULL, buffer, &outsize);
ok(ret == ERROR_SUCCESS, "RegQueryValueExA failed: %d\n", ret);
ok(outsize == insize, "wrong size: %u != %u\n", outsize, insize);
ok(memcmp(buffer, string, outsize) == 0, "bad string: %s/%u != %s\n",
wine_debugstr_an((char*)buffer, outsize), outsize, string);
ok(buffer[insize] == 0, "buffer overflow at %u %02x\n", insize, buffer[insize]);
/* RegEnumValueA may return a string with no trailing '\0' */
outsize=insize;
memset(buffer, 0xbd, sizeof(buffer));
nsize=sizeof(name);
ret = RegEnumValueA(subkey, 0, name, &nsize, NULL, NULL, buffer, &outsize);
ok(ret == ERROR_SUCCESS, "RegEnumValueA failed: %d\n", ret);
ok(strcmp(name, "stringtest") == 0, "wrong name: %s\n", name);
ok(outsize == insize, "wrong size: %u != %u\n", outsize, insize);
ok(memcmp(buffer, string, outsize) == 0, "bad string: %s/%u != %s\n",
wine_debugstr_an((char*)buffer, outsize), outsize, string);
ok(buffer[insize] == 0xbd, "buffer overflow at %u %02x\n", insize, buffer[insize]);
/* RegEnumValueA may return a string with no trailing '\0' */
outsize=insize;
memset(buffer, 0xbd, sizeof(buffer));
nsize=sizeof(name);
ret = RegEnumValueA(subkey, 0, name, &nsize, NULL, NULL, buffer, &outsize);
ok(ret == ERROR_SUCCESS, "RegEnumValueA failed: %d\n", ret);
ok(strcmp(name, "stringtest") == 0, "wrong name: %s\n", name);
ok(outsize == insize, "wrong size: %u != %u\n", outsize, insize);
ok(memcmp(buffer, string, outsize) == 0, "bad string: %s/%u != %s\n",
wine_debugstr_an((char*)buffer, outsize), outsize, string);
ok(buffer[insize] == 0xbd, "buffer overflow at %u %02x\n", insize, buffer[insize]);
/* RegEnumValueA adds a trailing '\0' if there is room */
outsize=insize+1;
memset(buffer, 0xbd, sizeof(buffer));
nsize=sizeof(name);
ret = RegEnumValueA(subkey, 0, name, &nsize, NULL, NULL, buffer, &outsize);
ok(ret == ERROR_SUCCESS, "RegEnumValueA failed: %d\n", ret);
ok(strcmp(name, "stringtest") == 0, "wrong name: %s\n", name);
ok(outsize == insize, "wrong size: %u != %u\n", outsize, insize);
ok(memcmp(buffer, string, outsize) == 0, "bad string: %s/%u != %s\n",
wine_debugstr_an((char*)buffer, outsize), outsize, string);
ok(buffer[insize] == 0, "buffer overflow at %u %02x\n", insize, buffer[insize]);
}
/* RegEnumValueA adds a trailing '\0' if there is room */
outsize=insize+1;
memset(buffer, 0xbd, sizeof(buffer));
nsize=sizeof(name);
ret = RegEnumValueA(subkey, 0, name, &nsize, NULL, NULL, buffer, &outsize);
ok(ret == ERROR_SUCCESS, "RegEnumValueA failed: %d\n", ret);
ok(strcmp(name, "stringtest") == 0, "wrong name: %s\n", name);
ok(outsize == insize, "wrong size: %u != %u\n", outsize, insize);
ok(memcmp(buffer, string, outsize) == 0, "bad string: %s/%u != %s\n",
wine_debugstr_an((char*)buffer, outsize), outsize, string);
ok(buffer[insize] == 0, "buffer overflow at %u %02x\n", insize, buffer[insize]);
RegDeleteKeyA(subkey, "");
RegCloseKey(subkey);
@ -1912,6 +2050,269 @@ static void test_redirection(void)
RegCloseKey( root64 );
}
static void test_classesroot(void)
{
HKEY hkey, hklm, hkcr, hkeysub1, hklmsub1, hkcrsub1, hklmsub2, hkcrsub2;
DWORD size = 8;
DWORD type = REG_SZ;
static CHAR buffer[8];
LONG res;
/* create a key in the user's classes */
if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Classes\\WineTestCls", &hkey ))
{
delete_key( hkey );
RegCloseKey( hkey );
}
res = RegCreateKeyExA( HKEY_CURRENT_USER, "Software\\Classes\\WineTestCls", 0, NULL, 0,
KEY_QUERY_VALUE|KEY_SET_VALUE, NULL, &hkey, NULL );
if (res == ERROR_ACCESS_DENIED)
{
skip("not enough privileges to add a user class\n");
return;
}
/* try to open that key in hkcr */
res = RegOpenKeyExA( HKEY_CLASSES_ROOT, "WineTestCls", 0,
KEY_QUERY_VALUE|KEY_SET_VALUE, &hkcr );
todo_wine ok(res == ERROR_SUCCESS ||
broken(res == ERROR_FILE_NOT_FOUND /* WinNT */),
"test key not found in hkcr: %d\n", res);
if (res)
{
skip("HKCR key merging not supported\n");
delete_key( hkey );
RegCloseKey( hkey );
return;
}
/* set a value in user's classes */
res = RegSetValueExA(hkey, "val1", 0, REG_SZ, (const BYTE *)"user", sizeof("user"));
ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%x\n", res, GetLastError());
/* try to find the value in hkcr */
res = RegQueryValueExA(hkcr, "val1", NULL, &type, (LPBYTE)buffer, &size);
ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d\n", res);
ok(!strcmp( buffer, "user" ), "value set to '%s'\n", buffer );
/* modify the value in hkcr */
res = RegSetValueExA(hkcr, "val1", 0, REG_SZ, (const BYTE *)"hkcr", sizeof("hkcr"));
ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%x\n", res, GetLastError());
/* check if the value is also modified in user's classes */
res = RegQueryValueExA(hkey, "val1", NULL, &type, (LPBYTE)buffer, &size);
ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d, GLE=%x\n", res, GetLastError());
ok(!strcmp( buffer, "hkcr" ), "value set to '%s'\n", buffer );
/* set a value in hkcr */
res = RegSetValueExA(hkcr, "val0", 0, REG_SZ, (const BYTE *)"hkcr", sizeof("hkcr"));
ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%x\n", res, GetLastError());
/* try to find the value in user's classes */
res = RegQueryValueExA(hkcr, "val0", NULL, &type, (LPBYTE)buffer, &size);
ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d\n", res);
ok(!strcmp( buffer, "hkcr" ), "value set to '%s'\n", buffer );
/* modify the value in user's classes */
res = RegSetValueExA(hkcr, "val0", 0, REG_SZ, (const BYTE *)"user", sizeof("user"));
ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%x\n", res, GetLastError());
/* check if the value is also modified in hkcr */
res = RegQueryValueExA(hkey, "val0", NULL, &type, (LPBYTE)buffer, &size);
ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d, GLE=%x\n", res, GetLastError());
ok(!strcmp( buffer, "user" ), "value set to '%s'\n", buffer );
/* cleanup */
delete_key( hkey );
delete_key( hkcr );
RegCloseKey( hkey );
RegCloseKey( hkcr );
/* create a key in the hklm classes */
if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Classes\\WineTestCls", &hklm ))
{
delete_key( hklm );
RegCloseKey( hklm );
}
res = RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Classes\\WineTestCls", 0, NULL, REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS, NULL, &hklm, NULL );
if (res == ERROR_ACCESS_DENIED)
{
skip("not enough privileges to add a system class\n");
return;
}
/* try to open that key in hkcr */
res = RegOpenKeyExA( HKEY_CLASSES_ROOT, "WineTestCls", 0,
KEY_QUERY_VALUE|KEY_SET_VALUE, &hkcr );
ok(res == ERROR_SUCCESS,
"test key not found in hkcr: %d\n", res);
if (res)
{
delete_key( hklm );
RegCloseKey( hklm );
return;
}
/* set a value in hklm classes */
res = RegSetValueExA(hklm, "val2", 0, REG_SZ, (const BYTE *)"hklm", sizeof("hklm"));
ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%x\n", res, GetLastError());
/* try to find the value in hkcr */
res = RegQueryValueExA(hkcr, "val2", NULL, &type, (LPBYTE)buffer, &size);
ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d\n", res);
ok(!strcmp( buffer, "hklm" ), "value set to '%s'\n", buffer );
/* modify the value in hkcr */
res = RegSetValueExA(hkcr, "val2", 0, REG_SZ, (const BYTE *)"hkcr", sizeof("hkcr"));
ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%x\n", res, GetLastError());
/* check that the value is not modified in hklm classes */
res = RegQueryValueExA(hklm, "val2", NULL, &type, (LPBYTE)buffer, &size);
ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d, GLE=%x\n", res, GetLastError());
ok(!strcmp( buffer, "hklm" ), "value set to '%s'\n", buffer );
if (RegCreateKeyExA( HKEY_CURRENT_USER, "Software\\Classes\\WineTestCls", 0, NULL, 0,
KEY_QUERY_VALUE|KEY_SET_VALUE, NULL, &hkey, NULL )) return;
/* try to open that key in hkcr */
res = RegOpenKeyExA( HKEY_CLASSES_ROOT, "WineTestCls", 0,
KEY_QUERY_VALUE|KEY_SET_VALUE, &hkcr );
ok(res == ERROR_SUCCESS,
"test key not found in hkcr: %d\n", res);
/* set a value in user's classes */
res = RegSetValueExA(hkey, "val2", 0, REG_SZ, (const BYTE *)"user", sizeof("user"));
ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%x\n", res, GetLastError());
/* try to find the value in hkcr */
res = RegQueryValueExA(hkcr, "val2", NULL, &type, (LPBYTE)buffer, &size);
ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d\n", res);
ok(!strcmp( buffer, "user" ), "value set to '%s'\n", buffer );
/* modify the value in hklm */
res = RegSetValueExA(hklm, "val2", 0, REG_SZ, (const BYTE *)"hklm", sizeof("hklm"));
ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%x\n", res, GetLastError());
/* check that the value is not overwritten in hkcr or user's classes */
res = RegQueryValueExA(hkcr, "val2", NULL, &type, (LPBYTE)buffer, &size);
ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d\n", res);
ok(!strcmp( buffer, "user" ), "value set to '%s'\n", buffer );
res = RegQueryValueExA(hkey, "val2", NULL, &type, (LPBYTE)buffer, &size);
ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d, GLE=%x\n", res, GetLastError());
ok(!strcmp( buffer, "user" ), "value set to '%s'\n", buffer );
/* modify the value in hkcr */
res = RegSetValueExA(hkcr, "val2", 0, REG_SZ, (const BYTE *)"hkcr", sizeof("hkcr"));
ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%x\n", res, GetLastError());
/* check that the value is overwritten in hklm and user's classes */
res = RegQueryValueExA(hkcr, "val2", NULL, &type, (LPBYTE)buffer, &size);
ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d\n", res);
ok(!strcmp( buffer, "hkcr" ), "value set to '%s'\n", buffer );
res = RegQueryValueExA(hkey, "val2", NULL, &type, (LPBYTE)buffer, &size);
ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d, GLE=%x\n", res, GetLastError());
ok(!strcmp( buffer, "hkcr" ), "value set to '%s'\n", buffer );
/* create a subkey in hklm */
if (RegCreateKeyExA( hklm, "subkey1", 0, NULL, 0,
KEY_QUERY_VALUE|KEY_SET_VALUE, NULL, &hklmsub1, NULL )) return;
/* try to open that subkey in hkcr */
res = RegOpenKeyExA( hkcr, "subkey1", 0, KEY_QUERY_VALUE|KEY_SET_VALUE, &hkcrsub1 );
ok(res == ERROR_SUCCESS, "test key not found in hkcr: %d\n", res);
/* set a value in hklm classes */
res = RegSetValueExA(hklmsub1, "subval1", 0, REG_SZ, (const BYTE *)"hklm", sizeof("hklm"));
ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%x\n", res, GetLastError());
/* try to find the value in hkcr */
res = RegQueryValueExA(hkcrsub1, "subval1", NULL, &type, (LPBYTE)buffer, &size);
ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d\n", res);
ok(!strcmp( buffer, "hklm" ), "value set to '%s'\n", buffer );
/* modify the value in hkcr */
res = RegSetValueExA(hkcrsub1, "subval1", 0, REG_SZ, (const BYTE *)"hkcr", sizeof("hkcr"));
ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%x\n", res, GetLastError());
/* check that the value is modified in hklm classes */
res = RegQueryValueExA(hklmsub1, "subval1", NULL, &type, (LPBYTE)buffer, &size);
ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d, GLE=%x\n", res, GetLastError());
ok(!strcmp( buffer, "hkcr" ), "value set to '%s'\n", buffer );
/* create a subkey in user's classes */
if (RegCreateKeyExA( hkey, "subkey1", 0, NULL, 0,
KEY_QUERY_VALUE|KEY_SET_VALUE, NULL, &hkeysub1, NULL )) return;
/* set a value in user's classes */
res = RegSetValueExA(hkeysub1, "subval1", 0, REG_SZ, (const BYTE *)"user", sizeof("user"));
ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%x\n", res, GetLastError());
/* try to find the value in hkcr */
res = RegQueryValueExA(hkcrsub1, "subval1", NULL, &type, (LPBYTE)buffer, &size);
ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d\n", res);
ok(!strcmp( buffer, "user" ), "value set to '%s'\n", buffer );
/* modify the value in hklm */
res = RegSetValueExA(hklmsub1, "subval1", 0, REG_SZ, (const BYTE *)"hklm", sizeof("hklm"));
ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%x\n", res, GetLastError());
/* check that the value is not overwritten in hkcr or user's classes */
res = RegQueryValueExA(hkcrsub1, "subval1", NULL, &type, (LPBYTE)buffer, &size);
ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d\n", res);
ok(!strcmp( buffer, "user" ), "value set to '%s'\n", buffer );
res = RegQueryValueExA(hkeysub1, "subval1", NULL, &type, (LPBYTE)buffer, &size);
ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d, GLE=%x\n", res, GetLastError());
ok(!strcmp( buffer, "user" ), "value set to '%s'\n", buffer );
/* modify the value in hkcr */
res = RegSetValueExA(hkcrsub1, "subval1", 0, REG_SZ, (const BYTE *)"hkcr", sizeof("hkcr"));
ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%x\n", res, GetLastError());
/* check that the value is not overwritten in hklm, but in user's classes */
res = RegQueryValueExA(hklmsub1, "subval1", NULL, &type, (LPBYTE)buffer, &size);
ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d\n", res);
ok(!strcmp( buffer, "hklm" ), "value set to '%s'\n", buffer );
res = RegQueryValueExA(hkeysub1, "subval1", NULL, &type, (LPBYTE)buffer, &size);
ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d, GLE=%x\n", res, GetLastError());
ok(!strcmp( buffer, "hkcr" ), "value set to '%s'\n", buffer );
/* new subkey in hkcr */
if (RegCreateKeyExA( hkcr, "subkey2", 0, NULL, 0,
KEY_QUERY_VALUE|KEY_SET_VALUE, NULL, &hkcrsub2, NULL )) return;
res = RegSetValueExA(hkcrsub2, "subval1", 0, REG_SZ, (const BYTE *)"hkcr", sizeof("hkcr"));
ok(res == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%x\n", res, GetLastError());
/* try to open that new subkey in user's classes and hklm */
res = RegOpenKeyExA( hkey, "subkey2", 0, KEY_QUERY_VALUE|KEY_SET_VALUE, &hklmsub2 );
ok(res != ERROR_SUCCESS, "test key found in user's classes: %d\n", res);
hklmsub2 = 0;
res = RegOpenKeyExA( hklm, "subkey2", 0, KEY_QUERY_VALUE|KEY_SET_VALUE, &hklmsub2 );
ok(res == ERROR_SUCCESS, "test key not found in hklm: %d\n", res);
/* check that the value is present in hklm */
res = RegQueryValueExA(hklmsub2, "subval1", NULL, &type, (LPBYTE)buffer, &size);
ok(res == ERROR_SUCCESS, "RegQueryValueExA failed: %d\n", res);
ok(!strcmp( buffer, "hkcr" ), "value set to '%s'\n", buffer );
/* final cleanup */
delete_key( hkey );
delete_key( hklm );
delete_key( hkcr );
delete_key( hkeysub1 );
delete_key( hklmsub1 );
delete_key( hkcrsub1 );
delete_key( hklmsub2 );
delete_key( hkcrsub2 );
RegCloseKey( hkey );
RegCloseKey( hklm );
RegCloseKey( hkcr );
RegCloseKey( hkeysub1 );
RegCloseKey( hklmsub1 );
RegCloseKey( hkcrsub1 );
RegCloseKey( hklmsub2 );
RegCloseKey( hkcrsub2 );
}
static void test_deleted_key(void)
{
HKEY hkey, hkey2;
@ -2004,6 +2405,7 @@ START_TEST(registry)
test_string_termination();
test_symlinks();
test_redirection();
test_classesroot();
/* SaveKey/LoadKey require the SE_BACKUP_NAME privilege to be set */
if (set_privileges(SE_BACKUP_NAME, TRUE) &&

File diff suppressed because it is too large Load diff

View file

@ -34,6 +34,7 @@
//static const CHAR spooler[] = "Spooler"; /* Should be available on all platforms */
static const CHAR spooler[] = "Eventlog"; /* All platform except reactos :-/ */
static const CHAR* selfname;
static BOOL (WINAPI *pChangeServiceConfig2A)(SC_HANDLE,DWORD,LPVOID);
static BOOL (WINAPI *pEnumServicesStatusExA)(SC_HANDLE, SC_ENUM_TYPE, DWORD,
@ -336,6 +337,13 @@ static void test_create_delete_svc(void)
ok(!svc_handle1, "Expected failure\n");
ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
/* Test if ServiceType can be a combined one for drivers */
SetLastError(0xdeadbeef);
svc_handle1 = CreateServiceA(scm_handle, servicename, NULL, 0, SERVICE_KERNEL_DRIVER | SERVICE_FILE_SYSTEM_DRIVER,
SERVICE_BOOT_START, 0, pathname, NULL, NULL, NULL, NULL, NULL);
ok(!svc_handle1, "Expected failure\n");
ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
/* The service already exists (check first, just in case) */
svc_handle1 = OpenServiceA(scm_handle, spooler, GENERIC_READ);
if (svc_handle1)
@ -602,7 +610,7 @@ static void test_get_displayname(void)
ok(ret, "Expected success, got error %u\n", GetLastError());
/* Test that shows that if the buffersize is enough, it's not changed */
ok(displaysize == tempsize * 2, "Expected no change for the needed buffer size\n");
ok(lstrlen(displayname) == tempsize/2,
ok(strlen(displayname) == tempsize/2,
"Expected the buffer to be twice the length of the string\n") ;
/* Do the buffer(size) tests also for GetServiceDisplayNameW */
@ -672,7 +680,7 @@ static void test_get_displayname(void)
displaysize = -1;
ret = GetServiceDisplayNameA(scm_handle, servicename, NULL, &displaysize);
ok(!ret, "Expected failure\n");
ok(displaysize == lstrlen(servicename) * 2,
ok(displaysize == strlen(servicename) * 2,
"Expected the displaysize to be twice the size of the servicename\n");
ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
"Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
@ -857,7 +865,7 @@ static void test_get_servicekeyname(void)
ok(ret, "Expected success, got error %u\n", GetLastError());
if (ret)
{
ok(lstrlen(servicename) == tempsize/2,
ok(strlen(servicename) == tempsize/2,
"Expected the buffer to be twice the length of the string\n") ;
ok(!lstrcmpi(servicename, spooler), "Expected %s, got %s\n", spooler, servicename);
ok(servicesize == (tempsize * 2),
@ -871,7 +879,7 @@ static void test_get_servicekeyname(void)
ok(ret, "Expected success, got error %u\n", GetLastError());
if (ret)
{
ok(lstrlen(servicename) == tempsize/2,
ok(strlen(servicename) == tempsize/2,
"Expected the buffer to be twice the length of the string\n") ;
ok(servicesize == lstrlenW(servicenameW),
"Expected servicesize not to change if buffer not insufficient\n") ;
@ -919,7 +927,6 @@ static void test_query_svc(void)
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());
@ -943,6 +950,12 @@ static void test_query_svc(void)
CloseServiceHandle(svc_handle);
/* More or less the same tests for QueryServiceStatusEx */
if (!pQueryServiceStatusEx)
{
win_skip( "QueryServiceStatusEx not available\n" );
CloseServiceHandle(scm_handle);
return;
}
/* Open service with not enough rights to query the status */
svc_handle = OpenServiceA(scm_handle, spooler, STANDARD_RIGHTS_READ);
@ -951,7 +964,6 @@ static void test_query_svc(void)
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());
@ -961,8 +973,8 @@ static void test_query_svc(void)
/* Only info level is correct. It looks like the buffer/size is checked second */
SetLastError(0xdeadbeef);
ret = pQueryServiceStatusEx(NULL, 0, NULL, 0, &needed);
/* NT4 and Wine check the handle first */
ret = pQueryServiceStatusEx(NULL, SC_STATUS_PROCESS_INFO, NULL, 0, &needed);
/* NT4 checks the handle first */
if (GetLastError() != ERROR_INVALID_HANDLE)
{
ok(!ret, "Expected failure\n");
@ -976,7 +988,7 @@ static void test_query_svc(void)
statusproc = HeapAlloc(GetProcessHeap(), 0, sizeof(SERVICE_STATUS_PROCESS));
bufsize = needed;
SetLastError(0xdeadbeef);
ret = pQueryServiceStatusEx(NULL, 0, (BYTE*)statusproc, bufsize, &needed);
ret = pQueryServiceStatusEx(NULL, SC_STATUS_PROCESS_INFO, (BYTE*)statusproc, bufsize, &needed);
ok(!ret, "Expected failure\n");
ok(GetLastError() == ERROR_INVALID_HANDLE,
"Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
@ -984,25 +996,22 @@ static void test_query_svc(void)
/* Correct handle and info level */
SetLastError(0xdeadbeef);
ret = pQueryServiceStatusEx(svc_handle, 0, NULL, 0, &needed);
ret = pQueryServiceStatusEx(svc_handle, SC_STATUS_PROCESS_INFO, 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);
ret = pQueryServiceStatusEx(svc_handle, SC_STATUS_PROCESS_INFO, (BYTE*)statusproc, bufsize, &needed);
ok(!ret, "Expected failure\n");
ok(GetLastError() == ERROR_ACCESS_DENIED,
"Expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
@ -1016,7 +1025,7 @@ static void test_query_svc(void)
statusproc = HeapAlloc(GetProcessHeap(), 0, sizeof(SERVICE_STATUS_PROCESS));
bufsize = sizeof(SERVICE_STATUS_PROCESS);
SetLastError(0xdeadbeef);
ret = pQueryServiceStatusEx(svc_handle, 0, (BYTE*)statusproc, bufsize, &needed);
ret = pQueryServiceStatusEx(svc_handle, SC_STATUS_PROCESS_INFO, (BYTE*)statusproc, bufsize, &needed);
ok(ret, "Expected success, got error %u\n", GetLastError());
if (statusproc->dwCurrentState == SERVICE_RUNNING)
ok(statusproc->dwProcessId != 0,
@ -1039,14 +1048,20 @@ static void test_enum_svc(void)
DWORD tempneeded, tempreturned, missing;
DWORD servicecountactive, servicecountinactive;
ENUM_SERVICE_STATUS *services;
ENUM_SERVICE_STATUSW *servicesW;
ENUM_SERVICE_STATUS_PROCESS *exservices;
INT i;
UINT 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());
SetLastError(0xdeadbeef);
ret = EnumServicesStatusW(NULL, 1, 0, NULL, 0, NULL, NULL, NULL);
ok(!ret, "Expected failure\n");
ok(GetLastError() == ERROR_INVALID_HANDLE,
"Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
@ -1057,7 +1072,13 @@ static void test_enum_svc(void)
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());
SetLastError(0xdeadbeef);
ret = EnumServicesStatusW(scm_handle, 1, 0, NULL, 0, NULL, NULL, NULL);
ok(!ret, "Expected failure\n");
ok(GetLastError() == ERROR_INVALID_ADDRESS ||
GetLastError() == ERROR_INVALID_PARAMETER /* NT4 */,
"Unexpected last error %d\n", GetLastError());
@ -1068,7 +1089,15 @@ static void test_enum_svc(void)
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());
returned = 0xdeadbeef;
SetLastError(0xdeadbeef);
ret = EnumServicesStatusW(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");
ok(GetLastError() == ERROR_INVALID_ADDRESS ||
GetLastError() == ERROR_INVALID_PARAMETER /* NT4 */,
"Unexpected last error %d\n", GetLastError());
@ -1080,7 +1109,16 @@ static void test_enum_svc(void)
ok(!ret, "Expected failure\n");
ok(needed == 0xdeadbeef || broken(needed != 0xdeadbeef), /* nt4 */
"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());
needed = 0xdeadbeef;
SetLastError(0xdeadbeef);
ret = EnumServicesStatusW(scm_handle, 0, 0, NULL, 0, &needed, NULL, NULL);
ok(!ret, "Expected failure\n");
ok(needed == 0xdeadbeef || broken(needed != 0xdeadbeef), /* nt4 */
"Expected no change to the needed buffer variable\n");
ok(GetLastError() == ERROR_INVALID_ADDRESS ||
GetLastError() == ERROR_INVALID_PARAMETER /* NT4 */,
"Unexpected last error %d\n", GetLastError());
@ -1091,59 +1129,93 @@ static void test_enum_svc(void)
SetLastError(0xdeadbeef);
ret = EnumServicesStatusA(scm_handle, 0, 0, NULL, 0, &needed, &returned, NULL);
ok(!ret, "Expected failure\n");
todo_wine
{
ok(needed == 0 || broken(needed != 0), /* nt4 */
"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 = EnumServicesStatusW(scm_handle, 0, 0, NULL, 0, &needed, &returned, NULL);
ok(!ret, "Expected failure\n");
ok(needed == 0 || broken(needed != 0), /* nt4 */
"Expected needed buffer size to be set to 0, got %d\n", needed);
ok(returned == 0 || broken(returned != 0), /* nt4 */
"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 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 || broken(needed != 0), /* nt4 */
"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);
ret = EnumServicesStatusW(scm_handle, SERVICE_WIN32, 0, NULL, 0, &needed, &returned, NULL);
ok(!ret, "Expected failure\n");
ok(needed == 0 || broken(needed != 0), /* nt4 */
"Expected needed buffer size to be set to 0, got %d\n", needed);
ok(returned == 0 || broken(returned != 0), /* nt4 */
"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 */
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 || broken(needed != 0), /* nt4 */
"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());
}
needed = 0xdeadbeef;
returned = 0xdeadbeef;
SetLastError(0xdeadbeef);
ret = EnumServicesStatusW(scm_handle, 0, SERVICE_STATE_ALL, NULL, 0, &needed, &returned, NULL);
ok(!ret, "Expected failure\n");
ok(needed == 0 || broken(needed != 0), /* nt4 */
"Expected needed buffer size to be set to 0, got %d\n", needed);
ok(returned == 0 || broken(returned != 0), /* nt4 */
"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);
ret = EnumServicesStatusA(scm_handle, SERVICE_WIN32, SERVICE_STATE_ALL, NULL, 0, &needed, &returned, NULL);
ok(!ret, "Expected failure\n");
todo_wine
{
ok(needed == 0 || broken(needed != 0), /* nt4 */
"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());
needed = 0xdeadbeef;
returned = 0xdeadbeef;
SetLastError(0xdeadbeef);
ret = EnumServicesStatusW(scm_handle, SERVICE_WIN32, SERVICE_STATE_ALL, NULL, 0, &needed, &returned, NULL);
ok(!ret, "Expected failure\n");
ok(needed == 0 || broken(needed != 0), /* nt4 */
"Expected needed buffer size to be set to 0, got %d\n", needed);
ok(returned == 0 || broken(returned != 0), /* nt4 */
"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());
@ -1155,22 +1227,24 @@ static void test_enum_svc(void)
needed = 0xdeadbeef;
returned = 0xdeadbeef;
SetLastError(0xdeadbeef);
ret = EnumServicesStatusA(scm_handle, SERVICE_WIN32, SERVICE_STATE_ALL, NULL, 0,
&needed, &returned, NULL);
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());
}
/* Test to show we get the same needed buffer size for the W-call */
neededW = 0xdeadbeef;
ret = EnumServicesStatusW(scm_handle, SERVICE_WIN32, SERVICE_STATE_ALL, NULL, 0,
&neededW, &returnedW, NULL);
returnedW = 0xdeadbeef;
SetLastError(0xdeadbeef);
ret = EnumServicesStatusW(scm_handle, SERVICE_WIN32, SERVICE_STATE_ALL, NULL, 0, &neededW, &returnedW, NULL);
ok(!ret, "Expected failure\n");
ok(neededW != 0xdeadbeef && neededW > 0, "Expected the needed buffer size for this one service\n");
ok(neededW == needed, "Expected needed buffersize to be the same for A- and W-calls\n");
ok(returnedW == 0, "Expected no service returned, got %d\n", returnedW);
ok(GetLastError() == ERROR_MORE_DATA,
"Expected ERROR_MORE_DATA, got %d\n", GetLastError());
/* Store the needed bytes */
tempneeded = needed;
@ -1183,17 +1257,26 @@ static void test_enum_svc(void)
SetLastError(0xdeadbeef);
ret = EnumServicesStatusA(scm_handle, SERVICE_WIN32, SERVICE_STATE_ALL,
services, bufsize, &needed, &returned, NULL);
todo_wine
{
ok(ret, "Expected success, got error %u\n", GetLastError());
ok(needed == 0, "Expected needed buffer to be 0 as we are done\n");
ok(returned != 0xdeadbeef && returned > 0, "Expected some returned services\n");
}
HeapFree(GetProcessHeap(), 0, services);
/* Store the number of returned services */
tempreturned = returned;
servicesW = HeapAlloc(GetProcessHeap(), 0, neededW);
bufsize = neededW;
neededW = 0xdeadbeef;
returnedW = 0xdeadbeef;
SetLastError(0xdeadbeef);
ret = EnumServicesStatusW(scm_handle, SERVICE_WIN32, SERVICE_STATE_ALL,
servicesW, bufsize, &neededW, &returnedW, NULL);
ok(ret, "Expected success, got error %u\n", GetLastError());
ok(neededW == 0, "Expected needed buffer to be 0 as we are done\n");
ok(returnedW != 0xdeadbeef && returnedW > 0, "Expected some returned services\n");
HeapFree(GetProcessHeap(), 0, servicesW);
/* Allocate less than the needed bytes and don't specify a resume handle */
services = HeapAlloc(GetProcessHeap(), 0, tempneeded);
bufsize = (tempreturned - 1) * sizeof(ENUM_SERVICE_STATUS);
@ -1203,13 +1286,10 @@ static void test_enum_svc(void)
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, "Expected fewer services to be returned\n");
ok(GetLastError() == ERROR_MORE_DATA,
"Expected ERROR_MORE_DATA, got %d\n", GetLastError());
}
/* Allocate less than the needed bytes, this time with a correct resume handle */
bufsize = (tempreturned - 1) * sizeof(ENUM_SERVICE_STATUS);
@ -1220,14 +1300,11 @@ static void test_enum_svc(void)
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, "Expected fewer services to be returned\n");
ok(resume, "Expected a resume handle\n");
todo_wine ok(resume, "Expected a resume handle\n");
ok(GetLastError() == ERROR_MORE_DATA,
"Expected ERROR_MORE_DATA, got %d\n", GetLastError());
}
/* Fetch the missing services but pass a bigger buffer size */
missing = tempreturned - returned;
@ -1237,12 +1314,9 @@ static void test_enum_svc(void)
SetLastError(0xdeadbeef);
ret = EnumServicesStatusA(scm_handle, SERVICE_WIN32, SERVICE_STATE_ALL,
services, bufsize, &needed, &returned, &resume);
todo_wine
{
ok(ret, "Expected success, got error %u\n", GetLastError());
ok(needed == 0, "Expected needed buffer to be 0 as we are done\n");
ok(returned == missing, "Expected %u services to be returned\n", missing);
}
ok(resume == 0, "Expected the resume handle to be 0\n");
HeapFree(GetProcessHeap(), 0, services);
@ -1287,7 +1361,6 @@ static void test_enum_svc(void)
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");
@ -1324,26 +1397,22 @@ static void test_enum_svc(void)
}
HeapFree(GetProcessHeap(), 0, services);
#if 0
/* These tests don't make sense on a real system because no test can determine
* how many service should be active or inactive.
*/
todo_wine
{
ok(servicecountactive == 0, "Active services mismatch %u\n", servicecountactive);
ok(servicecountinactive == 0, "Inactive services mismatch %u\n", servicecountinactive);
}
#endif
CloseServiceHandle(scm_handle);
/* More or less the same for EnumServicesStatusExA */
if (!pEnumServicesStatusExA)
{
win_skip( "EnumServicesStatusExA not available\n" );
return;
}
/* 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());
@ -1351,7 +1420,6 @@ static void test_enum_svc(void)
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());
@ -1362,7 +1430,6 @@ static void test_enum_svc(void)
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());
@ -1374,7 +1441,6 @@ static void test_enum_svc(void)
ok(!ret, "Expected failure\n");
ok(needed == 0xdeadbeef || broken(needed != 0xdeadbeef), /* nt4 */
"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());
@ -1384,13 +1450,10 @@ static void test_enum_svc(void)
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;
@ -1399,13 +1462,10 @@ static void test_enum_svc(void)
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 || broken(needed != 0), /* nt4 */
"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;
@ -1415,13 +1475,10 @@ static void test_enum_svc(void)
&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 || broken(needed != 0), /* nt4 */
"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;
@ -1431,13 +1488,10 @@ static void test_enum_svc(void)
&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 || broken(needed != 0), /* nt4 */
"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;
@ -1447,13 +1501,10 @@ static void test_enum_svc(void)
&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 || broken(needed != 0), /* nt4 */
"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;
@ -1462,7 +1513,6 @@ static void test_enum_svc(void)
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 || broken(needed != 0), /* nt4 */
"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);
@ -1478,7 +1528,6 @@ static void test_enum_svc(void)
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 || broken(needed != 0), /* nt4 */
"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);
@ -1497,12 +1546,9 @@ static void test_enum_svc(void)
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 "").
@ -1516,17 +1562,15 @@ static void test_enum_svc(void)
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());
}
/* Test to show we get the same needed buffer size for the W-call */
neededW = 0xdeadbeef;
ret = pEnumServicesStatusExW(scm_handle, 0, SERVICE_WIN32, SERVICE_STATE_ALL,
NULL, 0, &neededW, &returnedW, NULL, NULL);
ok(!ret, "Expected failure\n");
ok(neededW == needed, "Expected needed buffersize to be the same for A- and W-calls\n");
/* Store the needed bytes */
@ -1540,12 +1584,9 @@ static void test_enum_svc(void)
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, got error %u\n", GetLastError());
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");
}
HeapFree(GetProcessHeap(), 0, exservices);
/* Store the number of returned services */
@ -1560,13 +1601,10 @@ static void test_enum_svc(void)
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, "Expected fewer services to be returned\n");
ok(GetLastError() == ERROR_MORE_DATA,
"Expected ERROR_MORE_DATA, got %d\n", GetLastError());
}
/* Allocate less than the needed bytes, this time with a correct resume handle */
bufsize = (tempreturned - 1) * sizeof(ENUM_SERVICE_STATUS);
@ -1577,14 +1615,11 @@ static void test_enum_svc(void)
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, "Expected fewer services to be returned\n");
ok(resume, "Expected a resume handle\n");
todo_wine ok(resume, "Expected a resume handle\n");
ok(GetLastError() == ERROR_MORE_DATA,
"Expected ERROR_MORE_DATA, got %d\n", GetLastError());
}
/* Fetch that last service but pass a bigger buffer size */
missing = tempreturned - returned;
@ -1594,11 +1629,8 @@ static void test_enum_svc(void)
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, got error %u\n", GetLastError());
ok(needed == 0, "Expected needed buffer to be 0 as we are done\n");
}
ok(returned == missing, "Expected %u services to be returned\n", missing);
ok(resume == 0, "Expected the resume handle to be 0\n");
HeapFree(GetProcessHeap(), 0, exservices);
@ -1638,18 +1670,19 @@ static void test_enum_svc(void)
"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);
ret = pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32 | SERVICE_DRIVER,
SERVICE_STATE_ALL, NULL, 0, &needed, &returned, NULL, NULL);
ok(!ret, "Expected failure\n");
exservices = HeapAlloc(GetProcessHeap(), 0, needed);
pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32 | SERVICE_DRIVER,
SERVICE_STATE_ALL, (BYTE*)exservices, needed, &needed, &returned, NULL, NULL);
ret = pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32 | SERVICE_DRIVER,
SERVICE_STATE_ALL, (BYTE*)exservices, needed, &needed, &returned, NULL, NULL);
ok(ret, "Expected success %u\n", GetLastError());
/* 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");
@ -1687,13 +1720,8 @@ static void test_enum_svc(void)
}
HeapFree(GetProcessHeap(), 0, exservices);
#if 0
/* These tests don't make sense on a real system because no test can determine
* how many service should be active or inactive.
*/
ok(servicecountactive == 0, "Active services mismatch %u\n", servicecountactive);
ok(servicecountinactive == 0, "Inactive services mismatch %u\n", servicecountinactive);
#endif
CloseServiceHandle(scm_handle);
}
@ -1822,9 +1850,10 @@ static void test_sequence(void)
}
ok(!strcmp(config->lpServiceStartName, localsystem), "Expected 'LocalSystem', got '%s'\n", config->lpServiceStartName);
ok(!strcmp(config->lpDisplayName, displayname), "Expected '%s', got '%s'\n", displayname, config->lpDisplayName);
ok(ChangeServiceConfigA(svc_handle, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, SERVICE_ERROR_NORMAL, NULL, "TestGroup2", NULL, NULL, NULL, NULL, displayname2),
"ChangeServiceConfig failed (err=%d)\n", GetLastError());
ret = ChangeServiceConfigA(svc_handle, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, SERVICE_ERROR_NORMAL, NULL, "TestGroup2",
NULL, NULL, NULL, NULL, displayname2);
ok(ret, "ChangeServiceConfig failed (err=%d)\n", GetLastError());
QueryServiceConfigA(svc_handle, NULL, 0, &needed);
config = HeapReAlloc(GetProcessHeap(), 0, config, needed);
@ -2037,6 +2066,141 @@ cleanup:
CloseServiceHandle(scm_handle);
}
static DWORD try_start_stop(SC_HANDLE svc_handle, const char* name, DWORD is_nt4)
{
BOOL ret;
DWORD le1, le2;
SERVICE_STATUS status;
ret = StartServiceA(svc_handle, 0, NULL);
le1 = GetLastError();
ok(!ret, "%s: StartServiceA() should have failed\n", name);
if (pQueryServiceStatusEx)
{
DWORD needed;
SERVICE_STATUS_PROCESS statusproc;
ret = pQueryServiceStatusEx(svc_handle, SC_STATUS_PROCESS_INFO, (BYTE*)&statusproc, sizeof(statusproc), &needed);
ok(ret, "%s: QueryServiceStatusEx() failed le=%u\n", name, GetLastError());
ok(statusproc.dwCurrentState == SERVICE_STOPPED, "%s: should be stopped state=%x\n", name, statusproc.dwCurrentState);
ok(statusproc.dwProcessId == 0, "%s: ProcessId should be 0 instead of %x\n", name, statusproc.dwProcessId);
}
ret = StartServiceA(svc_handle, 0, NULL);
le2 = GetLastError();
ok(!ret, "%s: StartServiceA() should have failed\n", name);
ok(le2 == le1, "%s: the second try should yield the same error: %u != %u\n", name, le1, le2);
status.dwCurrentState = 0xdeadbeef;
ret = ControlService(svc_handle, SERVICE_CONTROL_STOP, &status);
le2 = GetLastError();
ok(!ret, "%s: ControlService() should have failed\n", name);
ok(le2 == ERROR_SERVICE_NOT_ACTIVE, "%s: %d != ERROR_SERVICE_NOT_ACTIVE\n", name, le2);
ok(status.dwCurrentState == SERVICE_STOPPED ||
broken(is_nt4), /* NT4 returns a random value */
"%s: should be stopped state=%x\n", name, status.dwCurrentState);
return le1;
}
static void test_start_stop(void)
{
BOOL ret;
SC_HANDLE scm_handle, svc_handle;
DWORD le, is_nt4;
static const char servicename[] = "Winetest";
char cmd[MAX_PATH+20];
const char* displayname;
SetLastError(0xdeadbeef);
scm_handle = OpenSCManagerA(NULL, NULL, GENERIC_ALL);
if (!scm_handle)
{
if(GetLastError() == ERROR_ACCESS_DENIED)
skip("Not enough rights to get a handle to the manager\n");
else
ok(FALSE, "Could not get a handle to the manager: %d\n", GetLastError());
return;
}
/* Detect NT4 */
svc_handle = OpenServiceA(scm_handle, NULL, GENERIC_READ);
is_nt4=(svc_handle == NULL && GetLastError() == ERROR_INVALID_PARAMETER);
/* Do some cleanup in case a previous run crashed */
svc_handle = OpenServiceA(scm_handle, servicename, GENERIC_ALL);
if (svc_handle)
{
DeleteService(svc_handle);
CloseServiceHandle(svc_handle);
}
/* Create a dummy disabled service */
sprintf(cmd, "\"%s\" service exit", selfname);
displayname = "Winetest Disabled Service";
svc_handle = CreateServiceA(scm_handle, servicename, displayname,
GENERIC_ALL, SERVICE_INTERACTIVE_PROCESS | SERVICE_WIN32_OWN_PROCESS,
SERVICE_DISABLED, SERVICE_ERROR_IGNORE, cmd, NULL,
NULL, NULL, NULL, NULL);
if (!svc_handle)
{
if(GetLastError() == ERROR_ACCESS_DENIED)
skip("Not enough rights to create the service\n");
else
ok(FALSE, "Could not create the service: %d\n", GetLastError());
goto cleanup;
}
le = try_start_stop(svc_handle, displayname, is_nt4);
ok(le == ERROR_SERVICE_DISABLED, "%d != ERROR_SERVICE_DISABLED\n", le);
/* Then one with a bad path */
displayname = "Winetest Bad Path";
ret = ChangeServiceConfigA(svc_handle, SERVICE_NO_CHANGE, SERVICE_DEMAND_START, SERVICE_NO_CHANGE, "c:\\no_such_file.exe", NULL, NULL, NULL, NULL, NULL, displayname);
ok(ret, "ChangeServiceConfig() failed le=%u\n", GetLastError());
try_start_stop(svc_handle, displayname, is_nt4);
if (is_nt4)
{
/* NT4 does not detect when a service fails to start and uses an
* insanely long timeout: 120s. So skip the rest of the tests.
*/
win_skip("Skip some service start/stop tests on NT4\n");
goto cleanup;
}
/* Again with a process that exits right away */
displayname = "Winetest Exit Service";
ret = ChangeServiceConfigA(svc_handle, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, cmd, NULL, NULL, NULL, NULL, NULL, displayname);
ok(ret, "ChangeServiceConfig() failed le=%u\n", GetLastError());
le = try_start_stop(svc_handle, displayname, is_nt4);
ok(le == ERROR_SERVICE_REQUEST_TIMEOUT, "%d != ERROR_SERVICE_REQUEST_TIMEOUT\n", le);
/* And finally with a service that plays dead, forcing a timeout.
* This time we will put no quotes. That should work too, even if there are
* spaces in the path.
*/
sprintf(cmd, "%s service sleep", selfname);
displayname = "Winetest Sleep Service";
ret = ChangeServiceConfigA(svc_handle, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, cmd, NULL, NULL, NULL, NULL, NULL, displayname);
ok(ret, "ChangeServiceConfig() failed le=%u\n", GetLastError());
le = try_start_stop(svc_handle, displayname, is_nt4);
ok(le == ERROR_SERVICE_REQUEST_TIMEOUT, "%d != ERROR_SERVICE_REQUEST_TIMEOUT\n", le);
cleanup:
if (svc_handle)
{
DeleteService(svc_handle);
CloseServiceHandle(svc_handle);
}
/* Wait a while. The following test does a CreateService again */
Sleep(1000);
CloseServiceHandle(scm_handle);
}
static void test_refcount(void)
{
SC_HANDLE scm_handle, svc_handle1, svc_handle2, svc_handle3, svc_handle4, svc_handle5;
@ -2140,6 +2304,19 @@ static void test_refcount(void)
START_TEST(service)
{
SC_HANDLE scm_handle;
int myARGC;
char** myARGV;
myARGC = winetest_get_mainargs(&myARGV);
selfname = myARGV[0];
if (myARGC >= 3)
{
if (strcmp(myARGV[2], "sleep") == 0)
/* Cause a service startup timeout */
Sleep(90000);
/* then, or if myARGV[2] == "exit", just exit */
return;
}
/* Bail out if we are on win98 */
SetLastError(0xdeadbeef);
@ -2166,6 +2343,7 @@ START_TEST(service)
/* Test the creation, querying and deletion of a service */
test_sequence();
test_queryconfig2();
test_start_stop();
/* The main reason for this test is to check if any refcounting is used
* and what the rules are
*/