Update of Winetests of non autosynched Dlls. Done by Kamil Horniceck
authorDaniel Reimer <reimer.daniel@freenet.de>
Fri, 9 May 2008 17:35:45 +0000 (17:35 +0000)
committerDaniel Reimer <reimer.daniel@freenet.de>
Fri, 9 May 2008 17:35:45 +0000 (17:35 +0000)
svn path=/trunk/; revision=33397

139 files changed:
rostests/winetests/advapi32/advapi32.rbuild
rostests/winetests/advapi32/cred.c [new file with mode: 0644]
rostests/winetests/advapi32/crypt.c
rostests/winetests/advapi32/crypt_lmhash.c
rostests/winetests/advapi32/crypt_md4.c
rostests/winetests/advapi32/crypt_md5.c
rostests/winetests/advapi32/crypt_sha.c
rostests/winetests/advapi32/lsa.c [new file with mode: 0644]
rostests/winetests/advapi32/registry.c
rostests/winetests/advapi32/security.c
rostests/winetests/advapi32/service.c [new file with mode: 0644]
rostests/winetests/advapi32/testlist.c
rostests/winetests/advpack/advpack.rbuild
rostests/winetests/advpack/files.c
rostests/winetests/browseui/autocomplete.c
rostests/winetests/browseui/browseui.rbuild
rostests/winetests/cabinet/cabinet.rbuild
rostests/winetests/cabinet/fdi.c
rostests/winetests/comcat/comcat.rbuild
rostests/winetests/comctl32/comctl32.rbuild
rostests/winetests/comctl32/dpa.c
rostests/winetests/comctl32/header.c
rostests/winetests/comctl32/listview.c
rostests/winetests/comctl32/monthcal.c
rostests/winetests/comctl32/mru.c
rostests/winetests/comdlg32/comdlg32.rbuild
rostests/winetests/comdlg32/printdlg.c
rostests/winetests/directory.rbuild
rostests/winetests/gdi32/bitmap.c
rostests/winetests/gdi32/brush.c
rostests/winetests/gdi32/clipping.c
rostests/winetests/gdi32/dc.c
rostests/winetests/gdi32/font.c
rostests/winetests/gdi32/gdi32.rbuild
rostests/winetests/gdi32/gdiobj.c
rostests/winetests/gdi32/generated.c [new file with mode: 0644]
rostests/winetests/gdi32/icm.c [new file with mode: 0644]
rostests/winetests/gdi32/mapping.c
rostests/winetests/gdi32/metafile.c
rostests/winetests/gdi32/palette.c
rostests/winetests/gdi32/path.c [new file with mode: 0644]
rostests/winetests/gdi32/pen.c [new file with mode: 0644]
rostests/winetests/gdi32/testlist.c
rostests/winetests/hlink/hlink.rbuild
rostests/winetests/icmp/icmp.rbuild
rostests/winetests/imm32/imm32.c
rostests/winetests/imm32/imm32.rbuild
rostests/winetests/kernel32/actctx.c [new file with mode: 0644]
rostests/winetests/kernel32/alloc.c
rostests/winetests/kernel32/atom.c
rostests/winetests/kernel32/change.c
rostests/winetests/kernel32/codepage.c
rostests/winetests/kernel32/comm.c
rostests/winetests/kernel32/console.c
rostests/winetests/kernel32/debugger.c [new file with mode: 0644]
rostests/winetests/kernel32/directory.c
rostests/winetests/kernel32/drive.c
rostests/winetests/kernel32/environ.c
rostests/winetests/kernel32/file.c
rostests/winetests/kernel32/format_msg.c
rostests/winetests/kernel32/heap.c
rostests/winetests/kernel32/kernel32.rbuild
rostests/winetests/kernel32/loader.c [new file with mode: 0644]
rostests/winetests/kernel32/locale.c
rostests/winetests/kernel32/mailslot.c
rostests/winetests/kernel32/module.c
rostests/winetests/kernel32/path.c
rostests/winetests/kernel32/pipe.c
rostests/winetests/kernel32/process.c
rostests/winetests/kernel32/profile.c
rostests/winetests/kernel32/resource.c [new file with mode: 0644]
rostests/winetests/kernel32/resource.rc [new file with mode: 0644]
rostests/winetests/kernel32/sync.c
rostests/winetests/kernel32/testlist.c
rostests/winetests/kernel32/thread.c
rostests/winetests/kernel32/time.c
rostests/winetests/kernel32/timer.c
rostests/winetests/kernel32/toolhelp.c [new file with mode: 0644]
rostests/winetests/kernel32/version.c [new file with mode: 0644]
rostests/winetests/kernel32/virtual.c
rostests/winetests/kernel32/volume.c [new file with mode: 0644]
rostests/winetests/lz32/lz32.rbuild
rostests/winetests/mapi32/mapi32.rbuild
rostests/winetests/mlang/mlang.rbuild
rostests/winetests/msacm32/msacm.c [new file with mode: 0644]
rostests/winetests/msacm32/msacm32.rbuild [new file with mode: 0644]
rostests/winetests/msacm32/testlist.c [new file with mode: 0644]
rostests/winetests/mshtml/htmldoc.c
rostests/winetests/mshtml/mshtml.rbuild
rostests/winetests/msi/db.c
rostests/winetests/msi/format.c
rostests/winetests/msi/install.c
rostests/winetests/msi/msi.c
rostests/winetests/msi/msi.rbuild
rostests/winetests/msi/package.c
rostests/winetests/msi/source.c
rostests/winetests/msvcrt/cpp.c
rostests/winetests/msvcrt/file.c
rostests/winetests/msvcrt/heap.c
rostests/winetests/msvcrt/msvcrt.rbuild
rostests/winetests/msvcrt/printf.c
rostests/winetests/msvcrt/time.c
rostests/winetests/shell32/generated.c
rostests/winetests/shell32/shell32.rbuild
rostests/winetests/shell32/shelllink.c
rostests/winetests/shell32/shellpath.c
rostests/winetests/shell32/shfldr_netplaces.c [new file with mode: 0644]
rostests/winetests/shell32/shlexec.c
rostests/winetests/shell32/shlfileop.c
rostests/winetests/shell32/shlfolder.c
rostests/winetests/shell32/systray.c
rostests/winetests/shell32/testlist.c
rostests/winetests/user32/broadcast.c [new file with mode: 0644]
rostests/winetests/user32/class.c
rostests/winetests/user32/clipboard.c
rostests/winetests/user32/combo.c [new file with mode: 0644]
rostests/winetests/user32/cursoricon.c [new file with mode: 0644]
rostests/winetests/user32/dce.c
rostests/winetests/user32/dde.c
rostests/winetests/user32/dialog.c
rostests/winetests/user32/edit.c
rostests/winetests/user32/generated.c [new file with mode: 0644]
rostests/winetests/user32/input.c
rostests/winetests/user32/listbox.c
rostests/winetests/user32/menu.c
rostests/winetests/user32/monitor.c
rostests/winetests/user32/msg.c
rostests/winetests/user32/resource.c
rostests/winetests/user32/resource.rc
rostests/winetests/user32/scroll.c [new file with mode: 0644]
rostests/winetests/user32/static.c [new file with mode: 0644]
rostests/winetests/user32/sysparams.c
rostests/winetests/user32/test_mono.bmp [new file with mode: 0644]
rostests/winetests/user32/testlist.c
rostests/winetests/user32/text.c
rostests/winetests/user32/user32.rbuild
rostests/winetests/user32/win.c
rostests/winetests/user32/winstation.c
rostests/winetests/user32/wsprintf.c

index a77f327..7a056f0 100644 (file)
@@ -1,10 +1,24 @@
+<?xml version="1.0"?>
+<!DOCTYPE module SYSTEM "../../../tools/rbuild/project.dtd">
+<group>
 <module name="advapi32_winetest" type="win32cui" installbase="bin" installname="advapi32_winetest.exe" allowwarnings="true">
     <include base="advapi32_winetest">.</include>
     <define name="__USE_W32API" />
     <library>advapi32</library>
     <library>kernel32</library>
     <library>ntdll</library>
+    <library>uuid</library>
+    <library>ole32</library>
+    <file>cred.c</file>
+    <file>crypt.c</file>
+    <file>crypt_lmhash.c</file>
+    <file>crypt_md4.c</file>
+    <file>crypt_md5.c</file>
+    <file>crypt_sha.c</file>
+    <file>lsa.c</file>
     <file>registry.c</file>
     <file>security.c</file>
+    <file>service.c</file>
     <file>testlist.c</file>
 </module>
+</group>
diff --git a/rostests/winetests/advapi32/cred.c b/rostests/winetests/advapi32/cred.c
new file mode 100644 (file)
index 0000000..6d7b758
--- /dev/null
@@ -0,0 +1,305 @@
+/*
+ * Credential Function Tests
+ *
+ * Copyright 2007 Robert Shearman
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "wincred.h"
+
+#include "wine/test.h"
+
+static BOOL (WINAPI *pCredDeleteA)(LPCSTR,DWORD,DWORD);
+static BOOL (WINAPI *pCredEnumerateA)(LPCSTR,DWORD,DWORD *,PCREDENTIALA **);
+static VOID (WINAPI *pCredFree)(PVOID);
+static BOOL (WINAPI *pCredGetSessionTypes)(DWORD,LPDWORD);
+static BOOL (WINAPI *pCredReadA)(LPCSTR,DWORD,DWORD,PCREDENTIALA *);
+static BOOL (WINAPI *pCredRenameA)(LPCSTR,LPCSTR,DWORD,DWORD);
+static BOOL (WINAPI *pCredWriteA)(PCREDENTIALA,DWORD);
+
+#define TEST_TARGET_NAME  "credtest.winehq.org"
+#define TEST_TARGET_NAME2 "credtest2.winehq.org"
+static const WCHAR TEST_PASSWORD[] = {'p','4','$','$','w','0','r','d','!',0};
+
+static void test_CredReadA(void)
+{
+    BOOL ret;
+    PCREDENTIALA cred;
+
+    SetLastError(0xdeadbeef);
+    ret = pCredReadA(TEST_TARGET_NAME, -1, 0, &cred);
+    ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
+        "CredReadA should have failed with ERROR_INVALID_PARAMETER instead of %d\n",
+        GetLastError());
+
+    SetLastError(0xdeadbeef);
+    ret = pCredReadA(TEST_TARGET_NAME, CRED_TYPE_GENERIC, 0xdeadbeef, &cred);
+    ok(!ret && ( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER ),
+        "CredReadA should have failed with ERROR_INVALID_FLAGS or ERROR_INVALID_PARAMETER instead of %d\n",
+        GetLastError());
+
+    SetLastError(0xdeadbeef);
+    ret = pCredReadA(NULL, CRED_TYPE_GENERIC, 0, &cred);
+    ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
+        "CredReadA should have failed with ERROR_INVALID_PARAMETER instead of %d\n",
+        GetLastError());
+}
+
+static void test_CredWriteA(void)
+{
+    CREDENTIALA new_cred;
+    BOOL ret;
+
+    SetLastError(0xdeadbeef);
+    ret = pCredWriteA(NULL, 0);
+    ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
+        "CredWriteA should have failed with ERROR_INVALID_PARAMETER instead of %d\n",
+        GetLastError());
+
+    new_cred.Flags = 0;
+    new_cred.Type = CRED_TYPE_GENERIC;
+    new_cred.TargetName = NULL;
+    new_cred.Comment = (char *)"Comment";
+    new_cred.CredentialBlobSize = 0;
+    new_cred.CredentialBlob = NULL;
+    new_cred.Persist = CRED_PERSIST_ENTERPRISE;
+    new_cred.AttributeCount = 0;
+    new_cred.Attributes = NULL;
+    new_cred.TargetAlias = NULL;
+    new_cred.UserName = (char *)"winetest";
+
+    SetLastError(0xdeadbeef);
+    ret = pCredWriteA(&new_cred, 0);
+    ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
+        "CredWriteA should have failed with ERROR_INVALID_PARAMETER instead of %d\n",
+        GetLastError());
+
+    new_cred.TargetName = (char *)TEST_TARGET_NAME;
+    new_cred.Type = CRED_TYPE_DOMAIN_PASSWORD;
+
+    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());
+
+    new_cred.UserName = NULL;
+    SetLastError(0xdeadbeef);
+    ret = pCredWriteA(&new_cred, 0);
+    ok(!ret && GetLastError() == ERROR_BAD_USERNAME,
+        "CredWriteA with NULL username should have failed with ERROR_BAD_USERNAME instead of %d\n",
+        GetLastError());
+}
+
+static void test_CredDeleteA(void)
+{
+    BOOL ret;
+
+    SetLastError(0xdeadbeef);
+    ret = pCredDeleteA(TEST_TARGET_NAME, -1, 0);
+    ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
+        "CredDeleteA should have failed with ERROR_INVALID_PARAMETER instead of %d\n",
+        GetLastError());
+
+    SetLastError(0xdeadbeef);
+    ret = pCredDeleteA(TEST_TARGET_NAME, CRED_TYPE_GENERIC, 0xdeadbeef);
+    ok(!ret && ( GetLastError() == ERROR_INVALID_FLAGS || GetLastError() == ERROR_INVALID_PARAMETER /* Vista */ ),
+        "CredDeleteA should have failed with ERROR_INVALID_FLAGS or ERROR_INVALID_PARAMETER instead of %d\n",
+        GetLastError());
+}
+
+static void check_blob(int line, DWORD cred_type, PCREDENTIALA cred)
+{
+    if (cred_type == CRED_TYPE_DOMAIN_PASSWORD)
+    {
+        todo_wine
+        ok_(__FILE__, line)(cred->CredentialBlobSize == 0, "expected CredentialBlobSize of 0 but got %d\n", cred->CredentialBlobSize);
+        todo_wine
+        ok_(__FILE__, line)(!cred->CredentialBlob, "expected NULL credentials but got %p\n", cred->CredentialBlob);
+    }
+    else
+    {
+        DWORD size=sizeof(TEST_PASSWORD);
+        ok_(__FILE__, line)(cred->CredentialBlobSize == size, "expected CredentialBlobSize of %u but got %u\n", size, cred->CredentialBlobSize);
+        ok_(__FILE__, line)(cred->CredentialBlob != NULL, "CredentialBlob should be present\n");
+        if (cred->CredentialBlob)
+            ok_(__FILE__, line)(!memcmp(cred->CredentialBlob, TEST_PASSWORD, size), "wrong CredentialBlob\n");
+    }
+}
+
+static void test_generic(void)
+{
+    BOOL ret;
+    DWORD count, i;
+    PCREDENTIALA *creds;
+    CREDENTIALA new_cred;
+    PCREDENTIALA cred;
+    BOOL found = FALSE;
+
+    new_cred.Flags = 0;
+    new_cred.Type = CRED_TYPE_GENERIC;
+    new_cred.TargetName = (char *)TEST_TARGET_NAME;
+    new_cred.Comment = (char *)"Comment";
+    new_cred.CredentialBlobSize = sizeof(TEST_PASSWORD);
+    new_cred.CredentialBlob = (LPBYTE)TEST_PASSWORD;
+    new_cred.Persist = CRED_PERSIST_ENTERPRISE;
+    new_cred.AttributeCount = 0;
+    new_cred.Attributes = NULL;
+    new_cred.TargetAlias = NULL;
+    new_cred.UserName = (char *)"winetest";
+
+    ret = pCredWriteA(&new_cred, 0);
+    ok(ret, "CredWriteA failed with error %d\n", GetLastError());
+
+    ret = pCredEnumerateA(NULL, 0, &count, &creds);
+    ok(ret, "CredEnumerateA failed with error %d\n", GetLastError());
+
+    for (i = 0; i < count; i++)
+    {
+        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]->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]);
+            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;
+        }
+    }
+    pCredFree(creds);
+    ok(found, "credentials not found\n");
+
+    ret = pCredReadA(TEST_TARGET_NAME, CRED_TYPE_GENERIC, 0, &cred);
+    ok(ret, "CredReadA failed with error %d\n", GetLastError());
+    pCredFree(cred);
+
+    ret = pCredDeleteA(TEST_TARGET_NAME, CRED_TYPE_GENERIC, 0);
+    ok(ret, "CredDeleteA failed with error %d\n", GetLastError());
+}
+
+static void test_domain_password(DWORD cred_type)
+{
+    BOOL ret;
+    DWORD count, i;
+    PCREDENTIALA *creds;
+    CREDENTIALA new_cred;
+    PCREDENTIALA cred;
+    BOOL found = FALSE;
+
+    new_cred.Flags = 0;
+    new_cred.Type = cred_type;
+    new_cred.TargetName = (char *)TEST_TARGET_NAME;
+    new_cred.Comment = (char *)"Comment";
+    new_cred.CredentialBlobSize = sizeof(TEST_PASSWORD);
+    new_cred.CredentialBlob = (LPBYTE)TEST_PASSWORD;
+    new_cred.Persist = CRED_PERSIST_ENTERPRISE;
+    new_cred.AttributeCount = 0;
+    new_cred.Attributes = NULL;
+    new_cred.TargetAlias = NULL;
+    new_cred.UserName = (char *)"test\\winetest";
+    ret = pCredWriteA(&new_cred, 0);
+    ok(ret, "CredWriteA failed with error %d\n", GetLastError());
+
+    ret = pCredEnumerateA(NULL, 0, &count, &creds);
+    ok(ret, "CredEnumerateA failed with error %d\n", GetLastError());
+
+    for (i = 0; i < count; i++)
+    {
+        if (!strcmp(creds[i]->TargetName, TEST_TARGET_NAME))
+        {
+            ok(creds[i]->Type == cred_type, "expected creds[%d]->Type 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, 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, "test\\winetest"), "expected creds[%d]->UserName \"winetest\" but got \"%s\"\n", i, creds[i]->UserName);
+            found = TRUE;
+        }
+    }
+    pCredFree(creds);
+    ok(found, "credentials not found\n");
+
+    ret = pCredReadA(TEST_TARGET_NAME, cred_type, 0, &cred);
+    ok(ret, "CredReadA failed with error %d\n", GetLastError());
+    if (ret)  /* don't check the values of cred, if CredReadA failed. */
+    {
+        check_blob(__LINE__, cred_type, cred);
+        pCredFree(cred);
+    }
+
+    ret = pCredDeleteA(TEST_TARGET_NAME, cred_type, 0);
+    ok(ret, "CredDeleteA failed with error %d\n", GetLastError());
+}
+
+START_TEST(cred)
+{
+    DWORD persists[CRED_TYPE_MAXIMUM];
+
+    pCredEnumerateA = (void *)GetProcAddress(GetModuleHandle("advapi32.dll"), "CredEnumerateA");
+    pCredFree = (void *)GetProcAddress(GetModuleHandle("advapi32.dll"), "CredFree");
+    pCredGetSessionTypes = (void *)GetProcAddress(GetModuleHandle("advapi32.dll"), "CredGetSessionTypes");
+    pCredWriteA = (void *)GetProcAddress(GetModuleHandle("advapi32.dll"), "CredWriteA");
+    pCredDeleteA = (void *)GetProcAddress(GetModuleHandle("advapi32.dll"), "CredDeleteA");
+    pCredReadA = (void *)GetProcAddress(GetModuleHandle("advapi32.dll"), "CredReadA");
+    pCredRenameA = (void *)GetProcAddress(GetModuleHandle("advapi32.dll"), "CredRenameA");
+
+    if (!pCredEnumerateA || !pCredFree || !pCredWriteA || !pCredDeleteA ||
+        !pCredReadA)
+    {
+        skip("credentials functions not present in advapi32.dll\n");
+        return;
+    }
+
+    if (pCredGetSessionTypes)
+    {
+        BOOL ret;
+        DWORD i;
+        ret = pCredGetSessionTypes(CRED_TYPE_MAXIMUM, persists);
+        ok(ret, "CredGetSessionTypes failed with error %d\n", GetLastError());
+        ok(persists[0] == CRED_PERSIST_NONE, "persists[0] = %u instead of CRED_PERSIST_NONE\n", persists[0]);
+        for (i=0; i < CRED_TYPE_MAXIMUM; i++)
+            ok(persists[i] <= CRED_PERSIST_ENTERPRISE, "bad value for persists[%u]: %u\n", i, persists[i]);
+    }
+    else
+        memset(persists, CRED_PERSIST_ENTERPRISE, sizeof(persists));
+
+    test_CredReadA();
+    test_CredWriteA();
+    test_CredDeleteA();
+
+    trace("generic:\n");
+    if (persists[CRED_TYPE_GENERIC] == CRED_PERSIST_NONE)
+        skip("CRED_TYPE_GENERIC credentials are not supported or are disabled. Skipping\n");
+    else
+        test_generic();
+
+        trace("domain password:\n");
+    if (persists[CRED_TYPE_DOMAIN_PASSWORD] == CRED_PERSIST_NONE)
+        skip("CRED_TYPE_DOMAIN_PASSWORD credentials are not supported or are disabled. Skipping\n");
+    else
+        test_domain_password(CRED_TYPE_DOMAIN_PASSWORD);
+
+    trace("domain visible password:\n");
+    if (persists[CRED_TYPE_DOMAIN_VISIBLE_PASSWORD] == CRED_PERSIST_NONE)
+        skip("CRED_TYPE_DOMAIN_VISIBLE_PASSWORD credentials are not supported or are disabled. Skipping\n");
+    else
+        test_domain_password(CRED_TYPE_DOMAIN_VISIBLE_PASSWORD);
+}
index 087ab46..8ad2b6b 100644 (file)
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 #include <stdarg.h>
@@ -34,7 +34,6 @@ static const char szKeySet[] = "wine_test_keyset";
 static const char szBadKeySet[] = "wine_test_bad_keyset";
 #define NON_DEF_PROV_TYPE 999
 
-static HMODULE hadvapi32;
 static BOOL (WINAPI *pCryptAcquireContextA)(HCRYPTPROV*,LPCSTR,LPCSTR,DWORD,DWORD);
 static BOOL (WINAPI *pCryptEnumProviderTypesA)(DWORD, DWORD*, DWORD, DWORD*, LPSTR, DWORD*);
 static BOOL (WINAPI *pCryptEnumProvidersA)(DWORD, DWORD*, DWORD, DWORD*, LPSTR, DWORD*);
@@ -68,47 +67,44 @@ static BOOL (WINAPI *pCryptVerifySignatureW)(HCRYPTHASH, BYTE*, DWORD, HCRYPTKEY
 
 static void init_function_pointers(void)
 {
-    hadvapi32 = GetModuleHandleA("advapi32.dll");
-
-    if(hadvapi32)
-    {
-        pCryptAcquireContextA = (void*)GetProcAddress(hadvapi32, "CryptAcquireContextA");
-        pCryptEnumProviderTypesA = (void*)GetProcAddress(hadvapi32, "CryptEnumProviderTypesA");
-        pCryptEnumProvidersA = (void*)GetProcAddress(hadvapi32, "CryptEnumProvidersA");
-        pCryptGetDefaultProviderA = (void*)GetProcAddress(hadvapi32, "CryptGetDefaultProviderA");
-        pCryptReleaseContext = (void*)GetProcAddress(hadvapi32, "CryptReleaseContext");
-        pCryptSetProviderExA = (void*)GetProcAddress(hadvapi32, "CryptSetProviderExA");
-        pCryptCreateHash = (void*)GetProcAddress(hadvapi32, "CryptCreateHash");
-        pCryptDestroyHash = (void*)GetProcAddress(hadvapi32, "CryptDestroyHash");
-        pCryptGenRandom = (void*)GetProcAddress(hadvapi32, "CryptGenRandom");
-        pCryptContextAddRef = (void*)GetProcAddress(hadvapi32, "CryptContextAddRef");
-        pCryptGenKey = (void*)GetProcAddress(hadvapi32, "CryptGenKey");
-        pCryptDestroyKey = (void*)GetProcAddress(hadvapi32, "CryptDestroyKey");
-        pCryptDecrypt = (void*)GetProcAddress(hadvapi32, "CryptDecrypt");
-        pCryptDeriveKey = (void*)GetProcAddress(hadvapi32, "CryptDeriveKey");
-        pCryptDuplicateHash = (void*)GetProcAddress(hadvapi32, "CryptDuplicateHash");
-        pCryptDuplicateKey = (void*)GetProcAddress(hadvapi32, "CryptDuplicateKey");
-        pCryptEncrypt = (void*)GetProcAddress(hadvapi32, "CryptEncrypt");
-        pCryptExportKey = (void*)GetProcAddress(hadvapi32, "CryptExportKey");
-        pCryptGetHashParam = (void*)GetProcAddress(hadvapi32, "CryptGetHashParam");
-        pCryptGetKeyParam = (void*)GetProcAddress(hadvapi32, "CryptGetKeyParam");
-        pCryptGetProvParam = (void*)GetProcAddress(hadvapi32, "CryptGetProvParam");
-        pCryptGetUserKey = (void*)GetProcAddress(hadvapi32, "CryptGetUserKey");
-        pCryptHashData = (void*)GetProcAddress(hadvapi32, "CryptHashData");
-        pCryptHashSessionKey = (void*)GetProcAddress(hadvapi32, "CryptHashSessionKey");
-        pCryptImportKey = (void*)GetProcAddress(hadvapi32, "CryptImportKey");
-        pCryptSignHashW = (void*)GetProcAddress(hadvapi32, "CryptSignHashW");
-        pCryptSetHashParam = (void*)GetProcAddress(hadvapi32, "CryptSetHashParam");
-        pCryptSetKeyParam = (void*)GetProcAddress(hadvapi32, "CryptSetKeyParam");
-        pCryptSetProvParam = (void*)GetProcAddress(hadvapi32, "CryptSetProvParam");
-        pCryptVerifySignatureW = (void*)GetProcAddress(hadvapi32, "CryptVerifySignatureW");
-    }
+    HMODULE hadvapi32 = GetModuleHandleA("advapi32.dll");
+
+    pCryptAcquireContextA = (void*)GetProcAddress(hadvapi32, "CryptAcquireContextA");
+    pCryptEnumProviderTypesA = (void*)GetProcAddress(hadvapi32, "CryptEnumProviderTypesA");
+    pCryptEnumProvidersA = (void*)GetProcAddress(hadvapi32, "CryptEnumProvidersA");
+    pCryptGetDefaultProviderA = (void*)GetProcAddress(hadvapi32, "CryptGetDefaultProviderA");
+    pCryptReleaseContext = (void*)GetProcAddress(hadvapi32, "CryptReleaseContext");
+    pCryptSetProviderExA = (void*)GetProcAddress(hadvapi32, "CryptSetProviderExA");
+    pCryptCreateHash = (void*)GetProcAddress(hadvapi32, "CryptCreateHash");
+    pCryptDestroyHash = (void*)GetProcAddress(hadvapi32, "CryptDestroyHash");
+    pCryptGenRandom = (void*)GetProcAddress(hadvapi32, "CryptGenRandom");
+    pCryptContextAddRef = (void*)GetProcAddress(hadvapi32, "CryptContextAddRef");
+    pCryptGenKey = (void*)GetProcAddress(hadvapi32, "CryptGenKey");
+    pCryptDestroyKey = (void*)GetProcAddress(hadvapi32, "CryptDestroyKey");
+    pCryptDecrypt = (void*)GetProcAddress(hadvapi32, "CryptDecrypt");
+    pCryptDeriveKey = (void*)GetProcAddress(hadvapi32, "CryptDeriveKey");
+    pCryptDuplicateHash = (void*)GetProcAddress(hadvapi32, "CryptDuplicateHash");
+    pCryptDuplicateKey = (void*)GetProcAddress(hadvapi32, "CryptDuplicateKey");
+    pCryptEncrypt = (void*)GetProcAddress(hadvapi32, "CryptEncrypt");
+    pCryptExportKey = (void*)GetProcAddress(hadvapi32, "CryptExportKey");
+    pCryptGetHashParam = (void*)GetProcAddress(hadvapi32, "CryptGetHashParam");
+    pCryptGetKeyParam = (void*)GetProcAddress(hadvapi32, "CryptGetKeyParam");
+    pCryptGetProvParam = (void*)GetProcAddress(hadvapi32, "CryptGetProvParam");
+    pCryptGetUserKey = (void*)GetProcAddress(hadvapi32, "CryptGetUserKey");
+    pCryptHashData = (void*)GetProcAddress(hadvapi32, "CryptHashData");
+    pCryptHashSessionKey = (void*)GetProcAddress(hadvapi32, "CryptHashSessionKey");
+    pCryptImportKey = (void*)GetProcAddress(hadvapi32, "CryptImportKey");
+    pCryptSignHashW = (void*)GetProcAddress(hadvapi32, "CryptSignHashW");
+    pCryptSetHashParam = (void*)GetProcAddress(hadvapi32, "CryptSetHashParam");
+    pCryptSetKeyParam = (void*)GetProcAddress(hadvapi32, "CryptSetKeyParam");
+    pCryptSetProvParam = (void*)GetProcAddress(hadvapi32, "CryptSetProvParam");
+    pCryptVerifySignatureW = (void*)GetProcAddress(hadvapi32, "CryptVerifySignatureW");
 }
 
 static void init_environment(void)
 {
        HCRYPTPROV hProv;
-
+       
        /* Ensure that container "wine_test_keyset" does exist */
        if (!pCryptAcquireContextA(&hProv, szKeySet, szRsaBaseProv, PROV_RSA_FULL, 0))
        {
@@ -154,49 +150,60 @@ static void test_acquire_context(void)
 {
        BOOL result;
        HCRYPTPROV hProv;
+       DWORD GLE;
 
-       /* Provoke all kinds of error conditions (which are easy to provoke).
+       /* Provoke all kinds of error conditions (which are easy to provoke). 
         * The order of the error tests seems to match Windows XP's rsaenh.dll CSP,
         * but since this is likely to change between CSP versions, we don't check
         * this. Please don't change the order of tests. */
        result = pCryptAcquireContextA(&hProv, NULL, NULL, 0, 0);
-       ok(!result && GetLastError()==NTE_BAD_PROV_TYPE, "%ld\n", GetLastError());
-
+       ok(!result && GetLastError()==NTE_BAD_PROV_TYPE, "%d\n", GetLastError());
+       
        result = pCryptAcquireContextA(&hProv, NULL, NULL, 1000, 0);
-       ok(!result && GetLastError()==NTE_BAD_PROV_TYPE, "%ld\n", GetLastError());
+       ok(!result && GetLastError()==NTE_BAD_PROV_TYPE, "%d\n", GetLastError());
 
        result = pCryptAcquireContextA(&hProv, NULL, NULL, NON_DEF_PROV_TYPE, 0);
-       ok(!result && GetLastError()==NTE_PROV_TYPE_NOT_DEF, "%ld\n", GetLastError());
-
+       ok(!result && GetLastError()==NTE_PROV_TYPE_NOT_DEF, "%d\n", GetLastError());
+       
        result = pCryptAcquireContextA(&hProv, szKeySet, szNonExistentProv, PROV_RSA_FULL, 0);
-       ok(!result && GetLastError()==NTE_KEYSET_NOT_DEF, "%ld\n", GetLastError());
+       ok(!result && GetLastError()==NTE_KEYSET_NOT_DEF, "%d\n", GetLastError());
 
        result = pCryptAcquireContextA(&hProv, szKeySet, szRsaBaseProv, NON_DEF_PROV_TYPE, 0);
-       ok(!result && GetLastError()==NTE_PROV_TYPE_NO_MATCH, "%ld\n", GetLastError());
-
+       ok(!result && GetLastError()==NTE_PROV_TYPE_NO_MATCH, "%d\n", GetLastError());
+       
        /* This test fails under Win2k SP4:
           result = TRUE, GetLastError() == ERROR_INVALID_PARAMETER
        SetLastError(0xdeadbeef);
        result = pCryptAcquireContextA(NULL, szKeySet, szRsaBaseProv, PROV_RSA_FULL, 0);
-       ok(!result && GetLastError()==ERROR_INVALID_PARAMETER, "%d/%ld\n", result, GetLastError());
+       ok(!result && GetLastError()==ERROR_INVALID_PARAMETER, "%d/%d\n", result, GetLastError());
        */
-
+       
        /* Last not least, try to really acquire a context. */
        hProv = 0;
        SetLastError(0xdeadbeef);
        result = pCryptAcquireContextA(&hProv, szKeySet, szRsaBaseProv, PROV_RSA_FULL, 0);
-       ok(result && (GetLastError() == ERROR_ENVVAR_NOT_FOUND || GetLastError() == ERROR_SUCCESS || GetLastError() == ERROR_RING2_STACK_IN_USE || GetLastError() == NTE_FAIL), "%d/%ld\n", result, GetLastError());
-
-       if (hProv)
+       GLE = GetLastError();
+       ok(result && (GLE == ERROR_ENVVAR_NOT_FOUND   || 
+                     GLE == ERROR_SUCCESS            || 
+                     GLE == ERROR_RING2_STACK_IN_USE || 
+                     GLE == NTE_FAIL                 ||
+                     GLE == ERROR_NOT_LOGGED_ON), "%d/%d\n", result, GLE);
+
+       if (hProv) 
                pCryptReleaseContext(hProv, 0);
 
        /* Try again, witch an empty ("\0") szProvider parameter */
        hProv = 0;
        SetLastError(0xdeadbeef);
        result = pCryptAcquireContextA(&hProv, szKeySet, "", PROV_RSA_FULL, 0);
-       ok(result && (GetLastError() == ERROR_ENVVAR_NOT_FOUND || GetLastError() == ERROR_SUCCESS  || GetLastError() == ERROR_RING2_STACK_IN_USE || GetLastError() == NTE_FAIL), "%d/%ld\n", result, GetLastError());
-
-       if (hProv)
+       GLE = GetLastError();
+       ok(result && (GLE == ERROR_ENVVAR_NOT_FOUND   || 
+                     GLE == ERROR_SUCCESS            || 
+                     GLE == ERROR_RING2_STACK_IN_USE || 
+                     GLE == NTE_FAIL                 ||
+                     GLE == ERROR_NOT_LOGGED_ON), "%d/%d\n", result, GetLastError());
+
+       if (hProv) 
                pCryptReleaseContext(hProv, 0);
 }
 
@@ -209,164 +216,264 @@ static void test_incorrect_api_usage(void)
     BYTE temp;
     DWORD dwLen, dwTemp;
 
-    /* This is to document incorrect api usage in the
+    /* This is to document incorrect api usage in the 
      * "Uru - Ages beyond Myst Demo" installer as reported by Paul Vriens.
      *
-     * The installer destroys a hash object after having released the context
-     * with which the hash was created. This is not allowed according to MSDN,
-     * since CryptReleaseContext destroys all hash and key objects belonging to
-     * the respective context. However, while wine used to crash, Windows is more
+     * The installer destroys a hash object after having released the context 
+     * with which the hash was created. This is not allowed according to MSDN, 
+     * since CryptReleaseContext destroys all hash and key objects belonging to 
+     * the respective context. However, while wine used to crash, Windows is more 
      * robust here and returns an ERROR_INVALID_PARAMETER code.
      */
-
-    result = pCryptAcquireContextA(&hProv, szBadKeySet, szRsaBaseProv,
+    
+    result = pCryptAcquireContextA(&hProv, szBadKeySet, szRsaBaseProv, 
                                    PROV_RSA_FULL, CRYPT_NEWKEYSET);
-    ok (result, "%08lx\n", GetLastError());
+    ok (result, "%08x\n", GetLastError());
     if (!result) return;
 
     result = pCryptCreateHash(hProv, CALG_SHA, 0, 0, &hHash);
-    ok (result, "%ld\n", GetLastError());
+    ok (result, "%d\n", GetLastError());
     if (!result) return;
 
     result = pCryptGenKey(hProv, CALG_RC4, 0, &hKey);
-    ok (result, "%ld\n", GetLastError());
+    ok (result, "%d\n", GetLastError());
     if (!result) return;
 
     result = pCryptGenKey(hProv, CALG_RC4, 0, &hKey2);
-    ok (result, "%ld\n", GetLastError());
+    ok (result, "%d\n", GetLastError());
     if (!result) return;
 
     result = pCryptDestroyKey(hKey2);
-    ok (result, "%ld\n", GetLastError());
+    ok (result, "%d\n", GetLastError());
 
-    dwTemp = CRYPT_MODE_ECB;
+    dwTemp = CRYPT_MODE_ECB;    
     result = pCryptSetKeyParam(hKey2, KP_MODE, (BYTE*)&dwTemp, sizeof(DWORD));
-    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%ld\n", GetLastError());
-
-    result = pCryptAcquireContextA(&hProv2, szBadKeySet, NULL, PROV_RSA_FULL,
+    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%d\n", GetLastError());
+    
+    result = pCryptAcquireContextA(&hProv2, szBadKeySet, NULL, PROV_RSA_FULL, 
                                    CRYPT_DELETEKEYSET);
-    ok (result, "%ld\n", GetLastError());
+    ok (result, "%d\n", GetLastError());
     if (!result) return;
-
+    
     result = pCryptReleaseContext(hProv, 0);
-    ok (result, "%ld\n", GetLastError());
+    ok (result, "%d\n", GetLastError());
     if (!result) return;
 
     result = pCryptReleaseContext(hProv, 0);
-    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%ld\n", GetLastError());
+    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%d\n", GetLastError());
 
     result = pCryptGenRandom(hProv, 1, &temp);
-    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%ld\n", GetLastError());
+    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%d\n", GetLastError());
 
 #ifdef CRASHES_ON_NT40
     result = pCryptContextAddRef(hProv, NULL, 0);
-    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%ld\n", GetLastError());
+    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%d\n", GetLastError());
 #endif
 
     result = pCryptCreateHash(hProv, CALG_SHA, 0, 0, &hHash2);
-    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%ld\n", GetLastError());
+    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%d\n", GetLastError());
 
     dwLen = 1;
     result = pCryptDecrypt(hKey, (HCRYPTHASH)NULL, TRUE, 0, &temp, &dwLen);
-    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%ld\n", GetLastError());
+    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%d\n", GetLastError());
 
     dwLen = 1;
     result = pCryptEncrypt(hKey, (HCRYPTHASH)NULL, TRUE, 0, &temp, &dwLen, 1);
-    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%ld\n", GetLastError());
+    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%d\n", GetLastError());
 
     result = pCryptDeriveKey(hProv, CALG_RC4, hHash, 0, &hKey2);
-    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%ld\n", GetLastError());
+    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%d\n", GetLastError());
 
 #ifdef CRASHES_ON_NT40
     result = pCryptDuplicateHash(hHash, NULL, 0, &hHash2);
-    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%ld\n", GetLastError());
+    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%d\n", GetLastError());
 
     result = pCryptDuplicateKey(hKey, NULL, 0, &hKey2);
-    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%ld\n", GetLastError());
+    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%d\n", GetLastError());
 #endif
 
     dwLen = 1;
     result = pCryptExportKey(hKey, (HCRYPTPROV)NULL, 0, 0, &temp, &dwLen);
-    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%ld\n", GetLastError());
+    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%d\n", GetLastError());
 
     result = pCryptGenKey(hProv, CALG_RC4, 0, &hKey2);
-    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%ld\n", GetLastError());
+    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%d\n", GetLastError());
 
     dwLen = 1;
     result = pCryptGetHashParam(hHash, 0, &temp, &dwLen, 0);
-    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%ld\n", GetLastError());
+    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%d\n", GetLastError());
 
     dwLen = 1;
     result = pCryptGetKeyParam(hKey, 0, &temp, &dwLen, 0);
-    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%ld\n", GetLastError());
+    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%d\n", GetLastError());
 
     dwLen = 1;
     result = pCryptGetProvParam(hProv, 0, &temp, &dwLen, 0);
-    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%ld\n", GetLastError());
-
+    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%d\n", GetLastError());
+    
     result = pCryptGetUserKey(hProv, 0, &hKey2);
-    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%ld\n", GetLastError());
+    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%d\n", GetLastError());
 
     result = pCryptHashData(hHash, &temp, 1, 0);
-    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%ld\n", GetLastError());
+    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%d\n", GetLastError());
 
     result = pCryptHashSessionKey(hHash, hKey, 0);
-    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%ld\n", GetLastError());
+    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%d\n", GetLastError());
 
     result = pCryptImportKey(hProv, &temp, 1, (HCRYPTKEY)NULL, 0, &hKey2);
-    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%ld\n", GetLastError());
+    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%d\n", GetLastError());
 
-    dwLen = 1;
-    result = pCryptSignHashW(hHash, 0, NULL, 0, &temp, &dwLen);
-    ok (!result && (GetLastError() == ERROR_INVALID_PARAMETER ||
-        GetLastError() == ERROR_CALL_NOT_IMPLEMENTED), "%ld\n", GetLastError());
+    if (pCryptSignHashW)
+    {
+        dwLen = 1;
+        result = pCryptSignHashW(hHash, 0, NULL, 0, &temp, &dwLen);
+        ok (!result && (GetLastError() == ERROR_INVALID_PARAMETER ||
+            GetLastError() == ERROR_CALL_NOT_IMPLEMENTED), "%d\n", GetLastError());
+    }
+    else
+        skip("CryptSignHashW is not available\n");
 
     result = pCryptSetKeyParam(hKey, 0, &temp, 1);
-    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%ld\n", GetLastError());
+    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%d\n", GetLastError());
 
     result = pCryptSetHashParam(hHash, 0, &temp, 1);
-    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%ld\n", GetLastError());
+    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%d\n", GetLastError());
 
     result = pCryptSetProvParam(hProv, 0, &temp, 1);
-    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%ld\n", GetLastError());
+    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%d\n", GetLastError());
 
-    result = pCryptVerifySignatureW(hHash, &temp, 1, hKey, NULL, 0);
-    ok (!result && (GetLastError() == ERROR_INVALID_PARAMETER ||
-        GetLastError() == ERROR_CALL_NOT_IMPLEMENTED), "%ld\n", GetLastError());
+    if (pCryptVerifySignatureW)
+    {
+        result = pCryptVerifySignatureW(hHash, &temp, 1, hKey, NULL, 0);
+        ok (!result && (GetLastError() == ERROR_INVALID_PARAMETER ||
+            GetLastError() == ERROR_CALL_NOT_IMPLEMENTED), "%d\n", GetLastError());
+    }
+    else
+        skip("CryptVerifySignatureW is not available\n");
 
     result = pCryptDestroyHash(hHash);
-    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%ld\n", GetLastError());
-
+    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%d\n", GetLastError());
+    
     result = pCryptDestroyKey(hKey);
-    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%ld\n", GetLastError());
+    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%d\n", GetLastError());
 }
 
-static BOOL FindProvRegVals(DWORD dwIndex, DWORD *pdwProvType, LPSTR *pszProvName,
+static const BYTE privKey[] = {
+ 0x07, 0x02, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x52, 0x53, 0x41, 0x32, 0x00,
+ 0x02, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x79, 0x10, 0x1c, 0xd0, 0x6b, 0x10,
+ 0x18, 0x30, 0x94, 0x61, 0xdc, 0x0e, 0xcb, 0x96, 0x4e, 0x21, 0x3f, 0x79, 0xcd,
+ 0xa9, 0x17, 0x62, 0xbc, 0xbb, 0x61, 0x4c, 0xe0, 0x75, 0x38, 0x6c, 0xf3, 0xde,
+ 0x60, 0x86, 0x03, 0x97, 0x65, 0xeb, 0x1e, 0x6b, 0xdb, 0x53, 0x85, 0xad, 0x68,
+ 0x21, 0xf1, 0x5d, 0xe7, 0x1f, 0xe6, 0x53, 0xb4, 0xbb, 0x59, 0x3e, 0x14, 0x27,
+ 0xb1, 0x83, 0xa7, 0x3a, 0x54, 0xe2, 0x8f, 0x65, 0x8e, 0x6a, 0x4a, 0xcf, 0x3b,
+ 0x1f, 0x65, 0xff, 0xfe, 0xf1, 0x31, 0x3a, 0x37, 0x7a, 0x8b, 0xcb, 0xc6, 0xd4,
+ 0x98, 0x50, 0x36, 0x67, 0xe4, 0xa1, 0xe8, 0x7e, 0x8a, 0xc5, 0x23, 0xf2, 0x77,
+ 0xf5, 0x37, 0x61, 0x49, 0x72, 0x59, 0xe8, 0x3d, 0xf7, 0x60, 0xb2, 0x77, 0xca,
+ 0x78, 0x54, 0x6d, 0x65, 0x9e, 0x03, 0x97, 0x1b, 0x61, 0xbd, 0x0c, 0xd8, 0x06,
+ 0x63, 0xe2, 0xc5, 0x48, 0xef, 0xb3, 0xe2, 0x6e, 0x98, 0x7d, 0xbd, 0x4e, 0x72,
+ 0x91, 0xdb, 0x31, 0x57, 0xe3, 0x65, 0x3a, 0x49, 0xca, 0xec, 0xd2, 0x02, 0x4e,
+ 0x22, 0x7e, 0x72, 0x8e, 0xf9, 0x79, 0x84, 0x82, 0xdf, 0x7b, 0x92, 0x2d, 0xaf,
+ 0xc9, 0xe4, 0x33, 0xef, 0x89, 0x5c, 0x66, 0x99, 0xd8, 0x80, 0x81, 0x47, 0x2b,
+ 0xb1, 0x66, 0x02, 0x84, 0x59, 0x7b, 0xc3, 0xbe, 0x98, 0x45, 0x4a, 0x3d, 0xdd,
+ 0xea, 0x2b, 0xdf, 0x4e, 0xb4, 0x24, 0x6b, 0xec, 0xe7, 0xd9, 0x0c, 0x45, 0xb8,
+ 0xbe, 0xca, 0x69, 0x37, 0x92, 0x4c, 0x38, 0x6b, 0x96, 0x6d, 0xcd, 0x86, 0x67,
+ 0x5c, 0xea, 0x54, 0x94, 0xa4, 0xca, 0xa4, 0x02, 0xa5, 0x21, 0x4d, 0xae, 0x40,
+ 0x8f, 0x9d, 0x51, 0x83, 0xf2, 0x3f, 0x33, 0xc1, 0x72, 0xb4, 0x1d, 0x94, 0x6e,
+ 0x7d, 0xe4, 0x27, 0x3f, 0xea, 0xff, 0xe5, 0x9b, 0xa7, 0x5e, 0x55, 0x8e, 0x0d,
+ 0x69, 0x1c, 0x7a, 0xff, 0x81, 0x9d, 0x53, 0x52, 0x97, 0x9a, 0x76, 0x79, 0xda,
+ 0x93, 0x32, 0x16, 0xec, 0x69, 0x51, 0x1a, 0x4e, 0xc3, 0xf1, 0x72, 0x80, 0x78,
+ 0x5e, 0x66, 0x4a, 0x8d, 0x85, 0x2f, 0x3f, 0xb2, 0xa7 };
+
+static void test_verify_sig(void)
+{
+       BOOL ret;
+       HCRYPTPROV prov;
+       HCRYPTKEY key;
+       HCRYPTHASH hash;
+       BYTE bogus[] = { 0 };
+
+       if (!pCryptVerifySignatureW)
+       {
+               skip("CryptVerifySignatureW is not available\n");
+               return;
+       }
+
+       SetLastError(0xdeadbeef);
+       ret = pCryptVerifySignatureW(0, NULL, 0, 0, NULL, 0);
+       if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
+       {
+               skip("CryptVerifySignatureW is not implemented\n");
+               return;
+       }
+       ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
+        "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
+       ret = pCryptAcquireContextA(&prov, szKeySet, NULL, PROV_RSA_FULL,
+        CRYPT_NEWKEYSET);
+       if (!ret && GetLastError() == NTE_EXISTS)
+               ret = pCryptAcquireContextA(&prov, szKeySet, NULL, PROV_RSA_FULL, 0);
+       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);
+       ok(ret, "CryptCreateHash failed: %08x\n", GetLastError());
+       SetLastError(0xdeadbeef);
+       ret = pCryptVerifySignatureW(hash, NULL, 0, 0, NULL, 0);
+       ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
+        "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
+       SetLastError(0xdeadbeef);
+       ret = pCryptVerifySignatureW(0, NULL, 0, key, NULL, 0);
+       ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
+        "Expected ERROR_INVALID_PARAMETER, got %08x\n", GetLastError());
+       SetLastError(0xdeadbeef);
+       ret = pCryptVerifySignatureW(hash, NULL, 0, key, NULL, 0);
+       ok(!ret && (GetLastError() == NTE_BAD_SIGNATURE ||
+        GetLastError() == ERROR_INVALID_PARAMETER),
+        "Expected NTE_BAD_SIGNATURE or ERROR_INVALID_PARAMETER, got %08x\n",
+        GetLastError());
+       SetLastError(0xdeadbeef);
+       ret = pCryptVerifySignatureW(hash, NULL, sizeof(bogus), key, NULL, 0);
+       ok(!ret && (GetLastError() == NTE_BAD_SIGNATURE ||
+        GetLastError() == ERROR_INVALID_PARAMETER),
+        "Expected NTE_BAD_SIGNATURE or ERROR_INVALID_PARAMETER, got %08x\n",
+        GetLastError());
+       SetLastError(0xdeadbeef);
+       ret = pCryptVerifySignatureW(hash, bogus, 0, key, NULL, 0);
+       ok(!ret && GetLastError() == NTE_BAD_SIGNATURE,
+        "Expected NTE_BAD_SIGNATURE, got %08x\n", GetLastError());
+       SetLastError(0xdeadbeef);
+       ret = pCryptVerifySignatureW(hash, bogus, sizeof(bogus), key, NULL, 0);
+       ok(!ret && GetLastError() == NTE_BAD_SIGNATURE,
+        "Expected NTE_BAD_SIGNATURE, got %08x\n", GetLastError());
+       pCryptDestroyKey(key);
+       pCryptDestroyHash(hash);
+       pCryptReleaseContext(prov, 0);
+}
+
+static BOOL FindProvRegVals(DWORD dwIndex, DWORD *pdwProvType, LPSTR *pszProvName, 
                            DWORD *pcbProvName, DWORD *pdwProvCount)
 {
        HKEY hKey;
        HKEY subkey;
        DWORD size = sizeof(DWORD);
-
+       
        if (RegOpenKey(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Cryptography\\Defaults\\Provider", &hKey))
                return FALSE;
-
-       RegQueryInfoKey(hKey, NULL, NULL, NULL, pdwProvCount, pcbProvName,
+       
+       RegQueryInfoKey(hKey, NULL, NULL, NULL, pdwProvCount, pcbProvName, 
                                 NULL, NULL, NULL, NULL, NULL, NULL);
        (*pcbProvName)++;
-
+       
        if (!(*pszProvName = ((LPSTR)LocalAlloc(LMEM_ZEROINIT, *pcbProvName))))
                return FALSE;
-
+       
        RegEnumKeyEx(hKey, dwIndex, *pszProvName, pcbProvName, NULL, NULL, NULL, NULL);
        (*pcbProvName)++;
 
        RegOpenKey(hKey, *pszProvName, &subkey);
-       RegQueryValueEx(subkey, "Type", NULL, NULL, (BYTE*)pdwProvType, &size);
-
+       RegQueryValueEx(subkey, "Type", NULL, NULL, (LPBYTE)pdwProvType, &size);
+       
        RegCloseKey(subkey);
        RegCloseKey(hKey);
-
+       
        return TRUE;
 }
 
@@ -378,33 +485,36 @@ static void test_enum_providers(void)
        DWORD dwType;
        DWORD provCount;
        DWORD dwIndex = 0;
-
+       
        /* actual results */
        CHAR *provider = NULL;
        DWORD providerLen;
        DWORD type;
        DWORD count;
-       BOOL result;
+       DWORD result;
        DWORD notNull = 5;
        DWORD notZeroFlags = 5;
-
+       
        if(!pCryptEnumProvidersA)
        {
-           trace("skipping CryptEnumProviders tests\n");
+           skip("CryptEnumProvidersA is not available\n");
            return;
        }
-
+       
        if (!FindProvRegVals(dwIndex, &dwType, &pszProvName, &cbName, &provCount))
-               return;
-
+       {
+           skip("Could not find providers in registry\n");
+           return;
+       }
+       
        /* check pdwReserved flag for NULL */
        result = pCryptEnumProvidersA(dwIndex, &notNull, 0, &type, NULL, &providerLen);
-       ok(!result && GetLastError()==ERROR_INVALID_PARAMETER, "%ld\n", GetLastError());
-
+       ok(!result && GetLastError()==ERROR_INVALID_PARAMETER, "%d\n", GetLastError());
+       
        /* check dwFlags == 0 */
        result = pCryptEnumProvidersA(dwIndex, NULL, notZeroFlags, &type, NULL, &providerLen);
-       ok(!result && GetLastError()==NTE_BAD_FLAGS, "%ld\n", GetLastError());
-
+       ok(!result && GetLastError()==NTE_BAD_FLAGS, "%d\n", GetLastError());
+       
        /* alloc provider to half the size required
         * cbName holds the size required */
        providerLen = cbName / 2;
@@ -412,12 +522,12 @@ static void test_enum_providers(void)
                return;
 
        result = pCryptEnumProvidersA(dwIndex, NULL, 0, &type, provider, &providerLen);
-       ok(!result && GetLastError()==ERROR_MORE_DATA, "expected %i, got %ld\n",
+       ok(!result && GetLastError()==ERROR_MORE_DATA, "expected %i, got %d\n",
                ERROR_MORE_DATA, GetLastError());
 
        LocalFree(provider);
 
-       /* loop through the providers to get the number of providers
+       /* loop through the providers to get the number of providers 
         * after loop ends, count should be provCount + 1 so subtract 1
         * to get actual number of providers */
        count = 0;
@@ -425,48 +535,49 @@ static void test_enum_providers(void)
                ;
        count--;
        ok(count==provCount, "expected %i, got %i\n", (int)provCount, (int)count);
-
+       
        /* loop past the actual number of providers to get the error
         * ERROR_NO_MORE_ITEMS */
        for (count = 0; count < provCount + 1; count++)
                result = pCryptEnumProvidersA(count, NULL, 0, &type, NULL, &providerLen);
-       ok(!result && GetLastError()==ERROR_NO_MORE_ITEMS, "expected %i, got %ld\n",
+       ok(!result && GetLastError()==ERROR_NO_MORE_ITEMS, "expected %i, got %d\n", 
                        ERROR_NO_MORE_ITEMS, GetLastError());
-
+       
        /* check expected versus actual values returned */
        result = pCryptEnumProvidersA(dwIndex, NULL, 0, &type, NULL, &providerLen);
        ok(result && providerLen==cbName, "expected %i, got %i\n", (int)cbName, (int)providerLen);
        if (!(provider = ((LPSTR)LocalAlloc(LMEM_ZEROINIT, providerLen))))
                return;
-
+               
+       providerLen = 0xdeadbeef;
        result = pCryptEnumProvidersA(dwIndex, NULL, 0, &type, provider, &providerLen);
-       ok(result && type==dwType, "expected %ld, got %ld\n",
-               dwType, type);
-       ok(result && !strcmp(pszProvName, provider), "expected %s, got %s\n", pszProvName, provider);
-       ok(result && cbName==providerLen, "expected %ld, got %ld\n",
-               cbName, providerLen);
+       ok(result, "expected TRUE, got %d\n", result);
+       ok(type==dwType, "expected %d, got %d\n", dwType, type);
+       if (pszProvName)
+           ok(!strcmp(pszProvName, provider), "expected %s, got %s\n", pszProvName, provider);
+       ok(cbName==providerLen, "expected %d, got %d\n", cbName, providerLen);
 
        LocalFree(provider);
 }
 
-static BOOL FindProvTypesRegVals(DWORD dwIndex, DWORD *pdwProvType, LPSTR *pszTypeName,
+static BOOL FindProvTypesRegVals(DWORD dwIndex, DWORD *pdwProvType, LPSTR *pszTypeName, 
                                 DWORD *pcbTypeName, DWORD *pdwTypeCount)
 {
        HKEY hKey;
        HKEY hSubKey;
        PSTR ch;
-
+       
        if (RegOpenKey(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Cryptography\\Defaults\\Provider Types", &hKey))
                return FALSE;
-
+       
        if (RegQueryInfoKey(hKey, NULL, NULL, NULL, pdwTypeCount, pcbTypeName, NULL,
                        NULL, NULL, NULL, NULL, NULL))
            return FALSE;
        (*pcbTypeName)++;
-
+       
        if (!(*pszTypeName = ((LPSTR)LocalAlloc(LMEM_ZEROINIT, *pcbTypeName))))
                return FALSE;
-
+       
        if (RegEnumKeyEx(hKey, dwIndex, *pszTypeName, pcbTypeName, NULL, NULL, NULL, NULL))
            return FALSE;
        (*pcbTypeName)++;
@@ -475,33 +586,33 @@ static BOOL FindProvTypesRegVals(DWORD dwIndex, DWORD *pdwProvType, LPSTR *pszTy
        *pdwProvType = *(--ch) - '0';
        *pdwProvType += (*(--ch) - '0') * 10;
        *pdwProvType += (*(--ch) - '0') * 100;
-
+       
        if (RegOpenKey(hKey, *pszTypeName, &hSubKey))
            return FALSE;
-
+       
        if (RegQueryValueEx(hSubKey, "TypeName", NULL, NULL, NULL, pcbTypeName))
             return FALSE;
 
        if (!(*pszTypeName = ((LPSTR)LocalAlloc(LMEM_ZEROINIT, *pcbTypeName))))
                return FALSE;
-
-       if (RegQueryValueEx(hSubKey, "TypeName", NULL, NULL, *pszTypeName, pcbTypeName))
+       
+       if (RegQueryValueEx(hSubKey, "TypeName", NULL, NULL, (LPBYTE)*pszTypeName, pcbTypeName))
            return FALSE;
-
+       
        RegCloseKey(hSubKey);
        RegCloseKey(hKey);
-
+       
        return TRUE;
 }
 
-static void test_enum_provider_types()
+static void test_enum_provider_types(void)
 {
        /* expected values */
        DWORD dwProvType;
        LPSTR pszTypeName = NULL;
        DWORD cbTypeName;
        DWORD dwTypeCount;
-
+       
        /* actual values */
        DWORD index = 0;
        DWORD provType;
@@ -511,29 +622,29 @@ static void test_enum_provider_types()
        DWORD result;
        DWORD notNull = 5;
        DWORD notZeroFlags = 5;
-
+       
        if(!pCryptEnumProviderTypesA)
        {
-           trace("skipping CryptEnumProviderTypes tests\n");
+           skip("CryptEnumProviderTypesA is not available\n");
            return;
        }
-
+       
        if (!FindProvTypesRegVals(index, &dwProvType, &pszTypeName, &cbTypeName, &dwTypeCount))
        {
-           trace("could not find provider types in registry, skipping the test\n");
+           skip("Could not find provider types in registry\n");
            return;
        }
-
+       
        /* check pdwReserved for NULL */
        result = pCryptEnumProviderTypesA(index, &notNull, 0, &provType, typeName, &typeNameSize);
-       ok(!result && GetLastError()==ERROR_INVALID_PARAMETER, "expected %i, got %ld\n",
+       ok(!result && GetLastError()==ERROR_INVALID_PARAMETER, "expected %i, got %d\n", 
                ERROR_INVALID_PARAMETER, GetLastError());
-
+       
        /* check dwFlags == zero */
        result = pCryptEnumProviderTypesA(index, NULL, notZeroFlags, &provType, typeName, &typeNameSize);
-       ok(!result && GetLastError()==NTE_BAD_FLAGS, "expected %i, got %ld\n",
+       ok(!result && GetLastError()==NTE_BAD_FLAGS, "expected %i, got %d\n",
                ERROR_INVALID_PARAMETER, GetLastError());
-
+       
        /* alloc provider type to half the size required
         * cbTypeName holds the size required */
        typeNameSize = cbTypeName / 2;
@@ -547,40 +658,40 @@ static void test_enum_provider_types()
        ok(!result && GetLastError()==ERROR_MORE_DATA, "expected 0/ERROR_MORE_DATA, got %d/%08lx\n",
                result, GetLastError());
        */
-
+       
        LocalFree(typeName);
-
-       /* loop through the provider types to get the number of provider types
+       
+       /* loop through the provider types to get the number of provider types 
         * after loop ends, count should be dwTypeCount + 1 so subtract 1
         * to get actual number of provider types */
        typeCount = 0;
        while(pCryptEnumProviderTypesA(typeCount++, NULL, 0, &provType, NULL, &typeNameSize))
                ;
        typeCount--;
-       ok(typeCount==dwTypeCount, "expected %ld, got %ld\n", dwTypeCount, typeCount);
-
+       ok(typeCount==dwTypeCount, "expected %d, got %d\n", dwTypeCount, typeCount);
+       
        /* loop past the actual number of provider types to get the error
         * ERROR_NO_MORE_ITEMS */
        for (typeCount = 0; typeCount < dwTypeCount + 1; typeCount++)
                result = pCryptEnumProviderTypesA(typeCount, NULL, 0, &provType, NULL, &typeNameSize);
-       ok(!result && GetLastError()==ERROR_NO_MORE_ITEMS, "expected %i, got %ld\n",
+       ok(!result && GetLastError()==ERROR_NO_MORE_ITEMS, "expected %i, got %d\n", 
                        ERROR_NO_MORE_ITEMS, GetLastError());
-
+       
 
        /* check expected versus actual values returned */
        result = pCryptEnumProviderTypesA(index, NULL, 0, &provType, NULL, &typeNameSize);
-       ok(result && typeNameSize==cbTypeName, "expected %ld, got %ld\n", cbTypeName, typeNameSize);
+       ok(result && typeNameSize==cbTypeName, "expected %d, got %d\n", cbTypeName, typeNameSize);
        if (!(typeName = ((LPSTR)LocalAlloc(LMEM_ZEROINIT, typeNameSize))))
                return;
-
+               
        typeNameSize = 0xdeadbeef;
        result = pCryptEnumProviderTypesA(index, NULL, 0, &provType, typeName, &typeNameSize);
-       ok(result, "expected TRUE, got %ld\n", result);
-       ok(provType==dwProvType, "expected %ld, got %ld\n", dwProvType, provType);
+       ok(result, "expected TRUE, got %d\n", result);
+       ok(provType==dwProvType, "expected %d, got %d\n", dwProvType, provType);
        if (pszTypeName)
            ok(!strcmp(pszTypeName, typeName), "expected %s, got %s\n", pszTypeName, typeName);
-       ok(typeNameSize==cbTypeName, "expected %ld, got %ld\n", cbTypeName, typeNameSize);
-
+       ok(typeNameSize==cbTypeName, "expected %d, got %d\n", cbTypeName, typeNameSize);
+       
        LocalFree(typeName);
 }
 
@@ -590,58 +701,58 @@ static BOOL FindDfltProvRegVals(DWORD dwProvType, DWORD dwFlags, LPSTR *pszProvN
        PSTR keyname;
        PSTR ptr;
        DWORD user = dwFlags & CRYPT_USER_DEFAULT;
-
-       LPSTR MACHINESTR = "Software\\Microsoft\\Cryptography\\Defaults\\Provider Types\\Type XXX";
-       LPSTR USERSTR = "Software\\Microsoft\\Cryptography\\Provider Type XXX";
-
-       keyname = LocalAlloc(LMEM_ZEROINIT, (user ? strlen(USERSTR) : strlen(MACHINESTR)) + 1);
+       
+       LPCSTR machinestr = "Software\\Microsoft\\Cryptography\\Defaults\\Provider Types\\Type XXX";
+       LPCSTR userstr = "Software\\Microsoft\\Cryptography\\Provider Type XXX";
+       
+       keyname = LocalAlloc(LMEM_ZEROINIT, (user ? strlen(userstr) : strlen(machinestr)) + 1);
        if (keyname)
        {
-               user ? strcpy(keyname, USERSTR) : strcpy(keyname, MACHINESTR);
+               user ? strcpy(keyname, userstr) : strcpy(keyname, machinestr);
                ptr = keyname + strlen(keyname);
                *(--ptr) = (dwProvType % 10) + '0';
                *(--ptr) = ((dwProvType / 10) % 10) + '0';
                *(--ptr) = (dwProvType / 100) + '0';
        } else
                return FALSE;
-
+       
        if (RegOpenKey((dwFlags & CRYPT_USER_DEFAULT) ?  HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE ,keyname, &hKey))
        {
                LocalFree(keyname);
                return FALSE;
        }
        LocalFree(keyname);
-
-       if (RegQueryValueEx(hKey, "Name", NULL, NULL, *pszProvName, pcbProvName))
+       
+       if (RegQueryValueEx(hKey, "Name", NULL, NULL, (LPBYTE)*pszProvName, pcbProvName))
        {
                if (GetLastError() != ERROR_MORE_DATA)
                        SetLastError(NTE_PROV_TYPE_ENTRY_BAD);
                return FALSE;
        }
-
+       
        if (!(*pszProvName = LocalAlloc(LMEM_ZEROINIT, *pcbProvName)))
                return FALSE;
-
-       if (RegQueryValueEx(hKey, "Name", NULL, NULL, *pszProvName, pcbProvName))
+       
+       if (RegQueryValueEx(hKey, "Name", NULL, NULL, (LPBYTE)*pszProvName, pcbProvName))
        {
                if (GetLastError() != ERROR_MORE_DATA)
                        SetLastError(NTE_PROV_TYPE_ENTRY_BAD);
                return FALSE;
        }
-
+       
        RegCloseKey(hKey);
-
+       
        return TRUE;
 }
 
-static void test_get_default_provider()
+static void test_get_default_provider(void)
 {
        /* expected results */
        DWORD dwProvType = PROV_RSA_FULL;
        DWORD dwFlags = CRYPT_MACHINE_DEFAULT;
        LPSTR pszProvName = NULL;
        DWORD cbProvName;
-
+       
        /* actual results */
        DWORD provType = PROV_RSA_FULL;
        DWORD flags = CRYPT_MACHINE_DEFAULT;
@@ -649,92 +760,105 @@ static void test_get_default_provider()
        DWORD provNameSize;
        DWORD result;
        DWORD notNull = 5;
-
+       
        if(!pCryptGetDefaultProviderA)
        {
-           trace("skipping CryptGetDefaultProvider tests\n");
+           skip("CryptGetDefaultProviderA is not available\n");
            return;
        }
-
-       FindDfltProvRegVals(dwProvType, dwFlags, &pszProvName, &cbProvName);
-
+       
+       if(!FindDfltProvRegVals(dwProvType, dwFlags, &pszProvName, &cbProvName))
+       {
+           skip("Could not find default provider in registry\n");
+           return;
+       }
+       
        /* check pdwReserved for NULL */
        result = pCryptGetDefaultProviderA(provType, &notNull, flags, provName, &provNameSize);
-       ok(!result && GetLastError()==ERROR_INVALID_PARAMETER, "expected %i, got %ld\n",
+       ok(!result && GetLastError()==ERROR_INVALID_PARAMETER, "expected %i, got %d\n",
                ERROR_INVALID_PARAMETER, GetLastError());
-
+       
        /* check for invalid flag */
        flags = 0xdeadbeef;
        result = pCryptGetDefaultProviderA(provType, NULL, flags, provName, &provNameSize);
-       ok(!result && GetLastError()==NTE_BAD_FLAGS, "expected %ld, got %ld\n",
+       ok(!result && GetLastError()==NTE_BAD_FLAGS, "expected %d, got %d\n",
                NTE_BAD_FLAGS, GetLastError());
        flags = CRYPT_MACHINE_DEFAULT;
-
+       
        /* check for invalid prov type */
        provType = 0xdeadbeef;
        result = pCryptGetDefaultProviderA(provType, NULL, flags, provName, &provNameSize);
        ok(!result && (GetLastError() == NTE_BAD_PROV_TYPE ||
                       GetLastError() == ERROR_INVALID_PARAMETER),
-               "expected NTE_BAD_PROV_TYPE or ERROR_INVALID_PARAMETER, got %ld/%ld\n",
+               "expected NTE_BAD_PROV_TYPE or ERROR_INVALID_PARAMETER, got %d/%d\n",
                result, GetLastError());
        provType = PROV_RSA_FULL;
-
+       
        SetLastError(0);
-
+       
        /* alloc provName to half the size required
         * cbProvName holds the size required */
        provNameSize = cbProvName / 2;
        if (!(provName = LocalAlloc(LMEM_ZEROINIT, provNameSize)))
                return;
-
+       
        result = pCryptGetDefaultProviderA(provType, NULL, flags, provName, &provNameSize);
-       ok(!result && GetLastError()==ERROR_MORE_DATA, "expected %i, got %ld\n",
+       ok(!result && GetLastError()==ERROR_MORE_DATA, "expected %i, got %d\n",
                ERROR_MORE_DATA, GetLastError());
-
+               
        LocalFree(provName);
-
+       
        /* check expected versus actual values returned */
        result = pCryptGetDefaultProviderA(provType, NULL, flags, NULL, &provNameSize);
-       ok(result && provNameSize==cbProvName, "expected %ld, got %ld\n", cbProvName, provNameSize);
+       ok(result && provNameSize==cbProvName, "expected %d, got %d\n", cbProvName, provNameSize);
        provNameSize = cbProvName;
-
+       
        if (!(provName = LocalAlloc(LMEM_ZEROINIT, provNameSize)))
                return;
-
+       
+       provNameSize = 0xdeadbeef;
        result = pCryptGetDefaultProviderA(provType, NULL, flags, provName, &provNameSize);
-       ok(result && !strcmp(pszProvName, provName), "expected %s, got %s\n", pszProvName, provName);
-       ok(result && provNameSize==cbProvName, "expected %ld, got %ld\n", cbProvName, provNameSize);
+       ok(result, "expected TRUE, got %d\n", result);
+       if(pszProvName)
+           ok(!strcmp(pszProvName, provName), "expected %s, got %s\n", pszProvName, provName);
+       ok(provNameSize==cbProvName, "expected %d, got %d\n", cbProvName, provNameSize);
 
        LocalFree(provName);
 }
 
-static void test_set_provider_ex()
+static void test_set_provider_ex(void)
 {
        DWORD result;
        DWORD notNull = 5;
-
+       
        /* results */
        LPSTR pszProvName = NULL;
        DWORD cbProvName;
-
+       
        if(!pCryptGetDefaultProviderA || !pCryptSetProviderExA)
        {
-           trace("skipping CryptSetProviderEx tests\n");
+           skip("CryptGetDefaultProviderA and/or CryptSetProviderExA are not available\n");
            return;
        }
 
        /* check pdwReserved for NULL */
        result = pCryptSetProviderExA(MS_DEF_PROV, PROV_RSA_FULL, &notNull, CRYPT_MACHINE_DEFAULT);
-       ok(!result && GetLastError()==ERROR_INVALID_PARAMETER, "expected %i, got %ld\n",
+       ok(!result && GetLastError()==ERROR_INVALID_PARAMETER, "expected %i, got %d\n",
                ERROR_INVALID_PARAMETER, GetLastError());
 
        /* remove the default provider and then set it to MS_DEF_PROV/PROV_RSA_FULL */
+        SetLastError(0xdeadbeef);
        result = pCryptSetProviderExA(MS_DEF_PROV, PROV_RSA_FULL, NULL, CRYPT_MACHINE_DEFAULT | CRYPT_DELETE_DEFAULT);
-       ok(result, "%ld\n", GetLastError());
+       if (!result && (GetLastError() == ERROR_ACCESS_DENIED))
+       {
+               skip("Not enough rights to remove the default provider\n");
+               return;
+       }
+       ok(result, "%d\n", GetLastError());
 
        result = pCryptSetProviderExA(MS_DEF_PROV, PROV_RSA_FULL, NULL, CRYPT_MACHINE_DEFAULT);
-       ok(result, "%ld\n", GetLastError());
-
+       ok(result, "%d\n", GetLastError());
+       
        /* call CryptGetDefaultProvider to see if they match */
        result = pCryptGetDefaultProviderA(PROV_RSA_FULL, NULL, CRYPT_MACHINE_DEFAULT, NULL, &cbProvName);
        if (!(pszProvName = LocalAlloc(LMEM_ZEROINIT, cbProvName)))
@@ -742,11 +866,51 @@ static void test_set_provider_ex()
 
        result = pCryptGetDefaultProviderA(PROV_RSA_FULL, NULL, CRYPT_MACHINE_DEFAULT, pszProvName, &cbProvName);
        ok(result && !strcmp(MS_DEF_PROV, pszProvName), "expected %s, got %s\n", MS_DEF_PROV, pszProvName);
-       ok(result && cbProvName==(strlen(MS_DEF_PROV) + 1), "expected %i, got %ld\n", (strlen(MS_DEF_PROV) + 1), cbProvName);
+       ok(result && cbProvName==(strlen(MS_DEF_PROV) + 1), "expected %i, got %d\n", (lstrlenA(MS_DEF_PROV) + 1), cbProvName);
 
        LocalFree(pszProvName);
 }
 
+static void test_machine_guid(void)
+{
+   char originalGuid[40];
+   LONG r;
+   HKEY key;
+   DWORD size;
+   HCRYPTPROV hCryptProv;
+   BOOL restoreGuid = FALSE, ret;
+
+   r = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Cryptography",
+                     0, KEY_ALL_ACCESS, &key);
+   if (r != ERROR_SUCCESS)
+   {
+       skip("couldn't open HKLM\\Software\\Microsoft\\Cryptography\n");
+       return;
+   }
+   /* Cache existing MachineGuid, and delete it */
+   size = sizeof(originalGuid);
+   r = RegQueryValueExA(key, "MachineGuid", NULL, NULL, (BYTE *)originalGuid,
+                        &size);
+   if (r == ERROR_SUCCESS)
+   {
+       restoreGuid = TRUE;
+       r = RegDeleteValueA(key, "MachineGuid");
+       ok(!r, "RegDeleteValueA failed: %d\n", r);
+   }
+   else
+       ok(r == ERROR_FILE_NOT_FOUND, "expected ERROR_FILE_NOT_FOUND, got %d\n",
+          r);
+   /* Create and release a provider */
+   ret = pCryptAcquireContextA(&hCryptProv, szKeySet, NULL, PROV_RSA_FULL, 0);
+   ok(ret, "CryptAcquireContextA failed: %08x\n", GetLastError());
+   CryptReleaseContext(hCryptProv, 0);
+
+   if (restoreGuid)
+       RegSetValueExA(key, "MachineGuid", 0, REG_SZ, (const BYTE *)originalGuid,
+                      strlen(originalGuid)+1);
+   RegCloseKey(key);
+}
+
 START_TEST(crypt)
 {
        init_function_pointers();
@@ -754,9 +918,11 @@ START_TEST(crypt)
        init_environment();
        test_acquire_context();
        test_incorrect_api_usage();
+       test_verify_sig();
+       test_machine_guid();
        clean_up_environment();
        }
-
+       
        test_enum_providers();
        test_enum_provider_types();
        test_get_default_provider();
index e8e3eb4..b90e02c 100644 (file)
@@ -1,7 +1,8 @@
 /*
- * Unit tests for SystemFunction006 (LMHash?)
+ * Unit tests for SystemFunctionXXX (LMHash?)
  *
  * Copyright 2004 Hans Leidekker
+ * Copyright 2006 Mike McCormack
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 #include <stdio.h>
 
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
 #include "wine/test.h"
 #include "windef.h"
 #include "winbase.h"
+#include "winternl.h"
 
+struct ustring {
+    DWORD Length;
+    DWORD MaximumLength;
+    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)(void*, void*);
+typedef NTSTATUS (WINAPI *fnSystemFunction032)(struct ustring *, struct ustring *);
+
+fnSystemFunction001 pSystemFunction001;
+fnSystemFunction002 pSystemFunction002;
+fnSystemFunction003 pSystemFunction003;
+fnSystemFunction004 pSystemFunction004;
+fnSystemFunction004 pSystemFunction005;
 fnSystemFunction006 pSystemFunction006;
+fnSystemFunction008 pSystemFunction008;
+fnSystemFunction008 pSystemFunction009;
+
+/* encrypt two blocks */
+descrypt pSystemFunction012;
+descrypt pSystemFunction014;
+descrypt pSystemFunction016;
+descrypt pSystemFunction018;
+descrypt pSystemFunction020;
+descrypt pSystemFunction022;
+
+/* decrypt two blocks */
+descrypt pSystemFunction013;
+descrypt pSystemFunction015;
+descrypt pSystemFunction017;
+descrypt pSystemFunction019;
+descrypt pSystemFunction021;
+descrypt pSystemFunction023;
+
+/* encrypt two blocks with a 32bit key */
+descrypt pSystemFunction024;
+descrypt pSystemFunction025;
 
-static void test_SystemFunction006()
+/* decrypt two blocks with a 32bit key */
+descrypt pSystemFunction026;
+descrypt pSystemFunction027;
+
+typedef int (WINAPI *memcmpfunc)(unsigned char *, unsigned char *);
+memcmpfunc pSystemFunction030;
+memcmpfunc pSystemFunction031;
+
+fnSystemFunction032 pSystemFunction032;
+
+static void test_SystemFunction006(void)
 {
-    static unsigned char lmhash[16 + 1];
+    char lmhash[16 + 1];
 
-    unsigned char passwd[] = { 's','e','c','r','e','t', 0, 0, 0, 0, 0, 0, 0, 0 };
-    unsigned char expect[] =
+    char passwd[] = { 's','e','c','r','e','t', 0, 0, 0, 0, 0, 0, 0, 0 };
+    unsigned char expect[] = 
         { 0x85, 0xf5, 0x28, 0x9f, 0x09, 0xdc, 0xa7, 0xeb,
           0xaa, 0xd3, 0xb4, 0x35, 0xb5, 0x14, 0x04, 0xee };
 
@@ -45,19 +103,541 @@ static void test_SystemFunction006()
         lmhash[12], lmhash[13], lmhash[14], lmhash[15] );
 }
 
+static void test_SystemFunction008(void)
+{
+    /* example data from http://davenport.sourceforge.net/ntlm.html */
+    unsigned char hash[0x40] = {
+        0xff, 0x37, 0x50, 0xbc, 0xc2, 0xb2, 0x24, 0x12,
+        0xc2, 0x26, 0x5b, 0x23, 0x73, 0x4e, 0x0d, 0xac };
+    unsigned char challenge[0x40] = {
+        0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef };
+    unsigned char expected[0x18] = {
+        0xc3, 0x37, 0xcd, 0x5c, 0xbd, 0x44, 0xfc, 0x97,
+        0x82, 0xa6, 0x67, 0xaf, 0x6d, 0x42, 0x7c, 0x6d,
+        0xe6, 0x7c, 0x20, 0xc2, 0xd3, 0xe7, 0x7c, 0x56 };
+    unsigned char output[0x18];
+    NTSTATUS r;
+
+    r = pSystemFunction008(0,0,0);
+    ok( r == STATUS_UNSUCCESSFUL, "wrong error code\n");
+
+    r = pSystemFunction008(challenge,0,0);
+    ok( r == STATUS_UNSUCCESSFUL, "wrong error code\n");
+
+    r = pSystemFunction008(challenge, hash, 0);
+    ok( r == STATUS_UNSUCCESSFUL, "wrong error code\n");
+
+    /* crashes */
+    if (0)
+    {
+        r = pSystemFunction008(challenge, 0, output);
+        ok( r == STATUS_UNSUCCESSFUL, "wrong error code\n");
+    }
+
+    r = pSystemFunction008(0, 0, output);
+    ok( r == STATUS_UNSUCCESSFUL, "wrong error code\n");
+
+    memset(output, 0, sizeof output);
+    r = pSystemFunction008(challenge, hash, output);
+    ok( r == STATUS_SUCCESS, "wrong error code\n");
+
+    ok( !memcmp(output, expected, sizeof expected), "response wrong\n");
+}
+
+static void test_SystemFunction001(void)
+{
+    unsigned char key[8] = { 0xff, 0x37, 0x50, 0xbc, 0xc2, 0xb2, 0x24, 0 };
+    unsigned char data[8] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef };
+    unsigned char expected[8] = { 0xc3, 0x37, 0xcd, 0x5c, 0xbd, 0x44, 0xfc, 0x97 };
+    unsigned char output[16];
+    NTSTATUS r;
+
+    r = pSystemFunction001(0,0,0);
+    ok( r == STATUS_UNSUCCESSFUL, "wrong error code\n");
+
+    memset(output, 0, sizeof output);
+
+    r = pSystemFunction001(data,key,output);
+    ok( r == STATUS_SUCCESS, "wrong error code\n");
+
+    ok(!memcmp(output, expected, sizeof expected), "response wrong\n");
+}
+
+static void test_SystemFunction002(void)
+{
+    /* reverse of SystemFunction001 */
+    unsigned char key[8] = { 0xff, 0x37, 0x50, 0xbc, 0xc2, 0xb2, 0x24, 0 };
+    unsigned char expected[8] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef };
+    unsigned char data[8] = { 0xc3, 0x37, 0xcd, 0x5c, 0xbd, 0x44, 0xfc, 0x97 };
+    unsigned char output[8];
+    int r;
+
+    memset(output, 0, sizeof output);
+    r = pSystemFunction002(data, key, output);
+    ok(r == STATUS_SUCCESS, "function failed\n");
+    ok(!memcmp(output, expected, sizeof expected), "response wrong\n");
+}
+
+static void test_SystemFunction032(void)
+{
+    struct ustring key, data;
+    unsigned char szKey[] = { 'f','o','o',0 };
+    unsigned char szData[8] = { 'b','a','r',0 };
+    unsigned char expected[] = {0x28, 0xb9, 0xf8, 0xe1};
+    int r;
+
+    /* crashes:    pSystemFunction032(NULL,NULL); */
+
+    key.Buffer = szKey;
+    key.Length = sizeof szKey;
+    key.MaximumLength = key.Length;
+
+    data.Buffer = szData;
+    data.Length = 4;
+    data.MaximumLength = 8;
+
+    r = pSystemFunction032(&data, &key);
+    ok(r == STATUS_SUCCESS, "function failed\n");
+
+    ok(!memcmp(expected, data.Buffer, data.Length), "wrong result\n");
+}
+
+static void test_SystemFunction003(void)
+{
+    unsigned char output[8], data[8];
+    unsigned char key[7] = { 0xff, 0x37, 0x50, 0xbc, 0xc2, 0xb2, 0x24 };
+    unsigned char exp1[8] = { 0x9d, 0x21, 0xc8, 0x86, 0x6c, 0x21, 0xcf, 0x43 };
+    char exp2[] = "KGS!@#$%";
+    int r;
+
+    r = pSystemFunction003(NULL, NULL);
+    ok(r == STATUS_UNSUCCESSFUL, "function failed\n");
+
+    r = pSystemFunction003(key, NULL);
+    ok(r == STATUS_UNSUCCESSFUL, "function failed\n");
+
+    memset(data, 0, sizeof data);
+    r = pSystemFunction003(key, data);
+    ok(r == STATUS_SUCCESS, "function failed\n");
+    ok( !memcmp(exp1, data, sizeof data), "decrypted message wrong\n");
+
+    memset(output, 0, sizeof output);
+    r = pSystemFunction002(data, key, output);
+
+    ok( !memcmp(exp2, output, sizeof output), "decrypted message wrong\n");
+}
+
+static void test_SystemFunction004(void)
+{
+    unsigned char inbuf[0x100], keybuf[0x100], resbuf[0x100];
+    unsigned char output[8];
+    int r;
+    struct ustring in, key, out;
+
+    /* crash 
+    r = pSystemFunction004(NULL, NULL, NULL);
+    ok(r == STATUS_UNSUCCESSFUL, "function failed\n");
+    */
+
+    memset(inbuf, 0, sizeof inbuf);
+    memset(keybuf, 0, sizeof keybuf);
+    memset(resbuf, 0, sizeof resbuf);
+
+    in.Buffer = NULL;
+    in.Length = in.MaximumLength = 0;
+
+    key.Buffer = NULL;
+    key.Length = key.MaximumLength = 0;
+
+    out.Buffer = NULL;
+    out.Length = out.MaximumLength = 0;
+
+    r = pSystemFunction004(&in, &key, &out);
+    ok(r == STATUS_INVALID_PARAMETER_2, "function failed\n");
+
+    key.Buffer = keybuf;
+    key.Length = 0x100;
+    key.MaximumLength = 0x100;
+
+    r = pSystemFunction004(&in, &key, (struct ustring *)&out);
+    ok(r == STATUS_BUFFER_TOO_SMALL, "function failed\n");
+
+    in.Buffer = inbuf;
+    in.Length = 0x0c;
+    in.MaximumLength = 0;
+
+    /* add two identical blocks... */
+    inbuf[0] = 1;
+    inbuf[1] = 2;
+    inbuf[2] = 3;
+    inbuf[3] = 4;
+
+    inbuf[8] = 1;
+    inbuf[9] = 2;
+    inbuf[10] = 3;
+    inbuf[11] = 4;
+
+    /* check that the Length field is really obeyed */
+    keybuf[6] = 1;
+
+    key.Buffer = keybuf;
+    key.Length = 6;
+    key.MaximumLength = 0;
+
+    keybuf[1] = 0x33;
+
+    out.Buffer = resbuf;
+    out.Length = 0;
+    out.MaximumLength = 0x40;
+    r = pSystemFunction004(&in, &key, &out);
+    ok(r == STATUS_SUCCESS, "function failed\n");
+
+    keybuf[6] = 0;
+
+    memset(output, 0, sizeof output);
+    r = pSystemFunction002(out.Buffer, key.Buffer, output);
+
+    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(!memcmp(output, inbuf, sizeof output), "crypted data wrong\n");
+
+    memset(output, 0, sizeof output);
+    r = pSystemFunction002(out.Buffer+16, key.Buffer, output);
+    ok(!memcmp(output, inbuf, sizeof output), "crypted data wrong\n");
+}
+
+static void test_SystemFunction005(void)
+{
+    char output[0x40], result[0x40];
+    int r;
+    struct ustring in, key, out, res;
+    static char datastr[] = "twinkle twinkle little star";
+    static char keystr[]  = "byolnim";
+
+    in.Buffer = (unsigned char *)datastr;
+    in.Length = strlen(datastr);
+    in.MaximumLength = 0;
+
+    key.Buffer = (unsigned char *)keystr;
+    key.Length = strlen(keystr);
+    key.MaximumLength = 0;
+
+    out.Buffer = (unsigned char *)output;
+    out.Length = out.MaximumLength = sizeof output;
+
+    r = pSystemFunction004(&in, &key, &out);
+    ok(r == STATUS_SUCCESS, "function failed\n");
+
+    memset(result, 0, sizeof result);
+    res.Buffer = (unsigned char *)result;
+    res.Length = 0;
+    res.MaximumLength = sizeof result;
+
+    r = pSystemFunction005(&out, &key, &res);
+    ok(r == STATUS_SUCCESS, "function failed\n");
+
+    r = pSystemFunction005(&out, &key, &res);
+    ok(r == STATUS_SUCCESS, "function failed\n");
+
+    ok(res.Length == in.Length, "Length wrong\n");
+    ok(!memcmp(res.Buffer, in.Buffer, in.Length), "data wrong\n");
+
+    out.Length = 0;
+    out.MaximumLength = 0;
+    r = pSystemFunction005(&out, &key, &res);
+    ok(r == STATUS_SUCCESS, "function failed\n");
+
+    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");
+
+    key.Length = 1;
+    r = pSystemFunction005(&out, &key, &res);
+    ok(r == STATUS_UNKNOWN_REVISION, "function failed\n");
+
+    key.Length = 0;
+    r = pSystemFunction005(&out, &key, &res);
+    ok(r == STATUS_INVALID_PARAMETER_2, "function failed\n");
+}
+
+static void test_SystemFunction009(void)
+{
+    unsigned char hash[0x10] = {
+        0xff, 0x37, 0x50, 0xbc, 0xc2, 0xb2, 0x24, 0x12,
+        0xc2, 0x26, 0x5b, 0x23, 0x73, 0x4e, 0x0d, 0xac };
+    unsigned char challenge[8] = {
+        0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef };
+    unsigned char expected[0x18] = {
+        0xc3, 0x37, 0xcd, 0x5c, 0xbd, 0x44, 0xfc, 0x97,
+        0x82, 0xa6, 0x67, 0xaf, 0x6d, 0x42, 0x7c, 0x6d,
+        0xe6, 0x7c, 0x20, 0xc2, 0xd3, 0xe7, 0x7c, 0x56 };
+    unsigned char output[0x18];
+    int r;
+
+    memset(output, 0, sizeof output);
+    r = pSystemFunction009(challenge, hash, output);
+    ok( r == STATUS_SUCCESS, "wrong error code\n");
+    ok(!memcmp(output, expected, sizeof expected), "response wrong\n");
+}
+
+static unsigned char des_key[] = { 
+    0xff, 0x37, 0x50, 0xbc, 0xc2, 0xb2, 0x24, 
+    0xff, 0x37, 0x50, 0xbc, 0xc2, 0xb2, 0x24, 
+};
+static unsigned char des_plaintext[] = { 
+    0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 
+    0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0 
+};
+static unsigned char des_ciphertext[] = { 
+    0xc3, 0x37, 0xcd, 0x5c, 0xbd, 0x44, 0xfc, 0x97,
+    0xc3, 0x37, 0xcd, 0x5c, 0xbd, 0x44, 0xfc, 0x97, 0
+};
+
+/* test functions that encrypt two DES blocks */
+static void test_SystemFunction_encrypt(descrypt func, int num)
+{
+    unsigned char output[0x11];
+    int r;
+
+    if (!func)
+    {
+        skip("SystemFunction%03d is not available\n", num);
+        return;
+    }
+
+    r = func(NULL, NULL, NULL);
+    ok( r == STATUS_UNSUCCESSFUL, "wrong error code\n");
+
+    memset(output, 0, sizeof output);
+    r = func(des_plaintext, des_key, output);
+    ok( r == STATUS_SUCCESS, "wrong error code\n");
+    ok( !memcmp(des_ciphertext, output, sizeof des_ciphertext), "ciphertext wrong (%d)\n", num);
+}
+
+/* test functions that decrypt two DES blocks */
+static void test_SystemFunction_decrypt(descrypt func, int num)
+{
+    unsigned char output[0x11];
+    int r;
+
+    if (!func)
+    {
+        skip("SystemFunction%03d is not available\n", num);
+        return;
+    }
+
+    r = func(NULL, NULL, NULL);
+    ok( r == STATUS_UNSUCCESSFUL, "wrong error code\n");
+
+    memset(output, 0, sizeof output);
+
+    r = func(des_ciphertext, des_key, output);
+    ok( r == STATUS_SUCCESS, "wrong error code\n");
+    ok( !memcmp(des_plaintext, output, sizeof des_plaintext), "plaintext wrong (%d)\n", num);
+}
+
+static unsigned char des_ciphertext32[] = { 
+    0x69, 0x51, 0x35, 0x69, 0x0d, 0x29, 0x24, 0xad,
+    0x23, 0x6d, 0xfd, 0x43, 0x0d, 0xd3, 0x25, 0x81, 0
+};
+
+static void test_SystemFunction_enc32(descrypt func, int num)
+{
+    unsigned char key[4], output[0x11];
+    int r;
+
+    if (!func)
+    {
+        skip("SystemFunction%03d is not available\n", num);
+        return;
+    }
+
+    memset(output, 0, sizeof output);
+
+    /* two keys are generated using 4 bytes, repeated 4 times ... */
+    memcpy(key, "foo", 4);
+
+    r = func(des_plaintext, key, output);
+    ok( r == STATUS_SUCCESS, "wrong error code (%d)\n", num);
+
+    ok( !memcmp( output, des_ciphertext32, sizeof des_ciphertext32), "ciphertext wrong (%d)\n", num);
+}
+
+static void test_SystemFunction_dec32(descrypt func, int num)
+{
+    unsigned char key[4], output[0x11];
+    int r;
+
+    if (!func)
+    {
+        skip("SystemFunction%03d is not available\n", num);
+        return;
+    }
+
+    memset(output, 0, sizeof output);
+
+    /* two keys are generated using 4 bytes, repeated 4 times ... */
+    memcpy(key, "foo", 4);
+
+    r = func(des_ciphertext32, key, output);
+    ok( r == STATUS_SUCCESS, "wrong error code (%d)\n", num);
+
+    ok( !memcmp( output, des_plaintext, sizeof des_plaintext), "plaintext wrong (%d)\n", num);
+}
+
+static void test_memcmpfunc(memcmpfunc fn)
+{
+    unsigned char arg1[0x20], arg2[0x20];
+    int r;
+
+    if (!fn)
+    {
+        skip("function is not available\n");
+        return;
+    }
+
+    if (0)
+    {
+        /* crashes */
+        r = fn(NULL, NULL);
+    }
+
+    memset(arg1, 0, sizeof arg1);
+    memset(arg2, 0, sizeof arg2);
+    arg1[0x10] = 1;
+
+    r = fn(arg1, arg2);
+    ok( r == 1, "wrong error code\n");
+
+    memset(arg1, 1, sizeof arg1);
+    memset(arg2, 1, sizeof arg2);
+    arg1[0x10] = 0;
+
+    r = fn(arg1, arg2);
+    ok( r == 1, "wrong error code\n");
+
+    memset(arg1, 0, sizeof arg1);
+    memset(arg2, 1, sizeof arg2);
+
+    r = fn(arg1, arg2);
+    ok( r == 0, "wrong error code\n");
+
+    memset(arg1, 1, sizeof arg1);
+    memset(arg2, 0, sizeof arg2);
+
+    r = fn(arg1, arg2);
+    ok( r == 0, "wrong error code\n");
+}
+
 START_TEST(crypt_lmhash)
 {
-    HMODULE module;
+    HMODULE module = GetModuleHandleA("advapi32.dll");
 
-    if (!(module = LoadLibrary("advapi32.dll"))) return;
+    pSystemFunction001 = (fnSystemFunction001)GetProcAddress( module, "SystemFunction001" );
+    if (pSystemFunction001)
+        test_SystemFunction001();
+    else
+        skip("SystemFunction001 is not available\n");
 
-    pSystemFunction006 = (fnSystemFunction006)GetProcAddress( module, "SystemFunction006" );
+    pSystemFunction002 = (fnSystemFunction002)GetProcAddress( module, "SystemFunction002" );
+    if (pSystemFunction002)
+        test_SystemFunction002();
+    else
+        skip("SystemFunction002 is not available\n");
 
-    if (!pSystemFunction006) goto out;
+    pSystemFunction003 = (fnSystemFunction003)GetProcAddress( module, "SystemFunction003" );
+    if (pSystemFunction003)
+        test_SystemFunction003();
+    else
+        skip("SystemFunction002 is not available\n");
 
-    if (pSystemFunction006)
+    pSystemFunction004 = (fnSystemFunction004)GetProcAddress( module, "SystemFunction004" );
+    if (pSystemFunction004)
+        test_SystemFunction004();
+    else
+        skip("SystemFunction004 is not available\n");
+
+    pSystemFunction005 = (fnSystemFunction005)GetProcAddress( module, "SystemFunction005" );
+    if (pSystemFunction005)
+        test_SystemFunction005();
+    else
+        skip("SystemFunction005 is not available\n");
+
+    pSystemFunction006 = (fnSystemFunction006)GetProcAddress( module, "SystemFunction006" );
+    if (pSystemFunction006) 
         test_SystemFunction006();
+    else
+        skip("SystemFunction006 is not available\n");
+
+    pSystemFunction008 = (fnSystemFunction008)GetProcAddress( module, "SystemFunction008" );
+    if (pSystemFunction008)
+        test_SystemFunction008();
+    else
+        skip("SystemFunction008 is not available\n");
+
+    pSystemFunction009 = (fnSystemFunction009)GetProcAddress( module, "SystemFunction009" );
+    if (pSystemFunction009)
+        test_SystemFunction009();
+    else
+        skip("SystemFunction009 is not available\n");
+
+    pSystemFunction012 = (descrypt) GetProcAddress( module, "SystemFunction012");
+    pSystemFunction013 = (descrypt) GetProcAddress( module, "SystemFunction013");
+    pSystemFunction014 = (descrypt) GetProcAddress( module, "SystemFunction014");
+    pSystemFunction015 = (descrypt) GetProcAddress( module, "SystemFunction015");
+    pSystemFunction016 = (descrypt) GetProcAddress( module, "SystemFunction016");
+    pSystemFunction017 = (descrypt) GetProcAddress( module, "SystemFunction017");
+    pSystemFunction018 = (descrypt) GetProcAddress( module, "SystemFunction018");
+    pSystemFunction019 = (descrypt) GetProcAddress( module, "SystemFunction019");
+    pSystemFunction020 = (descrypt) GetProcAddress( module, "SystemFunction020");
+    pSystemFunction021 = (descrypt) GetProcAddress( module, "SystemFunction021");
+    pSystemFunction022 = (descrypt) GetProcAddress( module, "SystemFunction022");
+    pSystemFunction023 = (descrypt) GetProcAddress( module, "SystemFunction023");
+
+    /* these all encrypt two DES blocks */
+    test_SystemFunction_encrypt(pSystemFunction012, 12);
+    test_SystemFunction_encrypt(pSystemFunction014, 14);
+    test_SystemFunction_encrypt(pSystemFunction016, 16);
+    test_SystemFunction_encrypt(pSystemFunction018, 18);
+    test_SystemFunction_encrypt(pSystemFunction020, 20);
+    test_SystemFunction_encrypt(pSystemFunction022, 22);
+
+    /* these all decrypt two DES blocks */
+    test_SystemFunction_decrypt(pSystemFunction013, 13);
+    test_SystemFunction_decrypt(pSystemFunction015, 15);
+    test_SystemFunction_decrypt(pSystemFunction017, 17);
+    test_SystemFunction_decrypt(pSystemFunction019, 19);
+    test_SystemFunction_decrypt(pSystemFunction021, 21);
+    test_SystemFunction_decrypt(pSystemFunction023, 23);
+
+    pSystemFunction024 = (descrypt) GetProcAddress( module, "SystemFunction024");
+    pSystemFunction025 = (descrypt) GetProcAddress( module, "SystemFunction025");
+    pSystemFunction026 = (descrypt) GetProcAddress( module, "SystemFunction026");
+    pSystemFunction027 = (descrypt) GetProcAddress( module, "SystemFunction027");
+
+    /* these encrypt two DES blocks with a short key */
+    test_SystemFunction_enc32(pSystemFunction024, 24);
+    test_SystemFunction_enc32(pSystemFunction026, 26);
+
+    /* these descrypt two DES blocks with a short key */
+    test_SystemFunction_dec32(pSystemFunction025, 25);
+    test_SystemFunction_dec32(pSystemFunction027, 27);
+
+    pSystemFunction030 = (memcmpfunc) GetProcAddress( module, "SystemFunction030" );
+    pSystemFunction031 = (memcmpfunc) GetProcAddress( module, "SystemFunction031" );
+
+    test_memcmpfunc(pSystemFunction030);
+    test_memcmpfunc(pSystemFunction031);
 
-out:
-    FreeLibrary( module );
+    pSystemFunction032 = (fnSystemFunction032)GetProcAddress( module, "SystemFunction032" );
+    if (pSystemFunction032)
+        test_SystemFunction032();
+    else
+        skip("SystemFunction032 is not available\n");
 }
index cee8b7d..15a594b 100644 (file)
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 #include <stdio.h>
 
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
 #include "wine/test.h"
 #include "windef.h"
 #include "winbase.h"
 #include "winerror.h"
+#include "winternl.h"
 
 typedef struct
 {
@@ -36,14 +39,19 @@ typedef struct
 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);
+typedef int (WINAPI *md4hashfunc)(LPVOID, const LPBYTE, LPBYTE);
 
 fnMD4Init pMD4Init;
 fnMD4Update pMD4Update;
 fnMD4Final pMD4Final;
+fnSystemFunction007 pSystemFunction007;
+md4hashfunc pSystemFunction010;
+md4hashfunc pSystemFunction011;
 
 #define ctxcmp( a, b ) memcmp( (char*)a, (char*)b, FIELD_OFFSET( MD4_CTX, in ) )
 
-void test_md4_ctx()
+static void test_md4_ctx(void)
 {
     static unsigned char message[] =
         "In our Life there's If"
@@ -51,11 +59,10 @@ void test_md4_ctx()
         "In our business there is Sin"
         "In our bodies, there is Die";
 
-    int size = strlen( message );
-    HMODULE module;
+    int size = sizeof(message) - 1;
 
     MD4_CTX ctx;
-    MD4_CTX ctx_initialized =
+    MD4_CTX ctx_initialized = 
     {
         { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 },
         { 0, 0 }
@@ -77,13 +84,6 @@ void test_md4_ctx()
         { 0x5f, 0xd3, 0x9b, 0x29, 0x47, 0x53, 0x47, 0xaf,
           0xa5, 0xba, 0x0c, 0x05, 0xff, 0xc0, 0xc7, 0xda };
 
-    if (!(module = LoadLibrary( "advapi32.dll" ))) return;
-
-    pMD4Init = (fnMD4Init)GetProcAddress( module, "MD4Init" );
-    pMD4Update = (fnMD4Update)GetProcAddress( module, "MD4Update" );
-    pMD4Final = (fnMD4Final)GetProcAddress( module, "MD4Final" );
-
-    if (!pMD4Init || !pMD4Update || !pMD4Final) goto out;
 
     memset( &ctx, 0, sizeof(ctx) );
     pMD4Init( &ctx );
@@ -99,11 +99,80 @@ void test_md4_ctx()
     ok( ctxcmp( &ctx, &ctx_initialized ), "context has changed\n" );
     ok( !memcmp( ctx.digest, expect, sizeof(expect) ), "incorrect result\n" );
 
-out:
-    FreeLibrary( module );
+}
+
+static void test_SystemFunction007(void)
+{
+    int r;
+    UNICODE_STRING str;
+    BYTE output[0x10];
+    BYTE expected[0x10] = { 0x24, 0x0a, 0xf0, 0x9d, 0x84, 0x1c, 0xda, 0xcf, 
+                            0x56, 0xeb, 0x6b, 0x96, 0x55, 0xec, 0xcf, 0x0a };
+    WCHAR szFoo[] = {'f','o','o',0 };
+
+    if (0)
+    {
+    /* crashes on Windows */
+    r = pSystemFunction007(NULL, NULL);
+    ok( r == STATUS_UNSUCCESSFUL, "wrong error code\n");
+    }
+
+    str.Buffer = szFoo;
+    str.Length = 4*sizeof(WCHAR);
+    str.MaximumLength = str.Length;
+
+    memset(output, 0, sizeof output);
+    r = pSystemFunction007(&str, output);
+    ok( r == STATUS_SUCCESS, "wrong error code\n");
+
+    ok(!memcmp(output, expected, sizeof expected), "response wrong\n");
+}
+
+static void test_md4hashfunc(md4hashfunc func)
+{
+    unsigned char expected[0x10] = {
+        0x48, 0x7c, 0x3f, 0x5e, 0x2b, 0x0d, 0x6a, 0x79,
+        0x32, 0x4e, 0xcd, 0xbe, 0x9c, 0x15, 0x16, 0x6f };
+    unsigned char in[0x10], output[0x10];
+    int r;
+
+    memset(in, 0, sizeof in);
+    memset(output, 0, sizeof output);
+    r = func(0, in, output);
+    ok( r == STATUS_SUCCESS, "wrong error code\n");
+    ok( !memcmp(expected, output, sizeof output), "output wrong\n");
 }
 
 START_TEST(crypt_md4)
 {
-    test_md4_ctx();
+    HMODULE module;
+
+    module = GetModuleHandleA( "advapi32.dll" );
+
+    pMD4Init = (fnMD4Init)GetProcAddress( module, "MD4Init" );
+    pMD4Update = (fnMD4Update)GetProcAddress( module, "MD4Update" );
+    pMD4Final = (fnMD4Final)GetProcAddress( module, "MD4Final" );
+
+    if (pMD4Init && pMD4Update && pMD4Final)
+        test_md4_ctx();
+    else
+        skip("MD4Init and/or MD4Update and/or MD4Final are not available\n");
+
+    pSystemFunction007 = (fnSystemFunction007)GetProcAddress( module, "SystemFunction007" );
+    if (pSystemFunction007)
+        test_SystemFunction007();
+    else
+        skip("SystemFunction007 is not available\n");
+
+    pSystemFunction010 = (md4hashfunc)GetProcAddress( module, "SystemFunction010" );
+    if (pSystemFunction010)
+        test_md4hashfunc(pSystemFunction010);
+    else
+        skip("SystemFunction010 is not available\n");
+
+    pSystemFunction011 = (md4hashfunc)GetProcAddress( module, "SystemFunction011" );
+    if (pSystemFunction011)
+        test_md4hashfunc(pSystemFunction011);
+    else
+        skip("SystemFunction011 is not available\n");
 }
index 0e46e53..23d7d6b 100644 (file)
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 #include <stdio.h>
@@ -43,7 +43,7 @@ fnMD5Final pMD5Final;
 
 #define ctxcmp( a, b ) memcmp( (char*)a, (char*)b, FIELD_OFFSET( MD5_CTX, in ) )
 
-void test_md5_ctx()
+static void test_md5_ctx(void)
 {
     static unsigned char message[] =
         "In our Life there's If"
@@ -51,11 +51,11 @@ void test_md5_ctx()
         "In our business there is Sin"
         "In our bodies, there is Die";
 
-    int size = strlen( message );
+    int size = sizeof(message) - 1;
     HMODULE module;
 
     MD5_CTX ctx;
-    MD5_CTX ctx_initialized =
+    MD5_CTX ctx_initialized = 
     {
         { 0, 0 },
         { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 }
@@ -77,13 +77,17 @@ void test_md5_ctx()
         { 0x43, 0x03, 0xdd, 0x8c, 0x60, 0xd9, 0x3a, 0x22,
           0x0b, 0x28, 0xd0, 0xb2, 0x65, 0x93, 0xd0, 0x36 };
 
-    if (!(module = LoadLibrary( "advapi32.dll" ))) return;
+    module = GetModuleHandleA("advapi32.dll");
 
     pMD5Init = (fnMD5Init)GetProcAddress( module, "MD5Init" );
     pMD5Update = (fnMD5Update)GetProcAddress( module, "MD5Update" );
     pMD5Final = (fnMD5Final)GetProcAddress( module, "MD5Final" );
 
-    if (!pMD5Init || !pMD5Update || !pMD5Final) goto out;
+    if (!pMD5Init || !pMD5Update || !pMD5Final)
+    {
+        skip("Needed functions are not available\n");
+        return;
+    }
 
     memset( &ctx, 0, sizeof(ctx) );
     pMD5Init( &ctx );
@@ -98,9 +102,6 @@ void test_md5_ctx()
     pMD5Final( &ctx );
     ok( ctxcmp( &ctx, &ctx_initialized ), "context has changed\n" );
     ok( !memcmp( ctx.digest, expect, sizeof(expect) ), "incorrect result\n" );
-
-out:
-    FreeLibrary( module );
 }
 
 START_TEST(crypt_md5)
index 5cf6fdb..cfdaf99 100644 (file)
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 #include <stdarg.h>
@@ -33,8 +33,6 @@ typedef struct {
    UCHAR Buffer[64];
 } SHA_CTX, *PSHA_CTX;
 
-#define ctxcmp(a,b) memcmp((char*)a, (char*)b, FIELD_OFFSET(SHA_CTX, Buffer))
-
 static void test_sha_ctx(void)
 {
    FARPROC pA_SHAInit, pA_SHAUpdate, pA_SHAFinal;
@@ -45,34 +43,26 @@ static void test_sha_ctx(void)
    ULONG test_buffer_size = strlen(test_buffer);
    HMODULE hmod;
    SHA_CTX ctx;
-   SHA_CTX ctx_initialized = {{0, 0, 0, 0, 0}, {0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0}, {0, 0}};
-   SHA_CTX ctx_update1 = {{0, 0, 0, 0, 0}, {0xdbe5eba8, 0x6b4335ca, 0xf7c94abe, 0xc9f34e31, 0x311023f0}, {0, 0x67}};
-   SHA_CTX ctx_update2 = {{0, 0, 0, 0, 0}, {0x5ecc818d, 0x52498169, 0xf6758559, 0xd035a164, 0x871dd125}, {0, 0xce}};
    ULONG result[5];
    ULONG result_correct[5] = {0xe014f93, 0xe09791ec, 0x6dcf96c8, 0x8e9385fc, 0x1611c1bb};
 
-   hmod = LoadLibrary("advapi32.dll");
+   hmod = GetModuleHandleA("advapi32.dll");
    pA_SHAInit = GetProcAddress(hmod, "A_SHAInit");
    pA_SHAUpdate = GetProcAddress(hmod, "A_SHAUpdate");
    pA_SHAFinal = GetProcAddress(hmod, "A_SHAFinal");
 
-   if (!pA_SHAInit || !pA_SHAUpdate || !pA_SHAFinal) return;
+   if (!pA_SHAInit || !pA_SHAUpdate || !pA_SHAFinal)
+   {
+      skip("A_SHAInit and/or A_SHAUpdate and/or A_SHAFinal are not available\n");
+      return;
+   }
 
    RtlZeroMemory(&ctx, sizeof(ctx));
    pA_SHAInit(&ctx);
-   ok(!ctxcmp(&ctx, &ctx_initialized), "invalid initialization\n");
-
    pA_SHAUpdate(&ctx, test_buffer, test_buffer_size);
-   ok(!ctxcmp(&ctx, &ctx_update1), "update doesn't work correctly\n");
-
    pA_SHAUpdate(&ctx, test_buffer, test_buffer_size);
-   ok(!ctxcmp(&ctx, &ctx_update2), "update doesn't work correctly\n");
-
    pA_SHAFinal(&ctx, result);
-   ok(!ctxcmp(&ctx, &ctx_initialized), "context hasn't been reinitialized\n");
    ok(!memcmp(result, result_correct, sizeof(result)), "incorrect result\n");
-
-   FreeLibrary(hmod);
 }
 
 START_TEST(crypt_sha)
diff --git a/rostests/winetests/advapi32/lsa.c b/rostests/winetests/advapi32/lsa.c
new file mode 100644 (file)
index 0000000..4035416
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * Unit tests for lsa functions
+ *
+ * Copyright (c) 2006 Robert Reif
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
+#include "windef.h"
+#include "winbase.h"
+#include "winreg.h"
+#include "ntsecapi.h"
+#include "sddl.h"
+#include "winnls.h"
+#include "objbase.h"
+#define INITGUID
+#include "guiddef.h"
+#include "wine/test.h"
+
+static HMODULE hadvapi32;
+static NTSTATUS (WINAPI *pLsaClose)(LSA_HANDLE);
+static NTSTATUS (WINAPI *pLsaFreeMemory)(PVOID);
+static NTSTATUS (WINAPI *pLsaOpenPolicy)(PLSA_UNICODE_STRING,PLSA_OBJECT_ATTRIBUTES,ACCESS_MASK,PLSA_HANDLE);
+static NTSTATUS (WINAPI *pLsaQueryInformationPolicy)(LSA_HANDLE,POLICY_INFORMATION_CLASS,PVOID*);
+static BOOL     (WINAPI *pConvertSidToStringSidA)(PSID pSid, LPSTR *str);
+
+static BOOL init(void)
+{
+    hadvapi32 = GetModuleHandle("advapi32.dll");
+
+    pLsaClose = (void*)GetProcAddress(hadvapi32, "LsaClose");
+    pLsaFreeMemory = (void*)GetProcAddress(hadvapi32, "LsaFreeMemory");
+    pLsaOpenPolicy = (void*)GetProcAddress(hadvapi32, "LsaOpenPolicy");
+    pLsaQueryInformationPolicy = (void*)GetProcAddress(hadvapi32, "LsaQueryInformationPolicy");
+    pConvertSidToStringSidA = (void*)GetProcAddress(hadvapi32, "ConvertSidToStringSidA");
+
+    if (pLsaClose && pLsaFreeMemory && pLsaOpenPolicy && pLsaQueryInformationPolicy && pConvertSidToStringSidA)
+        return TRUE;
+
+    return FALSE;
+}
+
+static void test_lsa(void)
+{
+    NTSTATUS status;
+    LSA_HANDLE handle;
+    LSA_OBJECT_ATTRIBUTES object_attributes;
+
+    ZeroMemory(&object_attributes, sizeof(object_attributes));
+    object_attributes.Length = sizeof(object_attributes);
+
+    status = pLsaOpenPolicy( NULL, &object_attributes, POLICY_ALL_ACCESS, &handle);
+    ok(status == STATUS_SUCCESS || status == STATUS_ACCESS_DENIED,
+       "LsaOpenPolicy(POLICY_ALL_ACCESS) returned 0x%08x\n", status);
+
+    /* try a more restricted access mask if necessary */
+    if (status == STATUS_ACCESS_DENIED) {
+        trace("LsaOpenPolicy(POLICY_ALL_ACCESS) failed, trying POLICY_VIEW_LOCAL_INFORMATION\n");
+        status = pLsaOpenPolicy( NULL, &object_attributes, POLICY_VIEW_LOCAL_INFORMATION, &handle);
+        ok(status == STATUS_SUCCESS, "LsaOpenPolicy(POLICY_VIEW_LOCAL_INFORMATION) returned 0x%08x\n", status);
+    }
+
+    if (status == STATUS_SUCCESS) {
+        PPOLICY_AUDIT_EVENTS_INFO audit_events_info;
+        PPOLICY_PRIMARY_DOMAIN_INFO primary_domain_info;
+        PPOLICY_ACCOUNT_DOMAIN_INFO account_domain_info;
+        PPOLICY_DNS_DOMAIN_INFO dns_domain_info;
+
+        status = pLsaQueryInformationPolicy(handle, PolicyAuditEventsInformation, (PVOID*)&audit_events_info);
+        if (status == STATUS_ACCESS_DENIED)
+            skip("Not enough rights to retrieve PolicyAuditEventsInformation\n");
+        else
+            ok(status == STATUS_SUCCESS, "LsaQueryInformationPolicy(PolicyAuditEventsInformation) failed, returned 0x%08x\n", status);
+        if (status == STATUS_SUCCESS) {
+            pLsaFreeMemory((LPVOID)audit_events_info);
+        }
+
+        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))
+                {
+                    if (primary_domain_info->Name.Buffer) {
+                        LPSTR name = NULL;
+                        UINT len;
+                        len = WideCharToMultiByte( CP_ACP, 0, primary_domain_info->Name.Buffer, -1, NULL, 0, NULL, NULL );
+                        name = LocalAlloc( 0, len );
+                        WideCharToMultiByte( CP_ACP, 0, primary_domain_info->Name.Buffer, -1, name, len, NULL, NULL );
+                        trace("  name: %s sid: %s\n", name, strsid);
+                        LocalFree( name );
+                    } else
+                        trace("  name: NULL sid: %s\n", strsid);
+                    LocalFree( strsid );
+                }
+                else
+                    trace("invalid sid\n");
+            }
+            pLsaFreeMemory((LPVOID)primary_domain_info);
+        }
+
+        status = pLsaQueryInformationPolicy(handle, PolicyAccountDomainInformation, (PVOID*)&account_domain_info);
+        ok(status == STATUS_SUCCESS, "LsaQueryInformationPolicy(PolicyAccountDomainInformation) failed, returned 0x%08x\n", status);
+        if (status == STATUS_SUCCESS) {
+            pLsaFreeMemory((LPVOID)account_domain_info);
+        }
+
+        /* This isn't supported in NT4 */
+        status = pLsaQueryInformationPolicy(handle, PolicyDnsDomainInformation, (PVOID*)&dns_domain_info);
+        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;
+                LPSTR domain = NULL;
+                LPSTR forest = NULL;
+                LPSTR guidstr = NULL;
+                WCHAR guidstrW[64];
+                UINT len;
+                guidstrW[0] = '\0';
+                pConvertSidToStringSidA(dns_domain_info->Sid, &strsid);
+                StringFromGUID2(&dns_domain_info->DomainGuid, guidstrW, sizeof(guidstrW)/sizeof(WCHAR));
+                len = WideCharToMultiByte( CP_ACP, 0, guidstrW, -1, NULL, 0, NULL, NULL );
+                guidstr = LocalAlloc( 0, len );
+                WideCharToMultiByte( CP_ACP, 0, guidstrW, -1, guidstr, len, NULL, NULL );
+                if (dns_domain_info->Name.Buffer) {
+                    len = WideCharToMultiByte( CP_ACP, 0, dns_domain_info->Name.Buffer, -1, NULL, 0, NULL, NULL );
+                    name = LocalAlloc( 0, len );
+                    WideCharToMultiByte( CP_ACP, 0, dns_domain_info->Name.Buffer, -1, name, len, NULL, NULL );
+                }
+                if (dns_domain_info->DnsDomainName.Buffer) {
+                    len = WideCharToMultiByte( CP_ACP, 0, dns_domain_info->DnsDomainName.Buffer, -1, NULL, 0, NULL, NULL );
+                    domain = LocalAlloc( 0, len );
+                    WideCharToMultiByte( CP_ACP, 0, dns_domain_info->DnsDomainName.Buffer, -1, domain, len, NULL, NULL );
+                }
+                if (dns_domain_info->DnsForestName.Buffer) {
+                    len = WideCharToMultiByte( CP_ACP, 0, dns_domain_info->DnsForestName.Buffer, -1, NULL, 0, NULL, NULL );
+                    forest = LocalAlloc( 0, len );
+                    WideCharToMultiByte( CP_ACP, 0, dns_domain_info->DnsForestName.Buffer, -1, forest, len, NULL, NULL );
+                }
+                trace("  name: %s domain: %s forest: %s guid: %s sid: %s\n",
+                      name ? name : "NULL", domain ? domain : "NULL",
+                      forest ? forest : "NULL", guidstr, strsid ? strsid : "NULL");
+                LocalFree( name );
+                LocalFree( forest );
+                LocalFree( domain );
+                LocalFree( guidstr );
+                LocalFree( strsid );
+            }
+            pLsaFreeMemory((LPVOID)dns_domain_info);
+        }
+
+        status = pLsaClose(handle);
+        ok(status == STATUS_SUCCESS, "LsaClose() failed, returned 0x%08x\n", status);
+    }
+}
+
+START_TEST(lsa)
+{
+    if (!init()) {
+        skip("Needed functions are not available\n");
+        return;
+    }
+
+    test_lsa();
+}
index e881411..fe3d3ff 100644 (file)
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 #include <assert.h>
 #include <stdarg.h>
+#include <stdio.h>
 #include "wine/test.h"
 #include "windef.h"
 #include "winbase.h"
 #include "winreg.h"
+#include "winsvc.h"
 #include "winerror.h"
 
 static HKEY hkey_main;
+static DWORD GLE;
 
 static const char * sTestpath1 = "%LONGSYSTEMVAR%\\subdir1";
 static const char * sTestpath2 = "%FOO%\\subdir1";
 
+static HMODULE hadvapi32;
+static DWORD (WINAPI *pRegGetValueA)(HKEY,LPCSTR,LPCSTR,DWORD,LPDWORD,PVOID,LPDWORD);
+static DWORD (WINAPI *pRegDeleteTreeA)(HKEY,LPCSTR);
+
+
+
+/* Debugging functions from wine/libs/wine/debug.c */
+
+/* allocate some tmp string space */
+/* FIXME: this is not 100% thread-safe */
+static char *get_temp_buffer( int size )
+{
+    static char *list[32];
+    static long pos;
+    char *ret;
+    int idx;
+
+    idx = ++pos % (sizeof(list)/sizeof(list[0]));
+    if ((ret = realloc( list[idx], size ))) list[idx] = ret;
+    return ret;
+}
+
+static const char *wine_debugstr_an( const char *str, int n )
+{
+    static const char hex[16] = "0123456789abcdef";
+    char *dst, *res;
+    size_t size;
+
+    if (!((ULONG_PTR)str >> 16))
+    {
+        if (!str) return "(null)";
+        res = get_temp_buffer( 6 );
+        sprintf( res, "#%04x", LOWORD(str) );
+        return res;
+    }
+    if (n == -1) n = strlen(str);
+    if (n < 0) n = 0;
+    size = 10 + min( 300, n * 4 );
+    dst = res = get_temp_buffer( size );
+    *dst++ = '"';
+    while (n-- > 0 && dst <= res + size - 9)
+    {
+        unsigned char c = *str++;
+        switch (c)
+        {
+        case '\n': *dst++ = '\\'; *dst++ = 'n'; break;
+        case '\r': *dst++ = '\\'; *dst++ = 'r'; break;
+        case '\t': *dst++ = '\\'; *dst++ = 't'; break;
+        case '"':  *dst++ = '\\'; *dst++ = '"'; break;
+        case '\\': *dst++ = '\\'; *dst++ = '\\'; break;
+        default:
+            if (c >= ' ' && c <= 126)
+                *dst++ = c;
+            else
+            {
+                *dst++ = '\\';
+                *dst++ = 'x';
+                *dst++ = hex[(c >> 4) & 0x0f];
+                *dst++ = hex[c & 0x0f];
+            }
+        }
+    }
+    *dst++ = '"';
+    if (n > 0)
+    {
+        *dst++ = '.';
+        *dst++ = '.';
+        *dst++ = '.';
+    }
+    *dst++ = 0;
+    return res;
+}
+
+static const char *wine_debugstr_wn( const WCHAR *str, int n )
+{
+    char *dst, *res;
+    size_t size;
+
+    if (!HIWORD(str))
+    {
+        if (!str) return "(null)";
+        res = get_temp_buffer( 6 );
+        sprintf( res, "#%04x", LOWORD(str) );
+        return res;
+    }
+    if (n == -1) n = lstrlenW(str);
+    if (n < 0) n = 0;
+    size = 12 + min( 300, n * 5);
+    dst = res = get_temp_buffer( n * 5 + 7 );
+    *dst++ = 'L';
+    *dst++ = '"';
+    while (n-- > 0 && dst <= res + size - 10)
+    {
+        WCHAR c = *str++;
+        switch (c)
+        {
+        case '\n': *dst++ = '\\'; *dst++ = 'n'; break;
+        case '\r': *dst++ = '\\'; *dst++ = 'r'; break;
+        case '\t': *dst++ = '\\'; *dst++ = 't'; break;
+        case '"':  *dst++ = '\\'; *dst++ = '"'; break;
+        case '\\': *dst++ = '\\'; *dst++ = '\\'; break;
+        default:
+            if (c >= ' ' && c <= 126)
+                *dst++ = (char)c;
+            else
+            {
+                *dst++ = '\\';
+                sprintf(dst,"%04x",c);
+                dst+=4;
+            }
+        }
+    }
+    *dst++ = '"';
+    if (n > 0)
+    {
+        *dst++ = '.';
+        *dst++ = '.';
+        *dst++ = '.';
+    }
+    *dst = 0;
+    return res;
+}
+
+
+#define ADVAPI32_GET_PROC(func) \
+    p ## func = (void*)GetProcAddress(hadvapi32, #func); \
+    if(!p ## func) \
+      trace("GetProcAddress(%s) failed\n", #func);
+
+static void InitFunctionPtrs(void)
+{
+    hadvapi32 = GetModuleHandleA("advapi32.dll");
+
+    /* This function was introduced with Windows 2003 SP1 */
+    ADVAPI32_GET_PROC(RegGetValueA)
+    ADVAPI32_GET_PROC(RegDeleteTreeA)
+}
+
 /* delete key and all its subkeys */
 static DWORD delete_key( HKEY hkey )
 {
@@ -54,24 +195,256 @@ static DWORD delete_key( HKEY hkey )
 
 static void setup_main_key(void)
 {
-    if (RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\Test", &hkey_main )) delete_key( hkey_main );
+    if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\Test", &hkey_main )) delete_key( hkey_main );
 
     assert (!RegCreateKeyA( HKEY_CURRENT_USER, "Software\\Wine\\Test", &hkey_main ));
 }
 
+static void test_hkey_main_Value_A(LPCSTR name, LPCSTR string,
+                                   DWORD full_byte_len)
+{
+    DWORD ret, type, cbData;
+    DWORD str_byte_len;
+    LPSTR value;
+    static const char nA[]={'N', 0};
+
+    type=0xdeadbeef;
+    cbData=0xdeadbeef;
+    /* When successful RegQueryValueExA() leaves GLE as is,
+     * so we must reset it to detect unimplemented functions.
+     */
+    SetLastError(0xdeadbeef);
+    ret = RegQueryValueExA(hkey_main, name, NULL, &type, NULL, &cbData);
+    GLE = GetLastError();
+    ok(ret == ERROR_SUCCESS, "RegQueryValueExA failed: %d, GLE=%d\n", ret, GLE);
+    /* It is wrong for the Ansi version to not be implemented */
+    ok(GLE == 0xdeadbeef, "RegQueryValueExA set GLE = %u\n", GLE);
+    if(GLE == ERROR_CALL_NOT_IMPLEMENTED) return;
+
+    str_byte_len = (string ? lstrlenA(string) : 0) + 1;
+    ok(type == REG_SZ, "RegQueryValueExA returned type %d\n", type);
+    ok(cbData == full_byte_len || cbData == str_byte_len /* Win9x */,
+        "cbData=%d instead of %d or %d\n", cbData, full_byte_len, str_byte_len);
+
+    value = HeapAlloc(GetProcessHeap(), 0, (cbData+2)*sizeof(*value));
+    strcpy(value, nA);
+    type=0xdeadbeef;
+    ret = RegQueryValueExA(hkey_main, name, NULL, &type, (BYTE*)value, &cbData);
+    GLE = GetLastError();
+    ok(ret == ERROR_SUCCESS, "RegQueryValueExA failed: %d, GLE=%d\n", ret, GLE);
+    if (!string)
+    {
+        /* When cbData == 0, RegQueryValueExA() should not modify the buffer */
+        ok(strcmp(value, nA) == 0 || (cbData == 1 && *value == '\0') /* Win9x */,
+           "RegQueryValueExA failed: '%s' != '%s'\n", value, string);
+    }
+    else
+    {
+        ok(memcmp(value, string, cbData) == 0, "RegQueryValueExA failed: %s/%d != %s/%d\n",
+           wine_debugstr_an(value, cbData), cbData,
+           wine_debugstr_an(string, full_byte_len), full_byte_len);
+    }
+    HeapFree(GetProcessHeap(), 0, value);
+}
+
+static void test_hkey_main_Value_W(LPCWSTR name, LPCWSTR string,
+                                   DWORD full_byte_len)
+{
+    DWORD ret, type, cbData;
+    LPWSTR value;
+    static const WCHAR nW[]={'N', 0};
+
+    type=0xdeadbeef;
+    cbData=0xdeadbeef;
+    /* When successful RegQueryValueExW() leaves GLE as is,
+     * so we must reset it to detect unimplemented functions.
+     */
+    SetLastError(0xdeadbeef);
+    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;
+
+    ok(type == REG_SZ, "RegQueryValueExW returned type %d\n", type);
+    ok(cbData == full_byte_len,
+        "cbData=%d instead of %d\n", cbData, full_byte_len);
+
+    value = HeapAlloc(GetProcessHeap(), 0, (cbData+2)*sizeof(*value));
+    lstrcpyW(value, nW);
+    type=0xdeadbeef;
+    ret = RegQueryValueExW(hkey_main, name, NULL, &type, (BYTE*)value, &cbData);
+    GLE = GetLastError();
+    ok(ret == ERROR_SUCCESS, "RegQueryValueExW failed: %d, GLE=%d\n", ret, GLE);
+    if (!string)
+    {
+        /* When cbData == 0, RegQueryValueExW() should not modify the buffer */
+        string=nW;
+    }
+    ok(memcmp(value, string, cbData) == 0, "RegQueryValueExW failed: %s/%d != %s/%d\n",
+       wine_debugstr_wn(value, cbData / sizeof(WCHAR)), cbData,
+       wine_debugstr_wn(string, full_byte_len / sizeof(WCHAR)), full_byte_len);
+    HeapFree(GetProcessHeap(), 0, value);
+}
+
+static void test_set_value(void)
+{
+    DWORD ret;
+
+    static const WCHAR name1W[] =   {'C','l','e','a','n','S','i','n','g','l','e','S','t','r','i','n','g', 0};
+    static const WCHAR name2W[] =   {'S','o','m','e','I','n','t','r','a','Z','e','r','o','e','d','S','t','r','i','n','g', 0};
+    static const WCHAR emptyW[] = {0};
+    static const WCHAR string1W[] = {'T','h','i','s','N','e','v','e','r','B','r','e','a','k','s', 0};
+    static const WCHAR string2W[] = {'T','h','i','s', 0 ,'B','r','e','a','k','s', 0 , 0 ,'A', 0 , 0 , 0 , 'L','o','t', 0 , 0 , 0 , 0, 0};
+    static const WCHAR substring2W[] = {'T','h','i','s',0};
+
+    static const char name1A[] =   "CleanSingleString";
+    static const char name2A[] =   "SomeIntraZeroedString";
+    static const char emptyA[] = "";
+    static const char string1A[] = "ThisNeverBreaks";
+    static const char string2A[] = "This\0Breaks\0\0A\0\0\0Lot\0\0\0\0";
+    static const char substring2A[] = "This";
+
+    if (0)
+    {
+        /* Crashes on NT4, Windows 2000 and XP SP1 */
+        ret = RegSetValueA(hkey_main, NULL, REG_SZ, NULL, 0);
+        ok(ret == ERROR_INVALID_PARAMETER, "RegSetValueA should have failed with ERROR_INVALID_PARAMETER instead of %d\n", ret);
+    }
+
+    ret = RegSetValueA(hkey_main, NULL, REG_SZ, string1A, sizeof(string1A));
+    ok(ret == ERROR_SUCCESS, "RegSetValueA failed: %d, GLE=%d\n", ret, GetLastError());
+    test_hkey_main_Value_A(NULL, string1A, sizeof(string1A));
+    test_hkey_main_Value_W(NULL, string1W, sizeof(string1W));
+
+    /* RegSetValueA ignores the size passed in */
+    ret = RegSetValueA(hkey_main, NULL, REG_SZ, string1A, 4);
+    ok(ret == ERROR_SUCCESS, "RegSetValueA failed: %d, GLE=%d\n", ret, GetLastError());
+    test_hkey_main_Value_A(NULL, string1A, sizeof(string1A));
+    test_hkey_main_Value_W(NULL, string1W, sizeof(string1W));
+
+    /* stops at first null */
+    ret = RegSetValueA(hkey_main, NULL, REG_SZ, string2A, sizeof(string2A));
+    ok(ret == ERROR_SUCCESS, "RegSetValueA failed: %d, GLE=%d\n", ret, GetLastError());
+    test_hkey_main_Value_A(NULL, substring2A, sizeof(substring2A));
+    test_hkey_main_Value_W(NULL, substring2W, sizeof(substring2W));
+
+    /* only REG_SZ is supported */
+    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);
+    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);
+    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);
+
+    /* Test RegSetValueExA with a 'zero-byte' string (as Office 2003 does).
+     * Surprisingly enough we're supposed to get zero bytes out of it.
+     */
+    ret = RegSetValueExA(hkey_main, name1A, 0, REG_SZ, (const BYTE *)emptyA, 0);
+    ok(ret == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%d\n", ret, GetLastError());
+    test_hkey_main_Value_A(name1A, NULL, 0);
+    test_hkey_main_Value_W(name1W, NULL, 0);
+
+    /* test RegSetValueExA with an empty string */
+    ret = RegSetValueExA(hkey_main, name1A, 0, REG_SZ, (const BYTE *)emptyA, sizeof(emptyA));
+    ok(ret == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%d\n", ret, GetLastError());
+    test_hkey_main_Value_A(name1A, emptyA, sizeof(emptyA));
+    test_hkey_main_Value_W(name1W, emptyW, sizeof(emptyW));
+
+    /* test RegSetValueExA with off-by-one size */
+    ret = RegSetValueExA(hkey_main, name1A, 0, REG_SZ, (const BYTE *)string1A, sizeof(string1A)-sizeof(string1A[0]));
+    ok(ret == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%d\n", ret, GetLastError());
+    test_hkey_main_Value_A(name1A, string1A, sizeof(string1A));
+    test_hkey_main_Value_W(name1W, string1W, sizeof(string1W));
+
+    /* test RegSetValueExA with normal string */
+    ret = RegSetValueExA(hkey_main, name1A, 0, REG_SZ, (const BYTE *)string1A, sizeof(string1A));
+    ok(ret == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%d\n", ret, GetLastError());
+    test_hkey_main_Value_A(name1A, string1A, sizeof(string1A));
+    test_hkey_main_Value_W(name1W, string1W, sizeof(string1W));
+
+    /* test RegSetValueExA with intrazeroed string */
+    ret = RegSetValueExA(hkey_main, name2A, 0, REG_SZ, (const BYTE *)string2A, sizeof(string2A));
+    ok(ret == ERROR_SUCCESS, "RegSetValueExA failed: %d, GLE=%d\n", ret, GetLastError());
+    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 */
+        ret = RegSetValueW(hkey_main, NULL, REG_SZ, NULL, 0);
+        ok(ret == ERROR_INVALID_PARAMETER, "RegSetValueW should have failed with ERROR_INVALID_PARAMETER instead of %d\n", ret);
+    }
+
+    ret = RegSetValueW(hkey_main, NULL, REG_SZ, string1W, sizeof(string1W));
+    ok(ret == ERROR_SUCCESS, "RegSetValueW failed: %d, GLE=%d\n", ret, GetLastError());
+    test_hkey_main_Value_A(NULL, string1A, sizeof(string1A));
+    test_hkey_main_Value_W(NULL, string1W, sizeof(string1W));
+
+    /* RegSetValueA ignores the size passed in */
+    ret = RegSetValueW(hkey_main, NULL, REG_SZ, string1W, 4 * sizeof(string1W[0]));
+    ok(ret == ERROR_SUCCESS, "RegSetValueW failed: %d, GLE=%d\n", ret, GetLastError());
+    test_hkey_main_Value_A(NULL, string1A, sizeof(string1A));
+    test_hkey_main_Value_W(NULL, string1W, sizeof(string1W));
+
+    /* stops at first null */
+    ret = RegSetValueW(hkey_main, NULL, REG_SZ, string2W, sizeof(string2W));
+    ok(ret == ERROR_SUCCESS, "RegSetValueW failed: %d, GLE=%d\n", ret, GetLastError());
+    test_hkey_main_Value_A(NULL, substring2A, sizeof(substring2A));
+    test_hkey_main_Value_W(NULL, substring2W, sizeof(substring2W));
+
+    /* only REG_SZ is supported */
+    ret = RegSetValueW(hkey_main, NULL, REG_BINARY, string2W, sizeof(string2W));
+    ok(ret == ERROR_INVALID_PARAMETER, "RegSetValueW should have returned ERROR_INVALID_PARAMETER instead of %d\n", ret);
+    ret = RegSetValueW(hkey_main, NULL, REG_EXPAND_SZ, string2W, sizeof(string2W));
+    ok(ret == ERROR_INVALID_PARAMETER, "RegSetValueW should have returned ERROR_INVALID_PARAMETER instead of %d\n", ret);
+    ret = RegSetValueW(hkey_main, NULL, REG_MULTI_SZ, string2W, sizeof(string2W));
+    ok(ret == ERROR_INVALID_PARAMETER, "RegSetValueW should have returned ERROR_INVALID_PARAMETER instead of %d\n", ret);
+
+    /* test RegSetValueExW with off-by-one size */
+    ret = RegSetValueExW(hkey_main, name1W, 0, REG_SZ, (const BYTE *)string1W, sizeof(string1W)-sizeof(string1W[0]));
+    ok(ret == ERROR_SUCCESS, "RegSetValueExW failed: %d, GLE=%d\n", ret, GetLastError());
+    test_hkey_main_Value_A(name1A, string1A, sizeof(string1A));
+    test_hkey_main_Value_W(name1W, string1W, sizeof(string1W));
+
+    /* test RegSetValueExW with normal string */
+    ret = RegSetValueExW(hkey_main, name1W, 0, REG_SZ, (const BYTE *)string1W, sizeof(string1W));
+    ok(ret == ERROR_SUCCESS, "RegSetValueExW failed: %d, GLE=%d\n", ret, GetLastError());
+    test_hkey_main_Value_A(name1A, string1A, sizeof(string1A));
+    test_hkey_main_Value_W(name1W, string1W, sizeof(string1W));
+
+    /* test RegSetValueExW with intrazeroed string */
+    ret = RegSetValueExW(hkey_main, name2W, 0, REG_SZ, (const BYTE *)string2W, sizeof(string2W));
+    ok(ret == ERROR_SUCCESS, "RegSetValueExW failed: %d, GLE=%d\n", ret, GetLastError());
+    test_hkey_main_Value_A(name2A, string2A, sizeof(string2A));
+    test_hkey_main_Value_W(name2W, string2W, sizeof(string2W));
+}
+
 static void create_test_entries(void)
 {
+    static const DWORD qw[2] = { 0x12345678, 0x87654321 };
+
     SetEnvironmentVariableA("LONGSYSTEMVAR", "bar");
     SetEnvironmentVariableA("FOO", "ImARatherLongButIndeedNeededString");
 
-    ok(!RegSetValueExA(hkey_main,"Test1",0,REG_EXPAND_SZ, sTestpath1, strlen(sTestpath1)+1),
+    ok(!RegSetValueExA(hkey_main,"TP1_EXP_SZ",0,REG_EXPAND_SZ, (const BYTE *)sTestpath1, strlen(sTestpath1)+1), 
+        "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,"Test2",0,REG_SZ, sTestpath1, strlen(sTestpath1)+1),
+    ok(!RegSetValueExA(hkey_main,"TP1_ZB_SZ",0,REG_SZ, NULL, 0),
+       "RegSetValueExA failed\n");
+    ok(!RegSetValueExA(hkey_main,"TP2_EXP_SZ",0,REG_EXPAND_SZ, (const BYTE *)sTestpath2, strlen(sTestpath2)+1), 
         "RegSetValueExA failed\n");
-    ok(!RegSetValueExA(hkey_main,"Test3",0,REG_EXPAND_SZ, sTestpath2, strlen(sTestpath2)+1),
+    ok(!RegSetValueExA(hkey_main,"DWORD",0,REG_DWORD, (const BYTE *)qw, 4),
+        "RegSetValueExA failed\n");
+    ok(!RegSetValueExA(hkey_main,"BIN32",0,REG_BINARY, (const BYTE *)qw, 4),
+        "RegSetValueExA failed\n");
+    ok(!RegSetValueExA(hkey_main,"BIN64",0,REG_BINARY, (const BYTE *)qw, 8),
         "RegSetValueExA failed\n");
 }
-
+        
 static void test_enum_value(void)
 {
     DWORD res;
@@ -85,21 +458,21 @@ static void test_enum_value(void)
 
     /* create the working key for new 'Test' value */
     res = RegCreateKeyA( hkey_main, "TestKey", &test_key );
-    ok( res == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", res);
+    ok( res == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", res);
 
     /* check NULL data with zero length */
     res = RegSetValueExA( test_key, "Test", 0, REG_SZ, NULL, 0 );
     if (GetVersion() & 0x80000000)
-        ok( res == ERROR_INVALID_PARAMETER, "RegSetValueExA returned %ld\n", res );
+        ok( res == ERROR_INVALID_PARAMETER, "RegSetValueExA returned %d\n", res );
     else
-        ok( !res, "RegSetValueExA returned %ld\n", res );
+        ok( !res, "RegSetValueExA returned %d\n", res );
     res = RegSetValueExA( test_key, "Test", 0, REG_EXPAND_SZ, NULL, 0 );
-    ok( ERROR_SUCCESS == res || ERROR_INVALID_PARAMETER == res, "RegSetValueExA returned %ld\n", res );
+    ok( ERROR_SUCCESS == res || ERROR_INVALID_PARAMETER == res, "RegSetValueExA returned %d\n", res );
     res = RegSetValueExA( test_key, "Test", 0, REG_BINARY, NULL, 0 );
-    ok( ERROR_SUCCESS == res || ERROR_INVALID_PARAMETER == res, "RegSetValueExA returned %ld\n", res );
+    ok( ERROR_SUCCESS == res || ERROR_INVALID_PARAMETER == res, "RegSetValueExA returned %d\n", res );
 
-    res = RegSetValueExA( test_key, "Test", 0, REG_SZ, (BYTE *)"foobar", 7 );
-    ok( res == 0, "RegSetValueExA failed error %ld\n", res );
+    res = RegSetValueExA( test_key, "Test", 0, REG_SZ, (const BYTE *)"foobar", 7 );
+    ok( res == 0, "RegSetValueExA failed error %d\n", res );
 
     /* overflow both name and data */
     val_count = 2;
@@ -107,11 +480,11 @@ static void test_enum_value(void)
     type = 1234;
     strcpy( value, "xxxxxxxxxx" );
     strcpy( data, "xxxxxxxxxx" );
-    res = RegEnumValueA( test_key, 0, value, &val_count, NULL, &type, data, &data_count );
-    ok( res == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %ld\n", res );
-    ok( val_count == 2, "val_count set to %ld\n", val_count );
-    ok( data_count == 7, "data_count set to %ld instead of 7\n", data_count );
-    ok( type == REG_SZ, "type %ld is not REG_SZ\n", type );
+    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( 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 );
 
@@ -121,17 +494,17 @@ static void test_enum_value(void)
     type = 1234;
     strcpy( value, "xxxxxxxxxx" );
     strcpy( data, "xxxxxxxxxx" );
-    res = RegEnumValueA( test_key, 0, value, &val_count, NULL, &type, data, &data_count );
-    ok( res == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %ld\n", res );
+    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 %ld\n", val_count );
-    ok( data_count == 7, "data_count set to %ld instead of 7\n", data_count );
-    ok( type == REG_SZ, "type %ld is not REG_SZ\n", type );
-#if 0
-    /* v5.1.2600.0 (XP Home) does not touch value or data in this case */
-    ok( !strcmp( value, "Te" ), "value set to '%s' instead of 'Te'\n", value );
-    ok( !strcmp( data, "foobar" ), "data set to '%s' instead of 'foobar'\n", data );
-#endif
+    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( 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" ), 
+        "data set to '%s' instead of 'foobar' or 'xxxxxxx'\n", data );
 
     /* overflow empty name */
     val_count = 0;
@@ -139,16 +512,15 @@ static void test_enum_value(void)
     type = 1234;
     strcpy( value, "xxxxxxxxxx" );
     strcpy( data, "xxxxxxxxxx" );
-    res = RegEnumValueA( test_key, 0, value, &val_count, NULL, &type, data, &data_count );
-    ok( res == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %ld\n", res );
-    ok( val_count == 0, "val_count set to %ld\n", val_count );
-    ok( data_count == 7, "data_count set to %ld instead of 7\n", data_count );
-    ok( type == REG_SZ, "type %ld is not REG_SZ\n", type );
+    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( type == REG_SZ, "type %d is not REG_SZ\n", type );
     ok( !strcmp( value, "xxxxxxxxxx" ), "value set to '%s'\n", value );
-#if 0
-    /* v5.1.2600.0 (XP Home) does not touch data in this case */
-    ok( !strcmp( data, "foobar" ), "data set to '%s' instead of 'foobar'\n", data );
-#endif
+    /* v5.1.2600.0 (XP Home and Professional) does not touch data in this case */
+    ok( !strcmp( data, "foobar" ) || !strcmp( data, "xxxxxxx" ), 
+        "data set to '%s' instead of 'foobar' or 'xxxxxxx'\n", data );
 
     /* overflow data */
     val_count = 20;
@@ -156,11 +528,11 @@ static void test_enum_value(void)
     type = 1234;
     strcpy( value, "xxxxxxxxxx" );
     strcpy( data, "xxxxxxxxxx" );
-    res = RegEnumValueA( test_key, 0, value, &val_count, NULL, &type, data, &data_count );
-    ok( res == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %ld\n", res );
-    ok( val_count == 20, "val_count set to %ld\n", val_count );
-    ok( data_count == 7, "data_count set to %ld instead of 7\n", data_count );
-    ok( type == REG_SZ, "type %ld is not REG_SZ\n", type );
+    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 == 20, "val_count set to %d\n", val_count );
+    ok( data_count == 7, "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 );
 
@@ -170,21 +542,24 @@ static void test_enum_value(void)
     type = 1234;
     strcpy( value, "xxxxxxxxxx" );
     strcpy( data, "xxxxxxxxxx" );
-    res = RegEnumValueA( test_key, 0, value, &val_count, NULL, &type, data, &data_count );
-    ok( res == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", res );
-    ok( val_count == 4, "val_count set to %ld instead of 4\n", val_count );
-    ok( data_count == 7, "data_count set to %ld instead of 7\n", data_count );
-    ok( type == REG_SZ, "type %ld is not REG_SZ\n", type );
+    res = RegEnumValueA( test_key, 0, value, &val_count, NULL, &type, (LPBYTE)data, &data_count );
+    ok( res == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", res );
+    ok( val_count == 4, "val_count set to %d instead of 4\n", val_count );
+    ok( data_count == 7, "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, "Test" ), "value is '%s' instead of Test\n", value );
     ok( !strcmp( data, "foobar" ), "data is '%s' instead of foobar\n", data );
 
     /* Unicode tests */
 
-    SetLastError(0);
+    SetLastError(0xdeadbeef);
     res = RegSetValueExW( test_key, testW, 0, REG_SZ, (const BYTE *)foobarW, 7*sizeof(WCHAR) );
     if (res==0 && GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
-        return;
-    ok( res == 0, "RegSetValueExW failed error %ld\n", res );
+    {
+        skip("RegSetValueExW is not implemented\n");
+        goto cleanup;
+    }
+    ok( res == 0, "RegSetValueExW failed error %d\n", res );
 
     /* overflow both name and data */
     val_count = 2;
@@ -193,10 +568,10 @@ static void test_enum_value(void)
     memcpy( valueW, xxxW, sizeof(xxxW) );
     memcpy( dataW, xxxW, sizeof(xxxW) );
     res = RegEnumValueW( test_key, 0, valueW, &val_count, NULL, &type, (BYTE*)dataW, &data_count );
-    ok( res == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %ld\n", res );
-    ok( val_count == 2, "val_count set to %ld\n", val_count );
-    ok( data_count == 7*sizeof(WCHAR), "data_count set to %ld instead of 7*sizeof(WCHAR)\n", data_count );
-    ok( type == REG_SZ, "type %ld is not REG_SZ\n", type );
+    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*sizeof(WCHAR), "data_count set to %d instead of 7*sizeof(WCHAR)\n", data_count );
+    ok( type == REG_SZ, "type %d is not REG_SZ\n", type );
     ok( !memcmp( valueW, xxxW, sizeof(xxxW) ), "value modified\n" );
     ok( !memcmp( dataW, xxxW, sizeof(xxxW) ), "data modified\n" );
 
@@ -207,10 +582,10 @@ static void test_enum_value(void)
     memcpy( valueW, xxxW, sizeof(xxxW) );
     memcpy( dataW, xxxW, sizeof(xxxW) );
     res = RegEnumValueW( test_key, 0, valueW, &val_count, NULL, &type, (BYTE*)dataW, &data_count );
-    ok( res == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %ld\n", res );
-    ok( val_count == 3, "val_count set to %ld\n", val_count );
-    ok( data_count == 7*sizeof(WCHAR), "data_count set to %ld instead of 7*sizeof(WCHAR)\n", data_count );
-    ok( type == REG_SZ, "type %ld is not REG_SZ\n", type );
+    ok( res == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %d\n", res );
+    ok( val_count == 3, "val_count set to %d\n", val_count );
+    ok( data_count == 7*sizeof(WCHAR), "data_count set to %d instead of 7*sizeof(WCHAR)\n", data_count );
+    ok( type == REG_SZ, "type %d is not REG_SZ\n", type );
     ok( !memcmp( valueW, xxxW, sizeof(xxxW) ), "value modified\n" );
     ok( !memcmp( dataW, xxxW, sizeof(xxxW) ), "data modified\n" );
 
@@ -221,10 +596,10 @@ static void test_enum_value(void)
     memcpy( valueW, xxxW, sizeof(xxxW) );
     memcpy( dataW, xxxW, sizeof(xxxW) );
     res = RegEnumValueW( test_key, 0, valueW, &val_count, NULL, &type, (BYTE*)dataW, &data_count );
-    ok( res == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %ld\n", res );
-    ok( val_count == 4, "val_count set to %ld instead of 4\n", val_count );
-    ok( data_count == 7*sizeof(WCHAR), "data_count set to %ld instead of 7*sizeof(WCHAR)\n", data_count );
-    ok( type == REG_SZ, "type %ld is not REG_SZ\n", type );
+    ok( res == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %d\n", res );
+    ok( val_count == 4, "val_count set to %d instead of 4\n", val_count );
+    ok( data_count == 7*sizeof(WCHAR), "data_count set to %d instead of 7*sizeof(WCHAR)\n", data_count );
+    ok( type == REG_SZ, "type %d is not REG_SZ\n", type );
     ok( !memcmp( valueW, testW, sizeof(testW) ), "value is not 'Test'\n" );
     ok( !memcmp( dataW, xxxW, sizeof(xxxW) ), "data modified\n" );
 
@@ -235,27 +610,253 @@ static void test_enum_value(void)
     memcpy( valueW, xxxW, sizeof(xxxW) );
     memcpy( dataW, xxxW, sizeof(xxxW) );
     res = RegEnumValueW( test_key, 0, valueW, &val_count, NULL, &type, (BYTE*)dataW, &data_count );
-    ok( res == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", res );
-    ok( val_count == 4, "val_count set to %ld instead of 4\n", val_count );
-    ok( data_count == 7*sizeof(WCHAR), "data_count set to %ld instead of 7*sizeof(WCHAR)\n", data_count );
-    ok( type == REG_SZ, "type %ld is not REG_SZ\n", type );
+    ok( res == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", res );
+    ok( val_count == 4, "val_count set to %d instead of 4\n", val_count );
+    ok( data_count == 7*sizeof(WCHAR), "data_count set to %d instead of 7*sizeof(WCHAR)\n", data_count );
+    ok( type == REG_SZ, "type %d is not REG_SZ\n", type );
     ok( !memcmp( valueW, testW, sizeof(testW) ), "value is not 'Test'\n" );
     ok( !memcmp( dataW, foobarW, sizeof(foobarW) ), "data is not 'foobar'\n" );
+
+cleanup:
+    RegDeleteKeyA(test_key, "");
+    RegCloseKey(test_key);
 }
 
-static void test_query_value_ex()
+static void test_query_value_ex(void)
 {
     DWORD ret;
     DWORD size;
     DWORD type;
+    BYTE buffer[10];
+    
+    ret = RegQueryValueExA(hkey_main, "TP1_SZ", NULL, &type, NULL, &size);
+    ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
+    ok(size == strlen(sTestpath1) + 1, "(%d,%d)\n", (DWORD)strlen(sTestpath1) + 1, size);
+    ok(type == REG_SZ, "type %d is not REG_SZ\n", type);
+
+    type = 0xdeadbeef;
+    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);
+    }
 
-    ret = RegQueryValueExA(hkey_main, "Test2", NULL, &type, NULL, &size);
-    ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
-    ok(size == strlen(sTestpath1) + 1, "(%ld,%ld)\n", (DWORD)strlen(sTestpath1) + 1, size);
-    ok(type == REG_SZ, "type %ld is not REG_SZ\n", type);
+    size = sizeof(buffer);
+    ret = RegQueryValueExA(HKEY_CLASSES_ROOT, "Nonexistent Value", NULL, &type, buffer, &size);
+    ok(ret == ERROR_FILE_NOT_FOUND, "expected ERROR_FILE_NOT_FOUND, got %d\n", ret);
+    ok(size == sizeof(buffer), "size shouldn't have been changed to %d\n", size);
+
+    size = 4;
+    ret = RegQueryValueExA(hkey_main, "BIN32", NULL, &size, buffer, &size);
+    ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
 }
 
-static void test_reg_open_key()
+static void test_get_value(void)
+{
+    DWORD ret;
+    DWORD size;
+    DWORD type;
+    DWORD dw, qw[2];
+    CHAR buf[80];
+    CHAR expanded[] = "bar\\subdir1";
+    CHAR expanded2[] = "ImARatherLongButIndeedNeededString\\subdir1";
+   
+    if(!pRegGetValueA)
+    {
+        skip("RegGetValue not available on this platform\n");
+        return;
+    }
+
+    /* Invalid parameter */
+    ret = pRegGetValueA(hkey_main, NULL, "DWORD", RRF_RT_REG_DWORD, &type, &dw, NULL);
+    ok(ret == ERROR_INVALID_PARAMETER, "ret=%d\n", ret);
+
+    /* Query REG_DWORD using RRF_RT_REG_DWORD (ok) */
+    size = type = dw = 0xdeadbeef;
+    ret = pRegGetValueA(hkey_main, NULL, "DWORD", RRF_RT_REG_DWORD, &type, &dw, &size);
+    ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
+    ok(size == 4, "size=%d\n", size);
+    ok(type == REG_DWORD, "type=%d\n", type);
+    ok(dw == 0x12345678, "dw=%d\n", dw);
+
+    /* Query by subkey-name */
+    ret = pRegGetValueA(HKEY_CURRENT_USER, "Software\\Wine\\Test", "DWORD", RRF_RT_REG_DWORD, NULL, NULL, NULL);
+    ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
+
+    /* Query REG_DWORD using RRF_RT_REG_BINARY (restricted) */
+    size = type = dw = 0xdeadbeef;
+    ret = pRegGetValueA(hkey_main, NULL, "DWORD", RRF_RT_REG_BINARY, &type, &dw, &size);
+    ok(ret == ERROR_UNSUPPORTED_TYPE, "ret=%d\n", ret);
+    /* Although the function failed all values are retrieved */
+    ok(size == 4, "size=%d\n", size);
+    ok(type == REG_DWORD, "type=%d\n", type);
+    ok(dw == 0x12345678, "dw=%d\n", dw);
+
+    /* Test RRF_ZEROONFAILURE */
+    type = dw = 0xdeadbeef; size = 4;
+    ret = pRegGetValueA(hkey_main, NULL, "DWORD", RRF_RT_REG_SZ|RRF_ZEROONFAILURE, &type, &dw, &size);
+    ok(ret == ERROR_UNSUPPORTED_TYPE, "ret=%d\n", ret);
+    /* Again all values are retrieved ... */
+    ok(size == 4, "size=%d\n", size);
+    ok(type == REG_DWORD, "type=%d\n", type);
+    /* ... except the buffer, which is zeroed out */
+    ok(dw == 0, "dw=%d\n", dw);
+
+    /* Test RRF_ZEROONFAILURE with a NULL buffer... */
+    type = size = 0xbadbeef;
+    ret = pRegGetValueA(hkey_main, NULL, "DWORD", RRF_RT_REG_SZ|RRF_ZEROONFAILURE, &type, NULL, &size);
+    ok(ret == ERROR_UNSUPPORTED_TYPE, "ret=%d\n", ret);
+    ok(size == 4, "size=%d\n", size);
+    ok(type == REG_DWORD, "type=%d\n", type);
+
+    /* Query REG_DWORD using RRF_RT_DWORD (ok) */
+    size = type = dw = 0xdeadbeef;
+    ret = pRegGetValueA(hkey_main, NULL, "DWORD", RRF_RT_DWORD, &type, &dw, &size);
+    ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
+    ok(size == 4, "size=%d\n", size);
+    ok(type == REG_DWORD, "type=%d\n", type);
+    ok(dw == 0x12345678, "dw=%d\n", dw);
+
+    /* Query 32-bit REG_BINARY using RRF_RT_DWORD (ok) */
+    size = type = dw = 0xdeadbeef;
+    ret = pRegGetValueA(hkey_main, NULL, "BIN32", RRF_RT_DWORD, &type, &dw, &size);
+    ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
+    ok(size == 4, "size=%d\n", size);
+    ok(type == REG_BINARY, "type=%d\n", type);
+    ok(dw == 0x12345678, "dw=%d\n", dw);
+    
+    /* Query 64-bit REG_BINARY using RRF_RT_DWORD (type mismatch) */
+    qw[0] = qw[1] = size = type = 0xdeadbeef;
+    ret = pRegGetValueA(hkey_main, NULL, "BIN64", RRF_RT_DWORD, &type, qw, &size);
+    ok(ret == ERROR_DATATYPE_MISMATCH, "ret=%d\n", ret);
+    ok(size == 8, "size=%d\n", size);
+    ok(type == REG_BINARY, "type=%d\n", type);
+    ok(qw[0] == 0x12345678 && 
+       qw[1] == 0x87654321, "qw={%d,%d}\n", qw[0], qw[1]);
+    
+    /* Query 64-bit REG_BINARY using 32-bit buffer (buffer too small) */
+    type = dw = 0xdeadbeef; size = 4;
+    ret = pRegGetValueA(hkey_main, NULL, "BIN64", RRF_RT_REG_BINARY, &type, &dw, &size);
+    ok(ret == ERROR_MORE_DATA, "ret=%d\n", ret);
+    ok(dw == 0xdeadbeef, "dw=%d\n", dw);
+    ok(size == 8, "size=%d\n", size);
+
+    /* Query 64-bit REG_BINARY using RRF_RT_QWORD (ok) */
+    qw[0] = qw[1] = size = type = 0xdeadbeef;
+    ret = pRegGetValueA(hkey_main, NULL, "BIN64", RRF_RT_QWORD, &type, qw, &size);
+    ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
+    ok(size == 8, "size=%d\n", size);
+    ok(type == REG_BINARY, "type=%d\n", type);
+    ok(qw[0] == 0x12345678 &&
+       qw[1] == 0x87654321, "qw={%d,%d}\n", qw[0], qw[1]);
+
+    /* Query REG_SZ using RRF_RT_REG_SZ (ok) */
+    buf[0] = 0; type = 0xdeadbeef; size = sizeof(buf);
+    ret = pRegGetValueA(hkey_main, NULL, "TP1_SZ", RRF_RT_REG_SZ, &type, buf, &size);
+    ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
+    ok(size == strlen(sTestpath1)+1, "strlen(sTestpath1)=%d size=%d\n", lstrlenA(sTestpath1), size);
+    ok(type == REG_SZ, "type=%d\n", type);
+    ok(!strcmp(sTestpath1, buf), "sTestpath=\"%s\" buf=\"%s\"\n", sTestpath1, buf);
+
+    /* Query REG_SZ using RRF_RT_REG_SZ and no buffer (ok) */
+    type = 0xdeadbeef; size = 0;
+    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,
+       "strlen(sTestpath1)=%d size=%d\n", lstrlenA(sTestpath1), size);
+    ok(type == REG_SZ, "type=%d\n", type);
+
+    /* Query REG_SZ using RRF_RT_REG_SZ on a zero-byte value (ok) */
+    strcpy(buf, sTestpath1);
+    type = 0xdeadbeef;
+    size = sizeof(buf);
+    ret = pRegGetValueA(hkey_main, NULL, "TP1_ZB_SZ", RRF_RT_REG_SZ, &type, buf, &size);
+    ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
+    /* v5.2.3790.1830 (2003 SP1) returns sTestpath1 length + 2 here. */
+    ok(size == 0 ||
+       size == 1, /* win2k3 */
+       "size=%d\n", size);
+    ok(type == REG_SZ, "type=%d\n", type);
+    ok(!strcmp(sTestpath1, buf) ||
+       !strcmp(buf, ""),
+       "Expected \"%s\" or \"\", got \"%s\"\n", sTestpath1, buf);
+
+    /* Query REG_SZ using RRF_RT_REG_SZ|RRF_NOEXPAND (ok) */
+    buf[0] = 0; type = 0xdeadbeef; size = sizeof(buf);
+    ret = pRegGetValueA(hkey_main, NULL, "TP1_SZ", RRF_RT_REG_SZ|RRF_NOEXPAND, &type, buf, &size);
+    ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
+    ok(size == strlen(sTestpath1)+1, "strlen(sTestpath1)=%d size=%d\n", lstrlenA(sTestpath1), size);
+    ok(type == REG_SZ, "type=%d\n", type);
+    ok(!strcmp(sTestpath1, buf), "sTestpath=\"%s\" buf=\"%s\"\n", sTestpath1, buf);
+
+    /* Query REG_EXPAND_SZ using RRF_RT_REG_SZ and no buffer (ok, expands) */
+    size = 0;
+    ret = pRegGetValueA(hkey_main, NULL, "TP2_EXP_SZ", RRF_RT_REG_SZ, NULL, NULL, &size);
+    ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
+    ok((size == strlen(expanded2)+1) || /* win2k3 SP1 */
+       (size == strlen(expanded2)+2) || /* win2k3 SP2 */
+       (size == strlen(sTestpath2)+1),
+        "strlen(expanded2)=%d, strlen(sTestpath2)=%d, size=%d\n", lstrlenA(expanded2), lstrlenA(sTestpath2), size);
+
+    /* Query REG_EXPAND_SZ using RRF_RT_REG_SZ (ok, expands) */
+    buf[0] = 0; type = 0xdeadbeef; size = sizeof(buf);
+    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), 
+        "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);
+
+    /* Query REG_EXPAND_SZ using RRF_RT_REG_SZ (ok, expands a lot) */
+    buf[0] = 0; type = 0xdeadbeef; size = sizeof(buf);
+    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),
+        "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);
+
+    /* Query REG_EXPAND_SZ using RRF_RT_REG_EXPAND_SZ|RRF_NOEXPAND (ok, doesn't expand) */
+    buf[0] = 0; type = 0xdeadbeef; size = sizeof(buf);
+    ret = pRegGetValueA(hkey_main, NULL, "TP1_EXP_SZ", RRF_RT_REG_EXPAND_SZ|RRF_NOEXPAND, &type, buf, &size);
+    ok(ret == ERROR_SUCCESS, "ret=%d\n", ret);
+    ok(size == strlen(sTestpath1)+1, "strlen(sTestpath1)=%d size=%d\n", lstrlenA(sTestpath1), size);
+    ok(type == REG_EXPAND_SZ, "type=%d\n", type);
+    ok(!strcmp(sTestpath1, buf), "sTestpath=\"%s\" buf=\"%s\"\n", sTestpath1, buf);
+
+    /* Query REG_EXPAND_SZ using RRF_RT_REG_EXPAND_SZ|RRF_NOEXPAND and no buffer (ok, doesn't expand) */
+    size = 0xbadbeef;
+    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,
+       "strlen(sTestpath1)=%d size=%d\n", lstrlenA(sTestpath1), size);
+
+    /* Query REG_EXPAND_SZ using RRF_RT_REG_SZ|RRF_NOEXPAND (type mismatch) */
+    ret = pRegGetValueA(hkey_main, NULL, "TP1_EXP_SZ", RRF_RT_REG_SZ|RRF_NOEXPAND, NULL, NULL, NULL);
+    ok(ret == ERROR_UNSUPPORTED_TYPE, "ret=%d\n", ret);
+
+    /* 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);
+} 
+
+static void test_reg_open_key(void)
 {
     DWORD ret = 0;
     HKEY hkResult = NULL;
@@ -263,52 +864,57 @@ static void test_reg_open_key()
 
     /* successful open */
     ret = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Test", &hkResult);
-    ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
+    ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
     ok(hkResult != NULL, "expected hkResult != NULL\n");
     hkPreserve = hkResult;
 
-    /* open same key twice */
-    ret = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Test", &hkResult);
-    ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\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 %ld\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 %ld\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 %ld\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 %ld\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 %ld\n", ret);
-    ok(hkResult == NULL, "expected hkResult == NULL\n");
+    /* 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");
+    }
 
     /* only send NULL hKey
      * the value of hkResult remains unchanged
@@ -316,16 +922,47 @@ static void test_reg_open_key()
     hkResult = hkPreserve;
     ret = RegOpenKeyA(NULL, "Software\\Wine\\Test", &hkResult);
     ok(ret == ERROR_INVALID_HANDLE || ret == ERROR_BADKEY, /* Windows 95 returns BADKEY */
-       "expected ERROR_INVALID_HANDLE or ERROR_BADKEY, got %ld\n", ret);
+       "expected ERROR_INVALID_HANDLE or ERROR_BADKEY, got %d\n", ret);
     ok(hkResult == hkPreserve, "expected hkResult == hkPreserve\n");
     RegCloseKey(hkResult);
 
     /* send in NULL hkResult */
     ret = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Test", NULL);
-    ok(ret == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %ld\n", ret);
+    ok(ret == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %d\n", ret);
+
+    /*  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 */
+           , "expected ERROR_BAD_PATHNAME or ERROR_FILE_NOT_FOUND, got %d\n", ret);
 }
 
-static void test_reg_close_key()
+static void test_reg_create_key(void)
+{
+    LONG ret;
+    HKEY hkey1, hkey2;
+    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
+     * to the parent handle */
+    ret = RegCreateKeyExA(hkey1, "Subkey2", 0, NULL, 0, KEY_SET_VALUE, NULL, &hkey2, NULL);
+    ok(!ret, "RegCreateKeyExA failed with error %d\n", ret);
+
+    /* clean up */
+    RegDeleteKey(hkey2, "");
+    RegDeleteKey(hkey1, "");
+
+    /*  beginning backslash character */
+    ret = RegCreateKeyExA(hkey_main, "\\Subkey3", 0, NULL, 0, KEY_NOTIFY, NULL, &hkey1, NULL);
+    if (!(GetVersion() & 0x80000000))
+        ok(ret == ERROR_BAD_PATHNAME, "expected ERROR_BAD_PATHNAME, got %d\n", ret);
+    else {
+        ok(!ret, "RegCreateKeyExA failed with error %d\n", ret);
+        RegDeleteKey(hkey1, NULL);
+    }
+}
+
+static void test_reg_close_key(void)
 {
     DWORD ret = 0;
     HKEY hkHandle;
@@ -335,69 +972,83 @@ static void test_reg_close_key()
      */
     ret = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Test", &hkHandle);
     ret = RegCloseKey(hkHandle);
-    ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
+    ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
 
     /* try to close the key twice */
     ret = RegCloseKey(hkHandle); /* Windows 95 doesn't mind. */
     ok(ret == ERROR_INVALID_HANDLE || ret == ERROR_SUCCESS,
-       "expected ERROR_INVALID_HANDLE or ERROR_SUCCESS, got %ld\n", ret);
-
+       "expected ERROR_INVALID_HANDLE or ERROR_SUCCESS, got %d\n", ret);
+    
     /* try to close a NULL handle */
     ret = RegCloseKey(NULL);
     ok(ret == ERROR_INVALID_HANDLE || ret == ERROR_BADKEY, /* Windows 95 returns BADKEY */
-       "expected ERROR_INVALID_HANDLE or ERROR_BADKEY, got %ld\n", ret);
+       "expected ERROR_INVALID_HANDLE or ERROR_BADKEY, got %d\n", ret);
+
+    /* Check to see if we didn't potentially close our main handle, which could happen on win98 as
+     * win98 doesn't give a new handle when the same key is opened.
+     * Not re-opening will make some next tests fail.
+     */
+    if (hkey_main == hkHandle)
+    {
+        trace("The main handle is most likely closed, so re-opening\n");
+        RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\Test", &hkey_main );
+    }
 }
 
-static void test_reg_delete_key()
+static void test_reg_delete_key(void)
 {
     DWORD ret;
-    HKEY hkResult = NULL;
 
     ret = RegDeleteKey(hkey_main, NULL);
-    ok(ret == ERROR_INVALID_PARAMETER || ret == ERROR_ACCESS_DENIED,
-       "expected ERROR_INVALID_PARAMETER or ERROR_ACCESS_DENIED, got %ld\n", ret);
-
-    ret = RegCreateKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Tost", &hkResult);
-
-    ret = RegDeleteValue(hkResult, "noExists");
-    ok(ret == ERROR_FILE_NOT_FOUND, "expected ERROR_FILE_NOT_FOUND, got %ld\n", ret);
-
-    ret = RegDeleteKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Tost");
-
-    ret = RegCloseKey(hkResult);
 
+    /* There is a bug in NT4 and W2K that doesn't check if the subkey is NULL. If
+     * there are also no subkeys available it will delete the key pointed to by hkey_main.
+     * Not re-creating will make some next tests fail.
+     */
+    if (ret == ERROR_SUCCESS)
+    {
+        trace("We are probably running on NT4 or W2K as the main key is deleted,"
+            " re-creating the main key\n");
+        setup_main_key();
+    }
+    else
+        ok(ret == ERROR_INVALID_PARAMETER ||
+           ret == ERROR_ACCESS_DENIED ||
+           ret == ERROR_BADKEY, /* Win95 */
+           "ret=%d\n", ret);
 }
 
-static void test_reg_save_key()
+static void test_reg_save_key(void)
 {
     DWORD ret;
 
     ret = RegSaveKey(hkey_main, "saved_key", NULL);
-    ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
+    ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
 }
 
-static void test_reg_load_key()
+static void test_reg_load_key(void)
 {
     DWORD ret;
     HKEY hkHandle;
 
     ret = RegLoadKey(HKEY_LOCAL_MACHINE, "Test", "saved_key");
-    ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
+    ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
 
     ret = RegOpenKey(HKEY_LOCAL_MACHINE, "Test", &hkHandle);
-    ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
+    ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
 
     RegCloseKey(hkHandle);
 }
 
-static void test_reg_unload_key()
+static void test_reg_unload_key(void)
 {
     DWORD ret;
 
     ret = RegUnLoadKey(HKEY_LOCAL_MACHINE, "Test");
-    ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
+    ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %d\n", ret);
 
     DeleteFile("saved_key");
+    DeleteFile("saved_key.LOG");
 }
 
 static BOOL set_privileges(LPCSTR privilege, BOOL set)
@@ -417,7 +1068,7 @@ static BOOL set_privileges(LPCSTR privilege, BOOL set)
 
     tp.PrivilegeCount = 1;
     tp.Privileges[0].Luid = luid;
-
+    
     if (set)
         tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
     else
@@ -434,15 +1085,270 @@ static BOOL set_privileges(LPCSTR privilege, BOOL set)
     return TRUE;
 }
 
+/* tests that show that RegConnectRegistry and 
+   OpenSCManager accept computer names without the
+   \\ prefix (what MSDN says).   */
+static void test_regconnectregistry( void)
+{
+    CHAR compName[MAX_COMPUTERNAME_LENGTH + 1];
+    CHAR netwName[MAX_COMPUTERNAME_LENGTH + 3]; /* 2 chars for double backslash */
+    DWORD len = sizeof(compName) ;
+    BOOL ret;
+    LONG retl;
+    HKEY hkey;
+    SC_HANDLE schnd;
+
+    SetLastError(0xdeadbeef);
+    ret = GetComputerNameA(compName, &len);
+    ok( ret, "GetComputerName failed err = %d\n", GetLastError());
+    if( !ret) return;
+
+    lstrcpyA(netwName, "\\\\");
+    lstrcpynA(netwName+2, compName, MAX_COMPUTERNAME_LENGTH + 1);
+
+    retl = RegConnectRegistryA( compName, HKEY_LOCAL_MACHINE, &hkey);
+    ok( !retl ||
+        retl == ERROR_DLL_INIT_FAILED ||
+        retl == ERROR_BAD_NETPATH, /* some win2k */
+        "RegConnectRegistryA failed err = %d\n", retl);
+    if( !retl) RegCloseKey( hkey);
+
+    retl = RegConnectRegistryA( netwName, HKEY_LOCAL_MACHINE, &hkey);
+    ok( !retl ||
+        retl == ERROR_DLL_INIT_FAILED ||
+        retl == ERROR_BAD_NETPATH, /* some win2k */
+        "RegConnectRegistryA failed err = %d\n", retl);
+    if( !retl) RegCloseKey( hkey);
+
+    SetLastError(0xdeadbeef);
+    schnd = OpenSCManagerA( compName, NULL, GENERIC_READ); 
+    if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
+    {
+        skip("OpenSCManagerA is not implemented\n");
+        return;
+    }
+
+    ok( schnd != NULL, "OpenSCManagerA failed err = %d\n", GetLastError());
+    CloseServiceHandle( schnd);
+
+    SetLastError(0xdeadbeef);
+    schnd = OpenSCManagerA( netwName, NULL, GENERIC_READ); 
+    ok( schnd != NULL, "OpenSCManagerA failed err = %d\n", GetLastError());
+    CloseServiceHandle( schnd);
+
+}
+
+static void test_reg_query_value(void)
+{
+    HKEY subkey;
+    CHAR val[MAX_PATH];
+    WCHAR valW[5];
+    LONG size, ret;
+
+    static const WCHAR expected[] = {'d','a','t','a',0};
+
+    ret = RegCreateKeyA(hkey_main, "subkey", &subkey);
+    ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
+
+    ret = RegSetValueA(subkey, NULL, REG_SZ, "data", 4);
+    ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
+
+    /* try an invalid hkey */
+    SetLastError(0xdeadbeef);
+    size = MAX_PATH;
+    ret = RegQueryValueA((HKEY)0xcafebabe, "subkey", val, &size);
+    ok(ret == ERROR_INVALID_HANDLE || ret == ERROR_BADKEY, /* Windows 98 returns BADKEY */
+       "Expected ERROR_INVALID_HANDLE or ERROR_BADKEY, got %d\n", ret);
+    ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
+
+    /* try a NULL hkey */
+    SetLastError(0xdeadbeef);
+    size = MAX_PATH;
+    ret = RegQueryValueA(NULL, "subkey", val, &size);
+    ok(ret == ERROR_INVALID_HANDLE || ret == ERROR_BADKEY, /* Windows 98 returns BADKEY */
+       "Expected ERROR_INVALID_HANDLE or ERROR_BADKEY, got %d\n", ret);
+    ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
+
+    /* try a NULL value */
+    size = MAX_PATH;
+    ret = RegQueryValueA(hkey_main, "subkey", NULL, &size);
+    ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
+    ok(size == 5, "Expected 5, got %d\n", size);
+
+    /* try a NULL size */
+    SetLastError(0xdeadbeef);
+    val[0] = '\0';
+    ret = RegQueryValueA(hkey_main, "subkey", val, NULL);
+    ok(ret == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", ret);
+    ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
+    ok(lstrlenA(val) == 0, "Expected val to be untouched, got %s\n", val);
+
+    /* try a NULL value and size */
+    ret = RegQueryValueA(hkey_main, "subkey", NULL, NULL);
+    ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
+
+    /* try a size too small */
+    SetLastError(0xdeadbeef);
+    val[0] = '\0';
+    size = 1;
+    ret = RegQueryValueA(hkey_main, "subkey", val, &size);
+    ok(ret == ERROR_MORE_DATA, "Expected ERROR_MORE_DATA, got %d\n", ret);
+    ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
+    ok(lstrlenA(val) == 0, "Expected val to be untouched, got %s\n", val);
+    ok(size == 5, "Expected 5, got %d\n", size);
+
+    /* successfully read the value using 'subkey' */
+    size = MAX_PATH;
+    ret = RegQueryValueA(hkey_main, "subkey", val, &size);
+    ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
+    ok(!lstrcmpA(val, "data"), "Expected 'data', got '%s'\n", val);
+    ok(size == 5, "Expected 5, got %d\n", size);
+
+    /* successfully read the value using the subkey key */
+    size = MAX_PATH;
+    ret = RegQueryValueA(subkey, NULL, val, &size);
+    ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
+    ok(!lstrcmpA(val, "data"), "Expected 'data', got '%s'\n", val);
+    ok(size == 5, "Expected 5, got %d\n", size);
+
+    /* unicode - try size too small */
+    SetLastError(0xdeadbeef);
+    valW[0] = '\0';
+    size = 0;
+    ret = RegQueryValueW(subkey, NULL, valW, &size);
+    if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
+    {
+        skip("RegQueryValueW is not implemented\n");
+        goto cleanup;
+    }
+    ok(ret == ERROR_MORE_DATA, "Expected ERROR_MORE_DATA, got %d\n", ret);
+    ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
+    ok(lstrlenW(valW) == 0, "Expected valW to be untouched\n");
+    ok(size == sizeof(expected), "Got wrong size: %d\n", size);
+
+    /* unicode - try size in WCHARS */
+    SetLastError(0xdeadbeef);
+    size = sizeof(valW) / sizeof(WCHAR);
+    ret = RegQueryValueW(subkey, NULL, valW, &size);
+    ok(ret == ERROR_MORE_DATA, "Expected ERROR_MORE_DATA, got %d\n", ret);
+    ok(GetLastError() == 0xdeadbeef, "Expected 0xdeadbeef, got %d\n", GetLastError());
+    ok(lstrlenW(valW) == 0, "Expected valW to be untouched\n");
+    ok(size == sizeof(expected), "Got wrong size: %d\n", size);
+
+    /* unicode - successfully read the value */
+    size = sizeof(valW);
+    ret = RegQueryValueW(subkey, NULL, valW, &size);
+    ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
+    ok(!lstrcmpW(valW, expected), "Got wrong value\n");
+    ok(size == sizeof(expected), "Got wrong size: %d\n", size);
+
+    /* unicode - set the value without a NULL terminator */
+    ret = RegSetValueW(subkey, NULL, REG_SZ, expected, sizeof(expected)-sizeof(WCHAR));
+    ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
+
+    /* unicode - read the unterminated value, value is terminated for us */
+    memset(valW, 'a', sizeof(valW));
+    size = sizeof(valW);
+    ret = RegQueryValueW(subkey, NULL, valW, &size);
+    ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
+    ok(!lstrcmpW(valW, expected), "Got wrong value\n");
+    ok(size == sizeof(expected), "Got wrong size: %d\n", size);
+
+cleanup:
+    RegDeleteKeyA(subkey, "");
+    RegCloseKey(subkey);
+}
+
+static void test_reg_delete_tree(void)
+{
+    CHAR buffer[MAX_PATH];
+    HKEY subkey, subkey2;
+    LONG size, ret;
+
+    if(!pRegDeleteTreeA) {
+        skip("Skipping RegDeleteTreeA tests, function not present\n");
+        return;
+    }
+
+    ret = RegCreateKeyA(hkey_main, "subkey", &subkey);
+    ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
+    ret = RegCreateKeyA(subkey, "subkey2", &subkey2);
+    ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
+    ret = RegSetValueA(subkey, NULL, REG_SZ, "data", 4);
+    ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
+    ret = RegSetValueA(subkey2, NULL, REG_SZ, "data2", 5);
+    ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
+    ret = RegCloseKey(subkey2);
+    ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
+
+    ret = pRegDeleteTreeA(subkey, "subkey2");
+    ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
+    ok(RegOpenKeyA(subkey, "subkey2", &subkey2),
+        "subkey2 was not deleted\n");
+    size = MAX_PATH;
+    ok(!RegQueryValueA(subkey, NULL, buffer, &size),
+        "Default value of subkey not longer present\n");
+
+    ret = RegCreateKeyA(subkey, "subkey2", &subkey2);
+    ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
+    ret = RegCloseKey(subkey2);
+    ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
+    ret = pRegDeleteTreeA(hkey_main, "subkey\\subkey2");
+    ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
+    ok(RegOpenKeyA(subkey, "subkey2", &subkey2),
+        "subkey2 was not deleted\n");
+    ok(!RegQueryValueA(subkey, NULL, buffer, &size),
+        "Default value of subkey not longer present\n");
+
+    ret = RegCreateKeyA(subkey, "subkey2", &subkey2);
+    ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
+    ret = RegCloseKey(subkey2);
+    ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
+    ret = RegCreateKeyA(subkey, "subkey3", &subkey2);
+    ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
+    ret = RegCloseKey(subkey2);
+    ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
+    ret = RegSetValueA(subkey, "value", REG_SZ, "data2", 5);
+    ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
+    ret = pRegDeleteTreeA(subkey, NULL);
+    ok(ret == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", ret);
+    ok(!RegOpenKeyA(hkey_main, "subkey", &subkey),
+        "subkey was deleted\n");
+    ok(RegOpenKeyA(subkey, "subkey2", &subkey2),
+        "subkey2 was not deleted\n");
+    ok(RegOpenKeyA(subkey, "subkey3", &subkey2),
+        "subkey3 was not deleted\n");
+    size = MAX_PATH;
+    ret = RegQueryValueA(subkey, NULL, buffer, &size);
+    ok(ret == ERROR_SUCCESS,
+        "Default value of subkey is not present\n");
+    ok(!lstrlenA(buffer),
+        "Expected length 0 got length %u(%s)\n", lstrlenA(buffer), buffer);
+    size = MAX_PATH;
+    ok(RegQueryValueA(subkey, "value", buffer, &size),
+        "Value is still present\n");
+
+    ret = pRegDeleteTreeA(hkey_main, "not-here");
+    ok(ret == ERROR_FILE_NOT_FOUND,
+        "Expected ERROR_FILE_NOT_FOUND, got %d\n", ret);
+}
+
 START_TEST(registry)
 {
+    /* Load pointers for functions that are not available in all Windows versions */
+    InitFunctionPtrs();
+
     setup_main_key();
+    test_set_value();
     create_test_entries();
     test_enum_value();
     test_query_value_ex();
+    test_get_value();
     test_reg_open_key();
+    test_reg_create_key();
     test_reg_close_key();
     test_reg_delete_key();
+    test_reg_query_value();
 
     /* SaveKey/LoadKey require the SE_BACKUP_NAME privilege to be set */
     if (set_privileges(SE_BACKUP_NAME, TRUE) &&
@@ -455,6 +1361,11 @@ START_TEST(registry)
         set_privileges(SE_BACKUP_NAME, FALSE);
         set_privileges(SE_RESTORE_NAME, FALSE);
     }
+
+    test_reg_delete_tree();
+
     /* cleanup */
     delete_key( hkey_main );
+    
+    test_regconnectregistry();
 }
index d47366f..d393f11 100644 (file)
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
-#define _WIN32_WINNT 0x0501
-
+#include <stdarg.h>
 #include <stdio.h>
 
-#include "wine/test.h"
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
 #include "windef.h"
 #include "winbase.h"
 #include "winerror.h"
 #include "aclapi.h"
 #include "winnt.h"
+#include "sddl.h"
+#include "ntsecapi.h"
+#include "lmcons.h"
+
+#include "wine/test.h"
+
+/* copied from Wine winternl.h - not included in the Windows SDK */
+typedef enum _OBJECT_INFORMATION_CLASS {
+    ObjectBasicInformation,
+    ObjectNameInformation,
+    ObjectTypeInformation,
+    ObjectAllInformation,
+    ObjectDataInformation
+} OBJECT_INFORMATION_CLASS, *POBJECT_INFORMATION_CLASS;
+
+typedef struct _OBJECT_BASIC_INFORMATION {
+    ULONG  Attributes;
+    ACCESS_MASK  GrantedAccess;
+    ULONG  HandleCount;
+    ULONG  PointerCount;
+    ULONG  PagedPoolUsage;
+    ULONG  NonPagedPoolUsage;
+    ULONG  Reserved[3];
+    ULONG  NameInformationLength;
+    ULONG  TypeInformationLength;
+    ULONG  SecurityDescriptorLength;
+    LARGE_INTEGER  CreateTime;
+} OBJECT_BASIC_INFORMATION, *POBJECT_BASIC_INFORMATION;
+
+#define expect_eq(expr, value, type, format) { type ret = expr; ok((value) == ret, #expr " expected " format "  got " format "\n", (value), (ret)); }
 
-typedef BOOL (WINAPI *fnBuildTrusteeWithSidA)( TRUSTEE *trustee, PSID psid );
-typedef BOOL (WINAPI *fnBuildTrusteeWithNameA)( TRUSTEE *trustee, LPSTR str );
+static BOOL (WINAPI *pAddAccessAllowedAceEx)(PACL, DWORD, DWORD, DWORD, PSID);
+static BOOL (WINAPI *pAddAccessDeniedAceEx)(PACL, DWORD, DWORD, DWORD, PSID);
+static BOOL (WINAPI *pAddAuditAccessAceEx)(PACL, DWORD, DWORD, DWORD, PSID, BOOL, BOOL);
+typedef VOID (WINAPI *fnBuildTrusteeWithSidA)( PTRUSTEEA pTrustee, PSID pSid );
+typedef VOID (WINAPI *fnBuildTrusteeWithNameA)( PTRUSTEEA pTrustee, LPSTR pName );
+typedef VOID (WINAPI *fnBuildTrusteeWithObjectsAndNameA)( PTRUSTEEA pTrustee,
+                                                          POBJECTS_AND_NAME_A pObjName,
+                                                          SE_OBJECT_TYPE ObjectType,
+                                                          LPSTR ObjectTypeName,
+                                                          LPSTR InheritedObjectTypeName,
+                                                          LPSTR Name );
+typedef VOID (WINAPI *fnBuildTrusteeWithObjectsAndSidA)( PTRUSTEEA pTrustee,
+                                                         POBJECTS_AND_SID pObjSid,
+                                                         GUID* pObjectGuid,
+                                                         GUID* pInheritedObjectGuid,
+                                                         PSID pSid );
+typedef LPSTR (WINAPI *fnGetTrusteeNameA)( PTRUSTEEA pTrustee );
+typedef BOOL (WINAPI *fnMakeSelfRelativeSD)( PSECURITY_DESCRIPTOR, PSECURITY_DESCRIPTOR, LPDWORD );
 typedef BOOL (WINAPI *fnConvertSidToStringSidA)( PSID pSid, LPSTR *str );
 typedef BOOL (WINAPI *fnConvertStringSidToSidA)( LPCSTR str, PSID pSid );
+static BOOL (WINAPI *pConvertStringSecurityDescriptorToSecurityDescriptorA)(LPCSTR, DWORD,
+                                                                            PSECURITY_DESCRIPTOR*, PULONG );
+static BOOL (WINAPI *pConvertSecurityDescriptorToStringSecurityDescriptorA)(PSECURITY_DESCRIPTOR, DWORD,
+                                                                            SECURITY_INFORMATION, LPSTR *, PULONG );
 typedef BOOL (WINAPI *fnGetFileSecurityA)(LPCSTR, SECURITY_INFORMATION,
                                           PSECURITY_DESCRIPTOR, DWORD, LPDWORD);
+static DWORD (WINAPI *pGetNamedSecurityInfoA)(LPSTR, SE_OBJECT_TYPE, SECURITY_INFORMATION,
+                                              PSID*, PSID*, PACL*, PACL*,
+                                              PSECURITY_DESCRIPTOR*);
+typedef DWORD (WINAPI *fnRtlAdjustPrivilege)(ULONG,BOOLEAN,BOOLEAN,PBOOLEAN);
+typedef BOOL (WINAPI *fnCreateWellKnownSid)(WELL_KNOWN_SID_TYPE,PSID,PSID,DWORD*);
+typedef BOOL (WINAPI *fnDuplicateTokenEx)(HANDLE,DWORD,LPSECURITY_ATTRIBUTES,
+                                        SECURITY_IMPERSONATION_LEVEL,TOKEN_TYPE,PHANDLE);
+
+typedef NTSTATUS (WINAPI *fnLsaQueryInformationPolicy)(LSA_HANDLE,POLICY_INFORMATION_CLASS,PVOID*);
+typedef NTSTATUS (WINAPI *fnLsaClose)(LSA_HANDLE);
+typedef NTSTATUS (WINAPI *fnLsaFreeMemory)(PVOID);
+typedef NTSTATUS (WINAPI *fnLsaOpenPolicy)(PLSA_UNICODE_STRING,PLSA_OBJECT_ATTRIBUTES,ACCESS_MASK,PLSA_HANDLE);
+static NTSTATUS (WINAPI *pNtQueryObject)(HANDLE,OBJECT_INFORMATION_CLASS,PVOID,ULONG,PULONG);
+static DWORD (WINAPI *pSetEntriesInAclW)(ULONG, PEXPLICIT_ACCESSW, PACL, PACL*);
+static BOOL (WINAPI *pSetSecurityDescriptorControl)(PSECURITY_DESCRIPTOR, SECURITY_DESCRIPTOR_CONTROL,
+                                                    SECURITY_DESCRIPTOR_CONTROL);
 
 static HMODULE hmod;
+static int     myARGC;
+static char**  myARGV;
 
 fnBuildTrusteeWithSidA   pBuildTrusteeWithSidA;
 fnBuildTrusteeWithNameA  pBuildTrusteeWithNameA;
+fnBuildTrusteeWithObjectsAndNameA pBuildTrusteeWithObjectsAndNameA;
+fnBuildTrusteeWithObjectsAndSidA pBuildTrusteeWithObjectsAndSidA;
+fnGetTrusteeNameA pGetTrusteeNameA;
+fnMakeSelfRelativeSD pMakeSelfRelativeSD;
 fnConvertSidToStringSidA pConvertSidToStringSidA;
 fnConvertStringSidToSidA pConvertStringSidToSidA;
 fnGetFileSecurityA pGetFileSecurityA;
+fnRtlAdjustPrivilege pRtlAdjustPrivilege;
+fnCreateWellKnownSid pCreateWellKnownSid;
+fnDuplicateTokenEx pDuplicateTokenEx;
+fnLsaQueryInformationPolicy pLsaQueryInformationPolicy;
+fnLsaClose pLsaClose;
+fnLsaFreeMemory pLsaFreeMemory;
+fnLsaOpenPolicy pLsaOpenPolicy;
 
 struct sidRef
 {
@@ -52,10 +131,52 @@ struct sidRef
 
 static void init(void)
 {
+    HMODULE hntdll;
+
+    hntdll = GetModuleHandleA("ntdll.dll");
+    pNtQueryObject = (void *)GetProcAddress( hntdll, "NtQueryObject" );
+
     hmod = GetModuleHandle("advapi32.dll");
+    pAddAccessAllowedAceEx = (void *)GetProcAddress(hmod, "AddAccessAllowedAceEx");
+    pAddAccessDeniedAceEx = (void *)GetProcAddress(hmod, "AddAccessDeniedAceEx");
+    pAddAuditAccessAceEx = (void *)GetProcAddress(hmod, "AddAuditAccessAceEx");
+    pConvertStringSecurityDescriptorToSecurityDescriptorA =
+        (void *)GetProcAddress(hmod, "ConvertStringSecurityDescriptorToSecurityDescriptorA" );
+    pConvertSecurityDescriptorToStringSecurityDescriptorA =
+        (void *)GetProcAddress(hmod, "ConvertSecurityDescriptorToStringSecurityDescriptorA" );
+    pCreateWellKnownSid = (fnCreateWellKnownSid)GetProcAddress( hmod, "CreateWellKnownSid" );
+    pGetNamedSecurityInfoA = (void *)GetProcAddress(hmod, "GetNamedSecurityInfoA");
+    pMakeSelfRelativeSD = (void *)GetProcAddress(hmod, "MakeSelfRelativeSD");
+    pSetEntriesInAclW = (void *)GetProcAddress(hmod, "SetEntriesInAclW");
+    pSetSecurityDescriptorControl = (void *)GetProcAddress(hmod, "SetSecurityDescriptorControl");
+
+    myARGC = winetest_get_mainargs( &myARGV );
+}
+
+static void test_str_sid(const char *str_sid)
+{
+    PSID psid;
+    char *temp;
+
+    if (pConvertStringSidToSidA(str_sid, &psid))
+    {
+        if (pConvertSidToStringSidA(psid, &temp))
+        {
+            trace(" %s: %s\n", str_sid, temp);
+            LocalFree(temp);
+        }
+        LocalFree(psid);
+    }
+    else
+    {
+        if (GetLastError() != ERROR_INVALID_SID)
+            trace(" %s: couldn't be converted, returned %d\n", str_sid, GetLastError());
+        else
+            trace(" %s: couldn't be converted\n", str_sid);
+    }
 }
 
-void test_sid()
+static void test_sid(void)
 {
     struct sidRef refs[] = {
      { { {0x00,0x00,0x33,0x44,0x55,0x66} }, "S-1-860116326-1" },
@@ -68,6 +189,7 @@ void test_sid()
     const char noSubAuthStr[] = "S-1-5";
     unsigned int i;
     PSID psid = NULL;
+    SID *pisid;
     BOOL r;
     LPSTR str = NULL;
 
@@ -85,26 +207,33 @@ void test_sid()
     if( GetLastError() == ERROR_CALL_NOT_IMPLEMENTED )
         return;
     ok( GetLastError() == ERROR_INVALID_PARAMETER,
-     "expected GetLastError() is ERROR_INVALID_PARAMETER, got %ld\n",
+     "expected GetLastError() is ERROR_INVALID_PARAMETER, got %d\n",
      GetLastError() );
 
     r = pConvertStringSidToSidA( refs[0].refStr, NULL );
     ok( !r && GetLastError() == ERROR_INVALID_PARAMETER,
-     "expected GetLastError() is ERROR_INVALID_PARAMETER, got %ld\n",
+     "expected GetLastError() is ERROR_INVALID_PARAMETER, got %d\n",
      GetLastError() );
 
     r = pConvertStringSidToSidA( NULL, &str );
     ok( !r && GetLastError() == ERROR_INVALID_PARAMETER,
-     "expected GetLastError() is ERROR_INVALID_PARAMETER, got %ld\n",
+     "expected GetLastError() is ERROR_INVALID_PARAMETER, got %d\n",
      GetLastError() );
 
     r = pConvertStringSidToSidA( noSubAuthStr, &psid );
     ok( !r,
      "expected failure with no sub authorities\n" );
     ok( GetLastError() == ERROR_INVALID_SID,
-     "expected GetLastError() is ERROR_INVALID_SID, got %ld\n",
+     "expected GetLastError() is ERROR_INVALID_SID, got %d\n",
      GetLastError() );
 
+    ok(pConvertStringSidToSidA("S-1-5-21-93476-23408-4576", &psid), "ConvertStringSidToSidA failed\n");
+    pisid = (SID *)psid;
+    ok(pisid->SubAuthorityCount == 4, "Invalid sub authority count - expected 4, got %d\n", pisid->SubAuthorityCount);
+    ok(pisid->SubAuthority[0] == 21, "Invalid subauthority 0 - expceted 21, got %d\n", pisid->SubAuthority[0]);
+    ok(pisid->SubAuthority[3] == 4576, "Invalid subauthority 0 - expceted 4576, got %d\n", pisid->SubAuthority[3]);
+    LocalFree(str);
+
     for( i = 0; i < sizeof(refs) / sizeof(refs[0]); i++ )
     {
         PISID pisid;
@@ -130,7 +259,7 @@ void test_sid()
          !memcmp( pisid->IdentifierAuthority.Value, refs[i].auth.Value,
          sizeof(refs[i].auth) ),
          "string sid %s didn't parse to expected value\n"
-         "(got 0x%04x%08lx, expected 0x%04x%08lx)\n",
+         "(got 0x%04x%08x, expected 0x%04x%08x)\n",
          refs[i].refStr,
          MAKEWORD( pisid->IdentifierAuthority.Value[1],
          pisid->IdentifierAuthority.Value[0] ),
@@ -144,21 +273,77 @@ void test_sid()
         if( psid )
             LocalFree( psid );
     }
+
+    trace("String SIDs:\n");
+    test_str_sid("AO");
+    test_str_sid("RU");
+    test_str_sid("AN");
+    test_str_sid("AU");
+    test_str_sid("BA");
+    test_str_sid("BG");
+    test_str_sid("BO");
+    test_str_sid("BU");
+    test_str_sid("CA");
+    test_str_sid("CG");
+    test_str_sid("CO");
+    test_str_sid("DA");
+    test_str_sid("DC");
+    test_str_sid("DD");
+    test_str_sid("DG");
+    test_str_sid("DU");
+    test_str_sid("EA");
+    test_str_sid("ED");
+    test_str_sid("WD");
+    test_str_sid("PA");
+    test_str_sid("IU");
+    test_str_sid("LA");
+    test_str_sid("LG");
+    test_str_sid("LS");
+    test_str_sid("SY");
+    test_str_sid("NU");
+    test_str_sid("NO");
+    test_str_sid("NS");
+    test_str_sid("PO");
+    test_str_sid("PS");
+    test_str_sid("PU");
+    test_str_sid("RS");
+    test_str_sid("RD");
+    test_str_sid("RE");
+    test_str_sid("RC");
+    test_str_sid("SA");
+    test_str_sid("SO");
+    test_str_sid("SU");
 }
 
-void test_trustee()
+static void test_trustee(void)
 {
+    GUID ObjectType = {0x12345678, 0x1234, 0x5678, {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}};
+    GUID InheritedObjectType = {0x23456789, 0x2345, 0x6786, {0x2, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99}};
+    GUID ZeroGuid;
+    OBJECTS_AND_NAME_ oan;
+    OBJECTS_AND_SID oas;
     TRUSTEE trustee;
     PSID psid;
-    LPSTR str = "2jjj";
-
+    char szObjectTypeName[] = "ObjectTypeName";
+    char szInheritedObjectTypeName[] = "InheritedObjectTypeName";
+    char szTrusteeName[] = "szTrusteeName";
     SID_IDENTIFIER_AUTHORITY auth = { {0x11,0x22,0,0,0, 0} };
 
+    memset( &ZeroGuid, 0x00, sizeof (ZeroGuid) );
+
     pBuildTrusteeWithSidA = (fnBuildTrusteeWithSidA)
                     GetProcAddress( hmod, "BuildTrusteeWithSidA" );
     pBuildTrusteeWithNameA = (fnBuildTrusteeWithNameA)
                     GetProcAddress( hmod, "BuildTrusteeWithNameA" );
-    if( !pBuildTrusteeWithSidA || !pBuildTrusteeWithNameA)
+    pBuildTrusteeWithObjectsAndNameA = (fnBuildTrusteeWithObjectsAndNameA)
+                    GetProcAddress (hmod, "BuildTrusteeWithObjectsAndNameA" );
+    pBuildTrusteeWithObjectsAndSidA = (fnBuildTrusteeWithObjectsAndSidA)
+                    GetProcAddress (hmod, "BuildTrusteeWithObjectsAndSidA" );
+    pGetTrusteeNameA = (fnGetTrusteeNameA)
+                    GetProcAddress (hmod, "GetTrusteeNameA" );
+    if( !pBuildTrusteeWithSidA || !pBuildTrusteeWithNameA ||
+        !pBuildTrusteeWithObjectsAndNameA || !pBuildTrusteeWithObjectsAndSidA ||
+        !pGetTrusteeNameA )
         return;
 
     if ( ! AllocateAndInitializeSid( &auth, 1, 42, 0,0,0,0,0,0,0,&psid ) )
@@ -167,29 +352,122 @@ void test_trustee()
        return;
     }
 
+    /* test BuildTrusteeWithSidA */
     memset( &trustee, 0xff, sizeof trustee );
     pBuildTrusteeWithSidA( &trustee, psid );
 
     ok( trustee.pMultipleTrustee == NULL, "pMultipleTrustee wrong\n");
-    ok( trustee.MultipleTrusteeOperation == NO_MULTIPLE_TRUSTEE,
+    ok( trustee.MultipleTrusteeOperation == NO_MULTIPLE_TRUSTEE, 
         "MultipleTrusteeOperation wrong\n");
     ok( trustee.TrusteeForm == TRUSTEE_IS_SID, "TrusteeForm wrong\n");
     ok( trustee.TrusteeType == TRUSTEE_IS_UNKNOWN, "TrusteeType wrong\n");
     ok( trustee.ptstrName == (LPSTR) psid, "ptstrName wrong\n" );
+
+    /* test BuildTrusteeWithObjectsAndSidA (test 1) */
+    memset( &trustee, 0xff, sizeof trustee );
+    memset( &oas, 0xff, sizeof(oas) );
+    pBuildTrusteeWithObjectsAndSidA(&trustee, &oas, &ObjectType,
+                                    &InheritedObjectType, psid);
+
+    ok(trustee.pMultipleTrustee == NULL, "pMultipleTrustee wrong\n");
+    ok(trustee.MultipleTrusteeOperation == NO_MULTIPLE_TRUSTEE, "MultipleTrusteeOperation wrong\n");
+    ok(trustee.TrusteeForm == TRUSTEE_IS_OBJECTS_AND_SID, "TrusteeForm wrong\n");
+    ok(trustee.TrusteeType == TRUSTEE_IS_UNKNOWN, "TrusteeType wrong\n");
+    ok(trustee.ptstrName == (LPSTR)&oas, "ptstrName wrong\n");
+    ok(oas.ObjectsPresent == (ACE_OBJECT_TYPE_PRESENT | ACE_INHERITED_OBJECT_TYPE_PRESENT), "ObjectsPresent wrong\n");
+    ok(!memcmp(&oas.ObjectTypeGuid, &ObjectType, sizeof(GUID)), "ObjectTypeGuid wrong\n");
+    ok(!memcmp(&oas.InheritedObjectTypeGuid, &InheritedObjectType, sizeof(GUID)), "InheritedObjectTypeGuid wrong\n");
+    ok(oas.pSid == psid, "pSid wrong\n");
+
+    /* test GetTrusteeNameA */
+    ok(pGetTrusteeNameA(&trustee) == (LPSTR)&oas, "GetTrusteeName returned wrong value\n");
+
+    /* test BuildTrusteeWithObjectsAndSidA (test 2) */
+    memset( &trustee, 0xff, sizeof trustee );
+    memset( &oas, 0xff, sizeof(oas) );
+    pBuildTrusteeWithObjectsAndSidA(&trustee, &oas, NULL,
+                                    &InheritedObjectType, psid);
+
+    ok(trustee.pMultipleTrustee == NULL, "pMultipleTrustee wrong\n");
+    ok(trustee.MultipleTrusteeOperation == NO_MULTIPLE_TRUSTEE, "MultipleTrusteeOperation wrong\n");
+    ok(trustee.TrusteeForm == TRUSTEE_IS_OBJECTS_AND_SID, "TrusteeForm wrong\n");
+    ok(trustee.TrusteeType == TRUSTEE_IS_UNKNOWN, "TrusteeType wrong\n");
+    ok(trustee.ptstrName == (LPSTR)&oas, "ptstrName wrong\n");
+    ok(oas.ObjectsPresent == ACE_INHERITED_OBJECT_TYPE_PRESENT, "ObjectsPresent wrong\n");
+    ok(!memcmp(&oas.ObjectTypeGuid, &ZeroGuid, sizeof(GUID)), "ObjectTypeGuid wrong\n");
+    ok(!memcmp(&oas.InheritedObjectTypeGuid, &InheritedObjectType, sizeof(GUID)), "InheritedObjectTypeGuid wrong\n");
+    ok(oas.pSid == psid, "pSid wrong\n");
+
     FreeSid( psid );
 
     /* test BuildTrusteeWithNameA */
     memset( &trustee, 0xff, sizeof trustee );
-    pBuildTrusteeWithNameA( &trustee, str );
+    pBuildTrusteeWithNameA( &trustee, szTrusteeName );
 
     ok( trustee.pMultipleTrustee == NULL, "pMultipleTrustee wrong\n");
-    ok( trustee.MultipleTrusteeOperation == NO_MULTIPLE_TRUSTEE,
+    ok( trustee.MultipleTrusteeOperation == NO_MULTIPLE_TRUSTEE, 
         "MultipleTrusteeOperation wrong\n");
     ok( trustee.TrusteeForm == TRUSTEE_IS_NAME, "TrusteeForm wrong\n");
     ok( trustee.TrusteeType == TRUSTEE_IS_UNKNOWN, "TrusteeType wrong\n");
-    ok( trustee.ptstrName == str, "ptstrName wrong\n" );
-}
+    ok( trustee.ptstrName == szTrusteeName, "ptstrName wrong\n" );
+
+    /* test BuildTrusteeWithObjectsAndNameA (test 1) */
+    memset( &trustee, 0xff, sizeof trustee );
+    memset( &oan, 0xff, sizeof(oan) );
+    pBuildTrusteeWithObjectsAndNameA(&trustee, &oan, SE_KERNEL_OBJECT, szObjectTypeName,
+                                     szInheritedObjectTypeName, szTrusteeName);
+
+    ok(trustee.pMultipleTrustee == NULL, "pMultipleTrustee wrong\n");
+    ok(trustee.MultipleTrusteeOperation == NO_MULTIPLE_TRUSTEE, "MultipleTrusteeOperation wrong\n");
+    ok(trustee.TrusteeForm == TRUSTEE_IS_OBJECTS_AND_NAME, "TrusteeForm wrong\n");
+    ok(trustee.TrusteeType == TRUSTEE_IS_UNKNOWN, "TrusteeType wrong\n");
+    ok(trustee.ptstrName == (LPTSTR)&oan, "ptstrName wrong\n");
+    ok(oan.ObjectsPresent == (ACE_OBJECT_TYPE_PRESENT | ACE_INHERITED_OBJECT_TYPE_PRESENT), "ObjectsPresent wrong\n");
+    ok(oan.ObjectType == SE_KERNEL_OBJECT, "ObjectType wrong\n");
+    ok(oan.InheritedObjectTypeName == szInheritedObjectTypeName, "InheritedObjectTypeName wrong\n");
+    ok(oan.ptstrName == szTrusteeName, "szTrusteeName wrong\n");
+
+    /* test GetTrusteeNameA */
+    ok(pGetTrusteeNameA(&trustee) == (LPSTR)&oan, "GetTrusteeName returned wrong value\n");
+
+    /* test BuildTrusteeWithObjectsAndNameA (test 2) */
+    memset( &trustee, 0xff, sizeof trustee );
+    memset( &oan, 0xff, sizeof(oan) );
+    pBuildTrusteeWithObjectsAndNameA(&trustee, &oan, SE_KERNEL_OBJECT, NULL,
+                                     szInheritedObjectTypeName, szTrusteeName);
+
+    ok(trustee.pMultipleTrustee == NULL, "pMultipleTrustee wrong\n");
+    ok(trustee.MultipleTrusteeOperation == NO_MULTIPLE_TRUSTEE, "MultipleTrusteeOperation wrong\n");
+    ok(trustee.TrusteeForm == TRUSTEE_IS_OBJECTS_AND_NAME, "TrusteeForm wrong\n");
+    ok(trustee.TrusteeType == TRUSTEE_IS_UNKNOWN, "TrusteeType wrong\n");
+    ok(trustee.ptstrName == (LPSTR)&oan, "ptstrName wrong\n");
+    ok(oan.ObjectsPresent == ACE_INHERITED_OBJECT_TYPE_PRESENT, "ObjectsPresent wrong\n");
+    ok(oan.ObjectType == SE_KERNEL_OBJECT, "ObjectType wrong\n");
+    ok(oan.InheritedObjectTypeName == szInheritedObjectTypeName, "InheritedObjectTypeName wrong\n");
+    ok(oan.ptstrName == szTrusteeName, "szTrusteeName wrong\n");
 
+    /* test BuildTrusteeWithObjectsAndNameA (test 3) */
+    memset( &trustee, 0xff, sizeof trustee );
+    memset( &oan, 0xff, sizeof(oan) );
+    pBuildTrusteeWithObjectsAndNameA(&trustee, &oan, SE_KERNEL_OBJECT, szObjectTypeName,
+                                     NULL, szTrusteeName);
+
+    ok(trustee.pMultipleTrustee == NULL, "pMultipleTrustee wrong\n");
+    ok(trustee.MultipleTrusteeOperation == NO_MULTIPLE_TRUSTEE, "MultipleTrusteeOperation wrong\n");
+    ok(trustee.TrusteeForm == TRUSTEE_IS_OBJECTS_AND_NAME, "TrusteeForm wrong\n");
+    ok(trustee.TrusteeType == TRUSTEE_IS_UNKNOWN, "TrusteeType wrong\n");
+    ok(trustee.ptstrName == (LPTSTR)&oan, "ptstrName wrong\n");
+    ok(oan.ObjectsPresent == ACE_OBJECT_TYPE_PRESENT, "ObjectsPresent wrong\n");
+    ok(oan.ObjectType == SE_KERNEL_OBJECT, "ObjectType wrong\n");
+    ok(oan.InheritedObjectTypeName == NULL, "InheritedObjectTypeName wrong\n");
+    ok(oan.ptstrName == szTrusteeName, "szTrusteeName wrong\n");
+}
 /* If the first isn't defined, assume none is */
 #ifndef SE_MIN_WELL_KNOWN_PRIVILEGE
 #define SE_MIN_WELL_KNOWN_PRIVILEGE       2L
@@ -239,23 +517,23 @@ static void test_allocateLuid(void)
         return;
 
     ok(ret,
-     "AllocateLocallyUniqueId failed: %ld\n", GetLastError());
+     "AllocateLocallyUniqueId failed: %d\n", GetLastError());
     ret = pAllocateLocallyUniqueId(&luid2);
     ok( ret,
-     "AllocateLocallyUniqueId failed: %ld\n", GetLastError());
+     "AllocateLocallyUniqueId failed: %d\n", GetLastError());
     ok(luid1.LowPart > SE_MAX_WELL_KNOWN_PRIVILEGE || luid1.HighPart != 0,
      "AllocateLocallyUniqueId returned a well-known LUID\n");
     ok(luid1.LowPart != luid2.LowPart || luid1.HighPart != luid2.HighPart,
      "AllocateLocallyUniqueId returned non-unique LUIDs\n");
     ret = pAllocateLocallyUniqueId(NULL);
     ok( !ret && GetLastError() == ERROR_NOACCESS,
-     "AllocateLocallyUniqueId(NULL) didn't return ERROR_NOACCESS: %ld\n",
+     "AllocateLocallyUniqueId(NULL) didn't return ERROR_NOACCESS: %d\n",
      GetLastError());
 }
 
 static void test_lookupPrivilegeName(void)
 {
-    BOOL (WINAPI *pLookupPrivilegeNameA)(LPSTR, PLUID, LPSTR, LPDWORD);
+    BOOL (WINAPI *pLookupPrivilegeNameA)(LPCSTR, PLUID, LPSTR, LPDWORD);
     char buf[MAX_PATH]; /* arbitrary, seems long enough */
     DWORD cchName = sizeof(buf);
     LUID luid = { 0, 0 };
@@ -275,18 +553,18 @@ static void test_lookupPrivilegeName(void)
     luid.LowPart = SE_CREATE_TOKEN_PRIVILEGE;
     ret = pLookupPrivilegeNameA(NULL, &luid, NULL, &cchName);
     ok( !ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
-     "LookupPrivilegeNameA didn't fail with ERROR_INSUFFICIENT_BUFFER: %ld\n",
+     "LookupPrivilegeNameA didn't fail with ERROR_INSUFFICIENT_BUFFER: %d\n",
      GetLastError());
     ok(cchName == strlen("SeCreateTokenPrivilege") + 1,
      "LookupPrivilegeNameA returned an incorrect required length for\n"
-     "SeCreateTokenPrivilege (got %ld, expected %d)\n", cchName,
-     strlen("SeCreateTokenPrivilege") + 1);
+     "SeCreateTokenPrivilege (got %d, expected %d)\n", cchName,
+     lstrlenA("SeCreateTokenPrivilege") + 1);
     /* check a known value and its returned length on success */
     cchName = sizeof(buf);
     ok(pLookupPrivilegeNameA(NULL, &luid, buf, &cchName) &&
      cchName == strlen("SeCreateTokenPrivilege"),
      "LookupPrivilegeNameA returned an incorrect output length for\n"
-     "SeCreateTokenPrivilege (got %ld, expected %d)\n", cchName,
+     "SeCreateTokenPrivilege (got %d, expected %d)\n", cchName,
      (int)strlen("SeCreateTokenPrivilege"));
     /* check known values */
     for (i = SE_MIN_WELL_KNOWN_PRIVILEGE; i < SE_MAX_WELL_KNOWN_PRIVILEGE; i++)
@@ -295,21 +573,21 @@ static void test_lookupPrivilegeName(void)
         cchName = sizeof(buf);
         ret = pLookupPrivilegeNameA(NULL, &luid, buf, &cchName);
         ok( ret || GetLastError() == ERROR_NO_SUCH_PRIVILEGE,
-         "LookupPrivilegeNameA(0.%ld) failed: %ld\n", i, GetLastError());
+         "LookupPrivilegeNameA(0.%d) failed: %d\n", i, GetLastError());
     }
     /* check a bogus LUID */
     luid.LowPart = 0xdeadbeef;
     cchName = sizeof(buf);
     ret = pLookupPrivilegeNameA(NULL, &luid, buf, &cchName);
     ok( !ret && GetLastError() == ERROR_NO_SUCH_PRIVILEGE,
-     "LookupPrivilegeNameA didn't fail with ERROR_NO_SUCH_PRIVILEGE: %ld\n",
+     "LookupPrivilegeNameA didn't fail with ERROR_NO_SUCH_PRIVILEGE: %d\n",
      GetLastError());
     /* check on a bogus system */
     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: %ld\n",
+     "LookupPrivilegeNameA didn't fail with RPC_S_SERVER_UNAVAILABLE: %d\n",
      GetLastError());
 }
 
@@ -367,22 +645,22 @@ 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: %ld\n",
+     "LookupPrivilegeValueA didn't fail with RPC_S_SERVER_UNAVAILABLE: %d\n",
      GetLastError());
     /* check a NULL string */
     ret = pLookupPrivilegeValueA(NULL, 0, &luid);
     ok( !ret && GetLastError() == ERROR_NO_SUCH_PRIVILEGE,
-     "LookupPrivilegeValueA didn't fail with ERROR_NO_SUCH_PRIVILEGE: %ld\n",
+     "LookupPrivilegeValueA didn't fail with ERROR_NO_SUCH_PRIVILEGE: %d\n",
      GetLastError());
     /* check a bogus privilege name */
     ret = pLookupPrivilegeValueA(NULL, "SeBogusPrivilege", &luid);
     ok( !ret && GetLastError() == ERROR_NO_SUCH_PRIVILEGE,
-     "LookupPrivilegeValueA didn't fail with ERROR_NO_SUCH_PRIVILEGE: %ld\n",
+     "LookupPrivilegeValueA didn't fail with ERROR_NO_SUCH_PRIVILEGE: %d\n",
      GetLastError());
     /* check case insensitive */
     ret = pLookupPrivilegeValueA(NULL, "sEcREATEtOKENpRIVILEGE", &luid);
     ok( ret,
-     "LookupPrivilegeValueA(NULL, sEcREATEtOKENpRIVILEGE, &luid) failed: %ld\n",
+     "LookupPrivilegeValueA(NULL, sEcREATEtOKENpRIVILEGE, &luid) failed: %d\n",
      GetLastError());
     for (i = 0; i < sizeof(privs) / sizeof(privs[0]); i++)
     {
@@ -426,21 +704,1810 @@ static void test_FileSecurity(void)
     strcpy(directory, "\\Should not exist");
 
     SetLastError(NO_ERROR);
-    result = GetFileSecurityA( directory,OWNER_SECURITY_INFORMATION,
-                              (PSECURITY_DESCRIPTOR)buffer,0x40,&outSize);
-    ok(!result, "GetFileSecurityA should fail for not existing directories/files\n");
+    result = pGetFileSecurityA( directory,OWNER_SECURITY_INFORMATION,buffer,0x40,&outSize);
+    ok(!result, "GetFileSecurityA should fail for not existing directories/files\n"); 
     ok( (GetLastError() == ERROR_FILE_NOT_FOUND ) ||
-        (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) ,
+        (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) , 
         "last error ERROR_FILE_NOT_FOUND / ERROR_CALL_NOT_IMPLEMENTED (98) "
-        "expected, got %ld\n", GetLastError());
+        "expected, got %d\n", GetLastError());
+}
+
+static void test_AccessCheck(void)
+{
+    PSID EveryoneSid = NULL, AdminSid = NULL, UsersSid = NULL;
+    PACL Acl = NULL;
+    SECURITY_DESCRIPTOR *SecurityDescriptor = NULL;
+    SID_IDENTIFIER_AUTHORITY SIDAuthWorld = { SECURITY_WORLD_SID_AUTHORITY };
+    SID_IDENTIFIER_AUTHORITY SIDAuthNT = { SECURITY_NT_AUTHORITY };
+    GENERIC_MAPPING Mapping = { KEY_READ, KEY_WRITE, KEY_EXECUTE, KEY_ALL_ACCESS };
+    ACCESS_MASK Access;
+    BOOL AccessStatus;
+    HANDLE Token;
+    HANDLE ProcessToken;
+    BOOL ret;
+    DWORD PrivSetLen;
+    PRIVILEGE_SET *PrivSet;
+    BOOL res;
+    HMODULE NtDllModule;
+    BOOLEAN Enabled;
+    DWORD err;
+
+    NtDllModule = GetModuleHandle("ntdll.dll");
+    if (!NtDllModule)
+    {
+        skip("not running on NT, skipping test\n");
+        return;
+    }
+    pRtlAdjustPrivilege = (fnRtlAdjustPrivilege)
+                          GetProcAddress(NtDllModule, "RtlAdjustPrivilege");
+    if (!pRtlAdjustPrivilege)
+    {
+        skip("missing RtlAdjustPrivilege, skipping test\n");
+        return;
+    }
+
+    Acl = HeapAlloc(GetProcessHeap(), 0, 256);
+    res = InitializeAcl(Acl, 256, ACL_REVISION);
+    if(!res && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
+    {
+        skip("ACLs not implemented - skipping tests\n");
+        HeapFree(GetProcessHeap(), 0, Acl);
+        return;
+    }
+    ok(res, "InitializeAcl failed with error %d\n", GetLastError());
+
+    res = AllocateAndInitializeSid( &SIDAuthWorld, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &EveryoneSid);
+    ok(res, "AllocateAndInitializeSid failed with error %d\n", GetLastError());
+
+    res = AllocateAndInitializeSid( &SIDAuthNT, 2, SECURITY_BUILTIN_DOMAIN_RID,
+        DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &AdminSid);
+    ok(res, "AllocateAndInitializeSid failed with error %d\n", GetLastError());
+
+    res = AllocateAndInitializeSid( &SIDAuthNT, 2, SECURITY_BUILTIN_DOMAIN_RID,
+        DOMAIN_ALIAS_RID_USERS, 0, 0, 0, 0, 0, 0, &UsersSid);
+    ok(res, "AllocateAndInitializeSid failed with error %d\n", GetLastError());
+
+    SecurityDescriptor = HeapAlloc(GetProcessHeap(), 0, SECURITY_DESCRIPTOR_MIN_LENGTH);
+
+    res = InitializeSecurityDescriptor(SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
+    ok(res, "InitializeSecurityDescriptor failed with error %d\n", GetLastError());
+
+    res = SetSecurityDescriptorDacl(SecurityDescriptor, TRUE, Acl, FALSE);
+    ok(res, "SetSecurityDescriptorDacl failed with error %d\n", GetLastError());
+
+    PrivSetLen = FIELD_OFFSET(PRIVILEGE_SET, Privilege[16]);
+    PrivSet = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, PrivSetLen);
+    PrivSet->PrivilegeCount = 16;
+
+    res = OpenProcessToken(GetCurrentProcess(), TOKEN_DUPLICATE|TOKEN_QUERY, &ProcessToken);
+    ok(res, "OpenProcessToken failed with error %d\n", GetLastError());
+
+    pRtlAdjustPrivilege(SE_SECURITY_PRIVILEGE, FALSE, TRUE, &Enabled);
+
+    res = DuplicateToken(ProcessToken, SecurityImpersonation, &Token);
+    ok(res, "DuplicateToken failed with error %d\n", GetLastError());
+
+    /* SD without owner/group */
+    SetLastError(0xdeadbeef);
+    Access = AccessStatus = 0xdeadbeef;
+    ret = AccessCheck(SecurityDescriptor, Token, KEY_QUERY_VALUE, &Mapping,
+                      PrivSet, &PrivSetLen, &Access, &AccessStatus);
+    err = GetLastError();
+    ok(!ret && err == ERROR_INVALID_SECURITY_DESCR, "AccessCheck should have "
+       "failed with ERROR_INVALID_SECURITY_DESCR, instead of %d\n", err);
+    ok(Access == 0xdeadbeef && AccessStatus == 0xdeadbeef,
+       "Access and/or AccessStatus were changed!\n");
+
+    /* Set owner and group */
+    res = SetSecurityDescriptorOwner(SecurityDescriptor, AdminSid, FALSE);
+    ok(res, "SetSecurityDescriptorOwner failed with error %d\n", GetLastError());
+    res = SetSecurityDescriptorGroup(SecurityDescriptor, UsersSid, TRUE);
+    ok(res, "SetSecurityDescriptorGroup failed with error %d\n", GetLastError());
+
+    /* Generic access mask */
+    SetLastError(0xdeadbeef);
+    ret = AccessCheck(SecurityDescriptor, Token, GENERIC_READ, &Mapping,
+                      PrivSet, &PrivSetLen, &Access, &AccessStatus);
+    err = GetLastError();
+    ok(!ret && err == ERROR_GENERIC_NOT_MAPPED, "AccessCheck should have failed "
+       "with ERROR_GENERIC_NOT_MAPPED, instead of %d\n", err);
+    ok(Access == 0xdeadbeef && AccessStatus == 0xdeadbeef,
+       "Access and/or AccessStatus were changed!\n");
+
+    /* sd with no dacl present */
+    ret = SetSecurityDescriptorDacl(SecurityDescriptor, FALSE, NULL, FALSE);
+    ok(ret, "SetSecurityDescriptorDacl failed with error %d\n", GetLastError());
+    ret = AccessCheck(SecurityDescriptor, Token, KEY_READ, &Mapping,
+                      PrivSet, &PrivSetLen, &Access, &AccessStatus);
+    ok(ret, "AccessCheck failed with error %d\n", GetLastError());
+    ok(AccessStatus && (Access == KEY_READ),
+        "AccessCheck failed to grant access with error %d\n",
+        GetLastError());
+
+    /* sd with NULL dacl */
+    ret = SetSecurityDescriptorDacl(SecurityDescriptor, TRUE, NULL, FALSE);
+    ok(ret, "SetSecurityDescriptorDacl failed with error %d\n", GetLastError());
+    ret = AccessCheck(SecurityDescriptor, Token, KEY_READ, &Mapping,
+                      PrivSet, &PrivSetLen, &Access, &AccessStatus);
+    ok(ret, "AccessCheck failed with error %d\n", GetLastError());
+    ok(AccessStatus && (Access == KEY_READ),
+        "AccessCheck failed to grant access with error %d\n",
+        GetLastError());
+
+    /* sd with blank dacl */
+    ret = SetSecurityDescriptorDacl(SecurityDescriptor, TRUE, Acl, FALSE);
+    ok(ret, "SetSecurityDescriptorDacl failed with error %d\n", GetLastError());
+    ret = AccessCheck(SecurityDescriptor, Token, KEY_READ, &Mapping,
+                      PrivSet, &PrivSetLen, &Access, &AccessStatus);
+    ok(ret, "AccessCheck failed with error %d\n", GetLastError());
+    err = GetLastError();
+    ok(!AccessStatus && err == ERROR_ACCESS_DENIED, "AccessCheck should have failed "
+       "with ERROR_ACCESS_DENIED, instead of %d\n", err);
+    ok(!Access, "Should have failed to grant any access, got 0x%08x\n", Access);
+
+    res = AddAccessAllowedAce(Acl, ACL_REVISION, KEY_READ, EveryoneSid);
+    ok(res, "AddAccessAllowedAce failed with error %d\n", GetLastError());
+
+    res = AddAccessDeniedAce(Acl, ACL_REVISION, KEY_SET_VALUE, AdminSid);
+    ok(res, "AddAccessDeniedAce failed with error %d\n", GetLastError());
+
+    /* sd with dacl */
+    ret = AccessCheck(SecurityDescriptor, Token, KEY_READ, &Mapping,
+                      PrivSet, &PrivSetLen, &Access, &AccessStatus);
+    ok(ret, "AccessCheck failed with error %d\n", GetLastError());
+    ok(AccessStatus && (Access == KEY_READ),
+        "AccessCheck failed to grant access with error %d\n",
+        GetLastError());
+
+    ret = AccessCheck(SecurityDescriptor, Token, MAXIMUM_ALLOWED, &Mapping,
+                      PrivSet, &PrivSetLen, &Access, &AccessStatus);
+    ok(ret, "AccessCheck failed with error %d\n", GetLastError());
+    ok(AccessStatus,
+        "AccessCheck failed to grant any access with error %d\n",
+        GetLastError());
+    trace("AccessCheck with MAXIMUM_ALLOWED got Access 0x%08x\n", Access);
+
+    /* Access denied by SD */
+    SetLastError(0xdeadbeef);
+    ret = AccessCheck(SecurityDescriptor, Token, KEY_WRITE, &Mapping,
+                      PrivSet, &PrivSetLen, &Access, &AccessStatus);
+    ok(ret, "AccessCheck failed with error %d\n", GetLastError());
+    err = GetLastError();
+    ok(!AccessStatus && err == ERROR_ACCESS_DENIED, "AccessCheck should have failed "
+       "with ERROR_ACCESS_DENIED, instead of %d\n", err);
+    ok(!Access, "Should have failed to grant any access, got 0x%08x\n", Access);
+
+    SetLastError(0);
+    PrivSet->PrivilegeCount = 16;
+    ret = AccessCheck(SecurityDescriptor, Token, ACCESS_SYSTEM_SECURITY, &Mapping,
+                      PrivSet, &PrivSetLen, &Access, &AccessStatus);
+    ok(ret && !AccessStatus && GetLastError() == ERROR_PRIVILEGE_NOT_HELD,
+        "AccessCheck should have failed with ERROR_PRIVILEGE_NOT_HELD, instead of %d\n",
+        GetLastError());
+
+    ret = ImpersonateLoggedOnUser(Token);
+    ok(ret, "ImpersonateLoggedOnUser failed with error %d\n", GetLastError());
+    ret = pRtlAdjustPrivilege(SE_SECURITY_PRIVILEGE, TRUE, TRUE, &Enabled);
+    if (!ret)
+    {
+        SetLastError(0);
+        PrivSet->PrivilegeCount = 16;
+        ret = AccessCheck(SecurityDescriptor, Token, ACCESS_SYSTEM_SECURITY, &Mapping,
+                          PrivSet, &PrivSetLen, &Access, &AccessStatus);
+        ok(ret && AccessStatus && GetLastError() == 0,
+            "AccessCheck should have succeeded, error %d\n",
+            GetLastError());
+        ok(Access == ACCESS_SYSTEM_SECURITY,
+            "Access should be equal to ACCESS_SYSTEM_SECURITY instead of 0x%08x\n",
+            Access);
+    }
+    else
+        trace("Couldn't get SE_SECURITY_PRIVILEGE (0x%08x), skipping ACCESS_SYSTEM_SECURITY test\n",
+            ret);
+    ret = RevertToSelf();
+    ok(ret, "RevertToSelf failed with error %d\n", GetLastError());
+
+    /* test INHERIT_ONLY_ACE */
+    ret = InitializeAcl(Acl, 256, ACL_REVISION);
+    ok(ret, "InitializeAcl failed with error %d\n", GetLastError());
+
+    /* NT doesn't have AddAccessAllowedAceEx. Skipping this call/test doesn't influence
+     * the next ones.
+     */
+    if (pAddAccessAllowedAceEx)
+    {
+        ret = pAddAccessAllowedAceEx(Acl, ACL_REVISION, INHERIT_ONLY_ACE, KEY_READ, EveryoneSid);
+        ok(ret, "AddAccessAllowedAceEx failed with error %d\n", GetLastError());
+    }
+    else
+        skip("AddAccessAllowedAceEx is not available\n");
+
+    ret = AccessCheck(SecurityDescriptor, Token, KEY_READ, &Mapping,
+                      PrivSet, &PrivSetLen, &Access, &AccessStatus);
+    ok(ret, "AccessCheck failed with error %d\n", GetLastError());
+    err = GetLastError();
+    ok(!AccessStatus && err == ERROR_ACCESS_DENIED, "AccessCheck should have failed "
+       "with ERROR_ACCESS_DENIED, instead of %d\n", err);
+    ok(!Access, "Should have failed to grant any access, got 0x%08x\n", Access);
+
+    CloseHandle(Token);
+
+    res = DuplicateToken(ProcessToken, SecurityAnonymous, &Token);
+    ok(res, "DuplicateToken failed with error %d\n", GetLastError());
+
+    SetLastError(0xdeadbeef);
+    ret = AccessCheck(SecurityDescriptor, Token, MAXIMUM_ALLOWED, &Mapping,
+                      PrivSet, &PrivSetLen, &Access, &AccessStatus);
+    err = GetLastError();
+    ok(!ret && err == ERROR_BAD_IMPERSONATION_LEVEL, "AccessCheck should have failed "
+       "with ERROR_BAD_IMPERSONATION_LEVEL, instead of %d\n", err);
+
+    CloseHandle(Token);
+
+    SetLastError(0xdeadbeef);
+    ret = AccessCheck(SecurityDescriptor, ProcessToken, KEY_READ, &Mapping,
+                      PrivSet, &PrivSetLen, &Access, &AccessStatus);
+    err = GetLastError();
+    ok(!ret && err == ERROR_NO_IMPERSONATION_TOKEN, "AccessCheck should have failed "
+       "with ERROR_NO_IMPERSONATION_TOKEN, instead of %d\n", err);
+
+    CloseHandle(ProcessToken);
+
+    if (EveryoneSid)
+        FreeSid(EveryoneSid);
+    if (AdminSid)
+        FreeSid(AdminSid);
+    if (UsersSid)
+        FreeSid(UsersSid);
+    HeapFree(GetProcessHeap(), 0, Acl);
+    HeapFree(GetProcessHeap(), 0, SecurityDescriptor);
+    HeapFree(GetProcessHeap(), 0, PrivSet);
+}
+
+/* test GetTokenInformation for the various attributes */
+static void test_token_attr(void)
+{
+    HANDLE Token, ImpersonationToken;
+    DWORD Size;
+    TOKEN_PRIVILEGES *Privileges;
+    TOKEN_GROUPS *Groups;
+    TOKEN_USER *User;
+    BOOL ret;
+    DWORD i, GLE;
+    LPSTR SidString;
+    SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
+
+    /* cygwin-like use case */
+    SetLastError(0xdeadbeef);
+    ret = OpenProcessToken(GetCurrentProcess(), MAXIMUM_ALLOWED, &Token);
+    if(!ret && (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED))
+    {
+        skip("OpenProcessToken is not implemented\n");
+        return;
+    }
+    ok(ret, "OpenProcessToken failed with error %d\n", GetLastError());
+    if (ret)
+    {
+        BYTE buf[1024];
+        Size = sizeof(buf);
+        ret = GetTokenInformation(Token, TokenUser,(void*)buf, Size, &Size);
+        ok(ret, "GetTokenInformation failed with error %d\n", GetLastError());
+        Size = sizeof(ImpersonationLevel);
+        ret = GetTokenInformation(Token, TokenImpersonationLevel, &ImpersonationLevel, Size, &Size);
+        GLE = GetLastError();
+        ok(!ret && (GLE == ERROR_INVALID_PARAMETER), "GetTokenInformation(TokenImpersonationLevel) on primary token should have failed with ERROR_INVALID_PARAMETER instead of %d\n", GLE);
+        CloseHandle(Token);
+    }
+
+    if(!pConvertSidToStringSidA)
+    {
+        skip("ConvertSidToStringSidA is not available\n");
+        return;
+    }
+
+    SetLastError(0xdeadbeef);
+    ret = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY|TOKEN_DUPLICATE, &Token);
+    ok(ret, "OpenProcessToken failed with error %d\n", GetLastError());
+
+    /* groups */
+    ret = GetTokenInformation(Token, TokenGroups, NULL, 0, &Size);
+    Groups = HeapAlloc(GetProcessHeap(), 0, Size);
+    ret = GetTokenInformation(Token, TokenGroups, Groups, Size, &Size);
+    ok(ret, "GetTokenInformation(TokenGroups) failed with error %d\n", GetLastError());
+    trace("TokenGroups:\n");
+    for (i = 0; i < Groups->GroupCount; i++)
+    {
+        DWORD NameLength = 255;
+        TCHAR Name[255];
+        DWORD DomainLength = 255;
+        TCHAR Domain[255];
+        SID_NAME_USE SidNameUse;
+        pConvertSidToStringSidA(Groups->Groups[i].Sid, &SidString);
+        Name[0] = '\0';
+        Domain[0] = '\0';
+        ret = LookupAccountSid(NULL, Groups->Groups[i].Sid, Name, &NameLength, Domain, &DomainLength, &SidNameUse);
+        if (ret)
+            trace("\t%s, %s\\%s use: %d attr: 0x%08x\n", SidString, Domain, Name, SidNameUse, Groups->Groups[i].Attributes);
+        else
+            trace("\t%s, attr: 0x%08x LookupAccountSid failed with error %d\n", SidString, Groups->Groups[i].Attributes, GetLastError());
+        LocalFree(SidString);
+    }
+    HeapFree(GetProcessHeap(), 0, Groups);
+
+    /* user */
+    ret = GetTokenInformation(Token, TokenUser, NULL, 0, &Size);
+    ok(!ret && (GetLastError() == ERROR_INSUFFICIENT_BUFFER),
+        "GetTokenInformation(TokenUser) failed with error %d\n", GetLastError());
+    User = HeapAlloc(GetProcessHeap(), 0, Size);
+    ret = GetTokenInformation(Token, TokenUser, User, Size, &Size);
+    ok(ret,
+        "GetTokenInformation(TokenUser) failed with error %d\n", GetLastError());
+
+    pConvertSidToStringSidA(User->User.Sid, &SidString);
+    trace("TokenUser: %s attr: 0x%08x\n", SidString, User->User.Attributes);
+    LocalFree(SidString);
+    HeapFree(GetProcessHeap(), 0, User);
+
+    /* privileges */
+    ret = GetTokenInformation(Token, TokenPrivileges, NULL, 0, &Size);
+    ok(!ret && (GetLastError() == ERROR_INSUFFICIENT_BUFFER),
+        "GetTokenInformation(TokenPrivileges) failed with error %d\n", GetLastError());
+    Privileges = HeapAlloc(GetProcessHeap(), 0, Size);
+    ret = GetTokenInformation(Token, TokenPrivileges, Privileges, Size, &Size);
+    ok(ret,
+        "GetTokenInformation(TokenPrivileges) failed with error %d\n", GetLastError());
+    trace("TokenPrivileges:\n");
+    for (i = 0; i < Privileges->PrivilegeCount; i++)
+    {
+        TCHAR Name[256];
+        DWORD NameLen = sizeof(Name)/sizeof(Name[0]);
+        LookupPrivilegeName(NULL, &Privileges->Privileges[i].Luid, Name, &NameLen);
+        trace("\t%s, 0x%x\n", Name, Privileges->Privileges[i].Attributes);
+    }
+    HeapFree(GetProcessHeap(), 0, Privileges);
+
+    ret = DuplicateToken(Token, SecurityAnonymous, &ImpersonationToken);
+    ok(ret, "DuplicateToken failed with error %d\n", GetLastError());
+
+    Size = sizeof(ImpersonationLevel);
+    ret = GetTokenInformation(ImpersonationToken, TokenImpersonationLevel, &ImpersonationLevel, Size, &Size);
+    ok(ret, "GetTokenInformation(TokenImpersonationLevel) failed with error %d\n", GetLastError());
+    ok(ImpersonationLevel == SecurityAnonymous, "ImpersonationLevel should have been SecurityAnonymous instead of %d\n", ImpersonationLevel);
+
+    CloseHandle(ImpersonationToken);
+    CloseHandle(Token);
+}
+
+typedef union _MAX_SID
+{
+    SID sid;
+    char max[SECURITY_MAX_SID_SIZE];
+} MAX_SID;
+
+static void test_sid_str(PSID * sid)
+{
+    char *str_sid;
+    BOOL ret = pConvertSidToStringSidA(sid, &str_sid);
+    ok(ret, "ConvertSidToStringSidA() failed: %d\n", GetLastError());
+    if (ret)
+    {
+        char account[MAX_PATH], domain[MAX_PATH];
+        SID_NAME_USE use;
+        DWORD acc_size = MAX_PATH;
+        DWORD dom_size = MAX_PATH;
+        ret = LookupAccountSid(NULL, sid, account, &acc_size, domain, &dom_size, &use);
+        ok(ret || (!ret && (GetLastError() == ERROR_NONE_MAPPED)),
+           "LookupAccountSid(%s) failed: %d\n", str_sid, GetLastError());
+        if (ret)
+            trace(" %s %s\\%s %d\n", str_sid, domain, account, use);
+        else if (GetLastError() == ERROR_NONE_MAPPED)
+            trace(" %s couldn't be mapped\n", str_sid);
+        LocalFree(str_sid);
+    }
+}
+
+struct well_known_sid_value
+{
+    BOOL without_domain;
+    const char *sid_string;
+} well_known_sid_values[] = {
+/*  0 */ {TRUE, "S-1-0-0"},  {TRUE, "S-1-1-0"},  {TRUE, "S-1-2-0"},  {TRUE, "S-1-3-0"},
+/*  4 */ {TRUE, "S-1-3-1"},  {TRUE, "S-1-3-2"},  {TRUE, "S-1-3-3"},  {TRUE, "S-1-5"},
+/*  8 */ {FALSE, "S-1-5-1"}, {TRUE, "S-1-5-2"},  {TRUE, "S-1-5-3"},  {TRUE, "S-1-5-4"},
+/* 12 */ {TRUE, "S-1-5-6"},  {TRUE, "S-1-5-7"},  {TRUE, "S-1-5-8"},  {TRUE, "S-1-5-9"},
+/* 16 */ {TRUE, "S-1-5-10"}, {TRUE, "S-1-5-11"}, {TRUE, "S-1-5-12"}, {TRUE, "S-1-5-13"},
+/* 20 */ {TRUE, "S-1-5-14"}, {FALSE, NULL},      {TRUE, "S-1-5-18"}, {TRUE, "S-1-5-19"},
+/* 24 */ {TRUE, "S-1-5-20"}, {TRUE, "S-1-5-32"},
+/* 26 */ {FALSE, "S-1-5-32-544"}, {TRUE, "S-1-5-32-545"}, {TRUE, "S-1-5-32-546"},
+/* 29 */ {TRUE, "S-1-5-32-547"},  {TRUE, "S-1-5-32-548"}, {TRUE, "S-1-5-32-549"},
+/* 32 */ {TRUE, "S-1-5-32-550"},  {TRUE, "S-1-5-32-551"}, {TRUE, "S-1-5-32-552"},
+/* 35 */ {TRUE, "S-1-5-32-554"},  {TRUE, "S-1-5-32-555"}, {TRUE, "S-1-5-32-556"},
+/* 38 */ {FALSE, "S-1-5-21-12-23-34-45-56-500"}, {FALSE, "S-1-5-21-12-23-34-45-56-501"},
+/* 40 */ {FALSE, "S-1-5-21-12-23-34-45-56-502"}, {FALSE, "S-1-5-21-12-23-34-45-56-512"},
+/* 42 */ {FALSE, "S-1-5-21-12-23-34-45-56-513"}, {FALSE, "S-1-5-21-12-23-34-45-56-514"},
+/* 44 */ {FALSE, "S-1-5-21-12-23-34-45-56-515"}, {FALSE, "S-1-5-21-12-23-34-45-56-516"},
+/* 46 */ {FALSE, "S-1-5-21-12-23-34-45-56-517"}, {FALSE, "S-1-5-21-12-23-34-45-56-518"},
+/* 48 */ {FALSE, "S-1-5-21-12-23-34-45-56-519"}, {FALSE, "S-1-5-21-12-23-34-45-56-520"},
+/* 50 */ {FALSE, "S-1-5-21-12-23-34-45-56-553"},
+/* Added in Windows Server 2003 */
+/* 51 */ {TRUE, "S-1-5-64-10"},   {TRUE, "S-1-5-64-21"},   {TRUE, "S-1-5-64-14"},
+/* 54 */ {TRUE, "S-1-5-15"},      {TRUE, "S-1-5-1000"},    {FALSE, "S-1-5-32-557"},
+/* 57 */ {TRUE, "S-1-5-32-558"},  {TRUE, "S-1-5-32-559"},  {TRUE, "S-1-5-32-560"},
+/* 60 */ {TRUE, "S-1-5-32-561"}, {TRUE, "S-1-5-32-562"},
+/* Added in Windows Vista: */
+/* 62 */ {TRUE, "S-1-5-32-568"},
+/* 63 */ {TRUE, "S-1-5-17"},      {FALSE, "S-1-5-32-569"}, {TRUE, "S-1-16-0"},
+/* 66 */ {TRUE, "S-1-16-4096"},   {TRUE, "S-1-16-8192"},   {TRUE, "S-1-16-12288"},
+/* 69 */ {TRUE, "S-1-16-16384"},  {TRUE, "S-1-5-33"},      {TRUE, "S-1-3-4"},
+/* 72 */ {FALSE, "S-1-5-21-12-23-34-45-56-571"},  {FALSE, "S-1-5-21-12-23-34-45-56-572"},
+/* 74 */ {TRUE, "S-1-5-22"}, {FALSE, "S-1-5-21-12-23-34-45-56-521"}, {TRUE, "S-1-5-32-573"}
+};
+
+static void test_CreateWellKnownSid()
+{
+    SID_IDENTIFIER_AUTHORITY ident = { SECURITY_NT_AUTHORITY };
+    PSID domainsid;
+    int i;
+
+    if (!pCreateWellKnownSid)
+    {
+        skip("CreateWellKnownSid not available\n");
+        return;
+    }
+
+    /* a domain sid usually have three subauthorities but we test that CreateWellKnownSid doesn't check it */
+    AllocateAndInitializeSid(&ident, 6, SECURITY_NT_NON_UNIQUE, 12, 23, 34, 45, 56, 0, 0, &domainsid);
+
+    for (i = 0; i < sizeof(well_known_sid_values)/sizeof(well_known_sid_values[0]); i++)
+    {
+        struct well_known_sid_value *value = &well_known_sid_values[i];
+        char sid_buffer[SECURITY_MAX_SID_SIZE];
+        LPSTR str;
+        DWORD cb;
+
+        if (value->sid_string == NULL)
+            continue;
+
+        if (i > WinAccountRasAndIasServersSid)
+        {
+            /* These SIDs aren't implemented by all Windows versions - detect it and break the loop */
+            cb = sizeof(sid_buffer);
+            if (!pCreateWellKnownSid(i, domainsid, sid_buffer, &cb))
+            {
+                skip("Well known SIDs starting from %d are not implemented\n", i);
+                break;
+            }
+        }
+
+        cb = sizeof(sid_buffer);
+        ok(pCreateWellKnownSid(i, value->without_domain ? NULL : domainsid, sid_buffer, &cb), "Couldn't create well known sid %d\n", i);
+        expect_eq(GetSidLengthRequired(*GetSidSubAuthorityCount(sid_buffer)), cb, DWORD, "%d");
+        ok(IsValidSid(sid_buffer), "The sid is not valid\n");
+        ok(pConvertSidToStringSidA(sid_buffer, &str), "Couldn't convert SID to string\n");
+        ok(strcmp(str, value->sid_string) == 0, "SID mismatch - expected %s, got %s\n",
+            value->sid_string, str);
+        LocalFree(str);
+
+        if (value->without_domain)
+        {
+            char buf2[SECURITY_MAX_SID_SIZE];
+            cb = sizeof(buf2);
+            ok(pCreateWellKnownSid(i, domainsid, buf2, &cb), "Couldn't create well known sid %d with optional domain\n", i);
+            expect_eq(GetSidLengthRequired(*GetSidSubAuthorityCount(sid_buffer)), cb, DWORD, "%d");
+            ok(memcmp(buf2, sid_buffer, cb) == 0, "SID create with domain is different than without (%d)\n", i);
+        }
+    }
+}
+
+static void test_LookupAccountSid(void)
+{
+    SID_IDENTIFIER_AUTHORITY SIDAuthNT = { SECURITY_NT_AUTHORITY };
+    CHAR accountA[MAX_PATH], domainA[MAX_PATH];
+    DWORD acc_sizeA, dom_sizeA;
+    DWORD real_acc_sizeA, real_dom_sizeA;
+    WCHAR accountW[MAX_PATH], domainW[MAX_PATH];
+    DWORD acc_sizeW, dom_sizeW;
+    DWORD real_acc_sizeW, real_dom_sizeW;
+    PSID pUsersSid = NULL;
+    SID_NAME_USE use;
+    BOOL ret;
+    DWORD size;
+    MAX_SID  max_sid;
+    CHAR *str_sidA;
+    int i;
+
+    /* native windows crashes if account size, domain size, or name use is NULL */
+
+    ret = AllocateAndInitializeSid(&SIDAuthNT, 2, SECURITY_BUILTIN_DOMAIN_RID,
+        DOMAIN_ALIAS_RID_USERS, 0, 0, 0, 0, 0, 0, &pUsersSid);
+    ok(ret || (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED),
+       "AllocateAndInitializeSid failed with error %d\n", GetLastError());
+
+    /* not running on NT so give up */
+    if (!ret && (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED))
+        return;
+
+    real_acc_sizeA = MAX_PATH;
+    real_dom_sizeA = MAX_PATH;
+    ret = LookupAccountSidA(NULL, pUsersSid, accountA, &real_acc_sizeA, domainA, &real_dom_sizeA, &use);
+    ok(ret, "LookupAccountSidA() Expected TRUE, got FALSE\n");
+
+    /* try NULL account */
+    acc_sizeA = MAX_PATH;
+    dom_sizeA = MAX_PATH;
+    ret = LookupAccountSidA(NULL, pUsersSid, NULL, &acc_sizeA, domainA, &dom_sizeA, &use);
+    ok(ret, "LookupAccountSidA() Expected TRUE, got FALSE\n");
+
+    /* try NULL domain */
+    acc_sizeA = MAX_PATH;
+    dom_sizeA = MAX_PATH;
+    ret = LookupAccountSidA(NULL, pUsersSid, accountA, &acc_sizeA, NULL, &dom_sizeA, &use);
+    ok(ret, "LookupAccountSidA() Expected TRUE, got FALSE\n");
+
+    /* try a small account buffer */
+    acc_sizeA = 1;
+    dom_sizeA = MAX_PATH;
+    accountA[0] = 0;
+    ret = LookupAccountSidA(NULL, pUsersSid, accountA, &acc_sizeA, domainA, &dom_sizeA, &use);
+    ok(!ret, "LookupAccountSidA() Expected FALSE got TRUE\n");
+    ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
+       "LookupAccountSidA() Expected ERROR_NOT_ENOUGH_MEMORY, got %u\n", GetLastError());
+
+    /* try a 0 sized account buffer */
+    acc_sizeA = 0;
+    dom_sizeA = MAX_PATH;
+    accountA[0] = 0;
+    ret = LookupAccountSidA(NULL, pUsersSid, accountA, &acc_sizeA, domainA, &dom_sizeA, &use);
+    /* this can fail or succeed depending on OS version but the size will always be returned */
+    ok(acc_sizeA == real_acc_sizeA + 1,
+       "LookupAccountSidA() Expected acc_size = %u, got %u\n",
+       real_acc_sizeA + 1, acc_sizeA);
+
+    /* try a 0 sized account buffer */
+    acc_sizeA = 0;
+    dom_sizeA = MAX_PATH;
+    ret = LookupAccountSidA(NULL, pUsersSid, NULL, &acc_sizeA, domainA, &dom_sizeA, &use);
+    /* this can fail or succeed depending on OS version but the size will always be returned */
+    ok(acc_sizeA == real_acc_sizeA + 1,
+       "LookupAccountSid() Expected acc_size = %u, got %u\n",
+       real_acc_sizeA + 1, acc_sizeA);
+
+    /* try a small domain buffer */
+    dom_sizeA = 1;
+    acc_sizeA = MAX_PATH;
+    accountA[0] = 0;
+    ret = LookupAccountSidA(NULL, pUsersSid, accountA, &acc_sizeA, domainA, &dom_sizeA, &use);
+    ok(!ret, "LookupAccountSidA() Expected FALSE got TRUE\n");
+    ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
+       "LookupAccountSidA() Expected ERROR_NOT_ENOUGH_MEMORY, got %u\n", GetLastError());
+
+    /* try a 0 sized domain buffer */
+    dom_sizeA = 0;
+    acc_sizeA = MAX_PATH;
+    accountA[0] = 0;
+    ret = LookupAccountSidA(NULL, pUsersSid, accountA, &acc_sizeA, domainA, &dom_sizeA, &use);
+    /* this can fail or succeed depending on OS version but the size will always be returned */
+    ok(dom_sizeA == real_dom_sizeA + 1,
+       "LookupAccountSidA() Expected dom_size = %u, got %u\n",
+       real_dom_sizeA + 1, dom_sizeA);
+
+    /* try a 0 sized domain buffer */
+    dom_sizeA = 0;
+    acc_sizeA = MAX_PATH;
+    ret = LookupAccountSidA(NULL, pUsersSid, accountA, &acc_sizeA, NULL, &dom_sizeA, &use);
+    /* this can fail or succeed depending on OS version but the size will always be returned */
+    ok(dom_sizeA == real_dom_sizeA + 1,
+       "LookupAccountSidA() Expected dom_size = %u, got %u\n",
+       real_dom_sizeA + 1, dom_sizeA);
+
+    real_acc_sizeW = MAX_PATH;
+    real_dom_sizeW = MAX_PATH;
+    ret = LookupAccountSidW(NULL, pUsersSid, accountW, &real_acc_sizeW, domainW, &real_dom_sizeW, &use);
+    ok(ret, "LookupAccountSidW() Expected TRUE, got FALSE\n");
+
+    /* native windows crashes if domainW or accountW is NULL */
+
+    /* try a small account buffer */
+    acc_sizeW = 1;
+    dom_sizeW = MAX_PATH;
+    accountW[0] = 0;
+    ret = LookupAccountSidW(NULL, pUsersSid, accountW, &acc_sizeW, domainW, &dom_sizeW, &use);
+    ok(!ret, "LookupAccountSidW() Expected FALSE got TRUE\n");
+    ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
+       "LookupAccountSidW() Expected ERROR_NOT_ENOUGH_MEMORY, got %u\n", GetLastError());
+
+    /* try a 0 sized account buffer */
+    acc_sizeW = 0;
+    dom_sizeW = MAX_PATH;
+    accountW[0] = 0;
+    ret = LookupAccountSidW(NULL, pUsersSid, accountW, &acc_sizeW, domainW, &dom_sizeW, &use);
+    /* this can fail or succeed depending on OS version but the size will always be returned */
+    ok(acc_sizeW == real_acc_sizeW + 1,
+       "LookupAccountSidW() Expected acc_size = %u, got %u\n",
+       real_acc_sizeW + 1, acc_sizeW);
+
+    /* try a 0 sized account buffer */
+    acc_sizeW = 0;
+    dom_sizeW = MAX_PATH;
+    ret = LookupAccountSidW(NULL, pUsersSid, NULL, &acc_sizeW, domainW, &dom_sizeW, &use);
+    /* this can fail or succeed depending on OS version but the size will always be returned */
+    ok(acc_sizeW == real_acc_sizeW + 1,
+       "LookupAccountSidW() Expected acc_size = %u, got %u\n",
+       real_acc_sizeW + 1, acc_sizeW);
+
+    /* try a small domain buffer */
+    dom_sizeW = 1;
+    acc_sizeW = MAX_PATH;
+    accountW[0] = 0;
+    ret = LookupAccountSidW(NULL, pUsersSid, accountW, &acc_sizeW, domainW, &dom_sizeW, &use);
+    ok(!ret, "LookupAccountSidW() Expected FALSE got TRUE\n");
+    ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
+       "LookupAccountSidW() Expected ERROR_NOT_ENOUGH_MEMORY, got %u\n", GetLastError());
+
+    /* try a 0 sized domain buffer */
+    dom_sizeW = 0;
+    acc_sizeW = MAX_PATH;
+    accountW[0] = 0;
+    ret = LookupAccountSidW(NULL, pUsersSid, accountW, &acc_sizeW, domainW, &dom_sizeW, &use);
+    /* this can fail or succeed depending on OS version but the size will always be returned */
+    ok(dom_sizeW == real_dom_sizeW + 1,
+       "LookupAccountSidW() Expected dom_size = %u, got %u\n",
+       real_dom_sizeW + 1, dom_sizeW);
+
+    /* try a 0 sized domain buffer */
+    dom_sizeW = 0;
+    acc_sizeW = MAX_PATH;
+    ret = LookupAccountSidW(NULL, pUsersSid, accountW, &acc_sizeW, NULL, &dom_sizeW, &use);
+    /* this can fail or succeed depending on OS version but the size will always be returned */
+    ok(dom_sizeW == real_dom_sizeW + 1,
+       "LookupAccountSidW() Expected dom_size = %u, got %u\n",
+       real_dom_sizeW + 1, dom_sizeW);
+
+    FreeSid(pUsersSid);
+
+    if (pCreateWellKnownSid && pConvertSidToStringSidA)
+    {
+        trace("Well Known SIDs:\n");
+        for (i = 0; i <= 60; i++)
+        {
+            size = SECURITY_MAX_SID_SIZE;
+            if (pCreateWellKnownSid(i, NULL, &max_sid.sid, &size))
+            {
+                if (pConvertSidToStringSidA(&max_sid.sid, &str_sidA))
+                {
+                    acc_sizeA = MAX_PATH;
+                    dom_sizeA = MAX_PATH;
+                    if (LookupAccountSidA(NULL, &max_sid.sid, accountA, &acc_sizeA, domainA, &dom_sizeA, &use))
+                        trace(" %d: %s %s\\%s %d\n", i, str_sidA, domainA, accountA, use);
+                    LocalFree(str_sidA);
+                }
+            }
+            else
+            {
+                if (GetLastError() != ERROR_INVALID_PARAMETER)
+                    trace(" CreateWellKnownSid(%d) failed: %d\n", i, GetLastError());
+                else
+                    trace(" %d: not supported\n", i);
+            }
+        }
+
+        pLsaQueryInformationPolicy = (fnLsaQueryInformationPolicy)GetProcAddress( hmod, "LsaQueryInformationPolicy");
+        pLsaOpenPolicy = (fnLsaOpenPolicy)GetProcAddress( hmod, "LsaOpenPolicy");
+        pLsaFreeMemory = (fnLsaFreeMemory)GetProcAddress( hmod, "LsaFreeMemory");
+        pLsaClose = (fnLsaClose)GetProcAddress( hmod, "LsaClose");
+
+        if (pLsaQueryInformationPolicy && pLsaOpenPolicy && pLsaFreeMemory && pLsaClose)
+        {
+            NTSTATUS status;
+            LSA_HANDLE handle;
+            LSA_OBJECT_ATTRIBUTES object_attributes;
+
+            ZeroMemory(&object_attributes, sizeof(object_attributes));
+            object_attributes.Length = sizeof(object_attributes);
+
+            status = pLsaOpenPolicy( NULL, &object_attributes, POLICY_ALL_ACCESS, &handle);
+            ok(status == STATUS_SUCCESS || status == STATUS_ACCESS_DENIED,
+               "LsaOpenPolicy(POLICY_ALL_ACCESS) returned 0x%08x\n", status);
+
+            /* try a more restricted access mask if necessary */
+            if (status == STATUS_ACCESS_DENIED) {
+                trace("LsaOpenPolicy(POLICY_ALL_ACCESS) failed, trying POLICY_VIEW_LOCAL_INFORMATION\n");
+                status = pLsaOpenPolicy( NULL, &object_attributes, POLICY_VIEW_LOCAL_INFORMATION, &handle);
+                ok(status == STATUS_SUCCESS, "LsaOpenPolicy(POLICY_VIEW_LOCAL_INFORMATION) returned 0x%08x\n", status);
+            }
+
+            if (status == STATUS_SUCCESS)
+            {
+                PPOLICY_ACCOUNT_DOMAIN_INFO info;
+                status = pLsaQueryInformationPolicy(handle, PolicyAccountDomainInformation, (PVOID*)&info);
+                ok(status == STATUS_SUCCESS, "LsaQueryInformationPolicy() failed, returned 0x%08x\n", status);
+                if (status == STATUS_SUCCESS)
+                {
+                    ok(info->DomainSid!=0, "LsaQueryInformationPolicy(PolicyAccountDomainInformation) missing SID\n");
+                    if (info->DomainSid)
+                    {
+                        int count = *GetSidSubAuthorityCount(info->DomainSid);
+                        CopySid(GetSidLengthRequired(count), &max_sid, info->DomainSid);
+                        test_sid_str((PSID)&max_sid.sid);
+                        max_sid.sid.SubAuthority[count] = DOMAIN_USER_RID_ADMIN;
+                        max_sid.sid.SubAuthorityCount = count + 1;
+                        test_sid_str((PSID)&max_sid.sid);
+                        max_sid.sid.SubAuthority[count] = DOMAIN_USER_RID_GUEST;
+                        test_sid_str((PSID)&max_sid.sid);
+                        max_sid.sid.SubAuthority[count] = DOMAIN_GROUP_RID_ADMINS;
+                        test_sid_str((PSID)&max_sid.sid);
+                        max_sid.sid.SubAuthority[count] = DOMAIN_GROUP_RID_USERS;
+                        test_sid_str((PSID)&max_sid.sid);
+                        max_sid.sid.SubAuthority[count] = DOMAIN_GROUP_RID_GUESTS;
+                        test_sid_str((PSID)&max_sid.sid);
+                        max_sid.sid.SubAuthority[count] = DOMAIN_GROUP_RID_COMPUTERS;
+                        test_sid_str((PSID)&max_sid.sid);
+                        max_sid.sid.SubAuthority[count] = DOMAIN_GROUP_RID_CONTROLLERS;
+                        test_sid_str((PSID)&max_sid.sid);
+                        max_sid.sid.SubAuthority[count] = DOMAIN_GROUP_RID_CERT_ADMINS;
+                        test_sid_str((PSID)&max_sid.sid);
+                        max_sid.sid.SubAuthority[count] = DOMAIN_GROUP_RID_SCHEMA_ADMINS;
+                        test_sid_str((PSID)&max_sid.sid);
+                        max_sid.sid.SubAuthority[count] = DOMAIN_GROUP_RID_ENTERPRISE_ADMINS;
+                        test_sid_str((PSID)&max_sid.sid);
+                        max_sid.sid.SubAuthority[count] = DOMAIN_GROUP_RID_POLICY_ADMINS;
+                        test_sid_str((PSID)&max_sid.sid);
+                        max_sid.sid.SubAuthority[count] = DOMAIN_ALIAS_RID_RAS_SERVERS;
+                        test_sid_str((PSID)&max_sid.sid);
+                        max_sid.sid.SubAuthority[count] = 1000;        /* first user account */
+                        test_sid_str((PSID)&max_sid.sid);
+                    }
+
+                    pLsaFreeMemory((LPVOID)info);
+                }
+
+                status = pLsaClose(handle);
+                ok(status == STATUS_SUCCESS, "LsaClose() failed, returned 0x%08x\n", status);
+            }
+        }
+    }
+}
+
+static void get_sid_info(PSID psid, LPSTR *user, LPSTR *dom)
+{
+    static CHAR account[UNLEN + 1];
+    static CHAR domain[UNLEN + 1];
+    DWORD size, dom_size;
+    SID_NAME_USE use;
+
+    *user = account;
+    *dom = domain;
+
+    size = dom_size = UNLEN + 1;
+    account[0] = '\0';
+    domain[0] = '\0';
+    LookupAccountSidA(NULL, psid, account, &size, domain, &dom_size, &use);
+}
+
+static void test_LookupAccountName(void)
+{
+    DWORD sid_size, domain_size, user_size;
+    DWORD sid_save, domain_save;
+    CHAR user_name[UNLEN + 1];
+    SID_NAME_USE sid_use;
+    LPSTR domain, account, sid_dom;
+    PSID psid;
+    BOOL ret;
+
+    /* native crashes if (assuming all other parameters correct):
+     *  - peUse is NULL
+     *  - Sid is NULL and cbSid is > 0
+     *  - cbSid or cchReferencedDomainName are NULL
+     *  - ReferencedDomainName is NULL and cchReferencedDomainName is the correct size
+     */
+
+    user_size = UNLEN + 1;
+    SetLastError(0xdeadbeef);
+    ret = GetUserNameA(user_name, &user_size);
+    if (!ret && (GetLastError() == ERROR_NOT_LOGGED_ON))
+    {
+        /* Probably on win9x where the user used 'Cancel' instead of properly logging in */
+        skip("Cannot get the user name (win9x and not logged in properly)\n");
+        return;
+    }
+    ok(ret, "Failed to get user name : %d\n", GetLastError());
+
+    /* get sizes */
+    sid_size = 0;
+    domain_size = 0;
+    sid_use = 0xcafebabe;
+    SetLastError(0xdeadbeef);
+    ret = LookupAccountNameA(NULL, user_name, NULL, &sid_size, NULL, &domain_size, &sid_use);
+    if(!ret && (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED))
+    {
+        skip("LookupAccountNameA is not implemented\n");
+        return;
+    }
+    ok(!ret, "Expected 0, got %d\n", ret);
+    ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
+       "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
+    ok(sid_size != 0, "Expected non-zero sid size\n");
+    ok(domain_size != 0, "Expected non-zero domain size\n");
+    ok(sid_use == 0xcafebabe, "Expected 0xcafebabe, got %d\n", sid_use);
+
+    sid_save = sid_size;
+    domain_save = domain_size;
+
+    psid = HeapAlloc(GetProcessHeap(), 0, sid_size);
+    domain = HeapAlloc(GetProcessHeap(), 0, domain_size);
+
+    /* try valid account name */
+    ret = LookupAccountNameA(NULL, user_name, psid, &sid_size, domain, &domain_size, &sid_use);
+    get_sid_info(psid, &account, &sid_dom);
+    ok(ret, "Failed to lookup account name\n");
+    ok(sid_size == GetLengthSid(psid), "Expected %d, got %d\n", GetLengthSid(psid), sid_size);
+    todo_wine
+    {
+        ok(!lstrcmp(account, user_name), "Expected %s, got %s\n", user_name, account);
+        ok(!lstrcmp(domain, sid_dom), "Expected %s, got %s\n", sid_dom, domain);
+        ok(domain_size == domain_save - 1, "Expected %d, got %d\n", domain_save - 1, domain_size);
+        ok(lstrlen(domain) == domain_size, "Expected %d\n", lstrlen(domain));
+        ok(sid_use == SidTypeUser, "Expected SidTypeUser, got %d\n", sid_use);
+    }
+    domain_size = domain_save;
+    sid_size = sid_save;
+
+    if (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH)
+    {
+        skip("Non-english locale (test with hardcoded 'Everyone')\n");
+    }
+    else
+    {
+        ret = LookupAccountNameA(NULL, "Everyone", psid, &sid_size, domain, &domain_size, &sid_use);
+        get_sid_info(psid, &account, &sid_dom);
+        ok(ret, "Failed to lookup account name\n");
+        ok(sid_size != 0, "sid_size was zero\n");
+        ok(!lstrcmp(account, "Everyone"), "Expected Everyone, got %s\n", account);
+        todo_wine
+        ok(!lstrcmp(domain, sid_dom), "Expected %s, got %s\n", sid_dom, domain);
+        ok(domain_size == 0, "Expected 0, got %d\n", domain_size);
+        todo_wine
+        ok(lstrlen(domain) == domain_size, "Expected %d, got %d\n", lstrlen(domain), domain_size);
+        ok(sid_use == SidTypeWellKnownGroup, "Expected SidTypeUser, got %d\n", sid_use);
+        domain_size = domain_save;
+    }
+
+    /* NULL Sid with zero sid size */
+    SetLastError(0xdeadbeef);
+    sid_size = 0;
+    ret = LookupAccountNameA(NULL, user_name, NULL, &sid_size, domain, &domain_size, &sid_use);
+    ok(!ret, "Expected 0, got %d\n", ret);
+    ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
+       "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
+    ok(sid_size == sid_save, "Expected %d, got %d\n", sid_save, sid_size);
+    ok(domain_size == domain_save, "Expected %d, got %d\n", domain_save, domain_size);
+
+    /* try cchReferencedDomainName - 1 */
+    SetLastError(0xdeadbeef);
+    domain_size--;
+    ret = LookupAccountNameA(NULL, user_name, NULL, &sid_size, domain, &domain_size, &sid_use);
+    ok(!ret, "Expected 0, got %d\n", ret);
+    ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
+       "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
+    ok(sid_size == sid_save, "Expected %d, got %d\n", sid_save, sid_size);
+    ok(domain_size == domain_save, "Expected %d, got %d\n", domain_save, domain_size);
+
+    /* NULL ReferencedDomainName with zero domain name size */
+    SetLastError(0xdeadbeef);
+    domain_size = 0;
+    ret = LookupAccountNameA(NULL, user_name, psid, &sid_size, NULL, &domain_size, &sid_use);
+    ok(!ret, "Expected 0, got %d\n", ret);
+    ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
+       "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
+    ok(sid_size == sid_save, "Expected %d, got %d\n", sid_save, sid_size);
+    ok(domain_size == domain_save, "Expected %d, got %d\n", domain_save, domain_size);
+
+    HeapFree(GetProcessHeap(), 0, psid);
+    HeapFree(GetProcessHeap(), 0, domain);
+
+    /* get sizes for NULL account name */
+    sid_size = 0;
+    domain_size = 0;
+    sid_use = 0xcafebabe;
+    SetLastError(0xdeadbeef);
+    ret = LookupAccountNameA(NULL, NULL, NULL, &sid_size, NULL, &domain_size, &sid_use);
+    ok(!ret, "Expected 0, got %d\n", ret);
+    ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
+       "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
+    ok(sid_size != 0, "Expected non-zero sid size\n");
+    ok(domain_size != 0, "Expected non-zero domain size\n");
+    ok(sid_use == 0xcafebabe, "Expected 0xcafebabe, got %d\n", sid_use);
+
+    psid = HeapAlloc(GetProcessHeap(), 0, sid_size);
+    domain = HeapAlloc(GetProcessHeap(), 0, domain_size);
+
+    /* try NULL account name */
+    ret = LookupAccountNameA(NULL, NULL, psid, &sid_size, domain, &domain_size, &sid_use);
+    get_sid_info(psid, &account, &sid_dom);
+    ok(ret, "Failed to lookup account name\n");
+    todo_wine
+    {
+        /* Using a fixed string will not work on different locales */
+        ok(!lstrcmp(account, domain),
+           "Got %s for account and %s for domain, these should be the same\n",
+           account, domain);
+        ok(sid_use == SidTypeDomain, "Expected SidTypeDomain, got %d\n", SidTypeDomain);
+    }
+
+    /* try an invalid account name */
+    SetLastError(0xdeadbeef);
+    sid_size = 0;
+    domain_size = 0;
+    ret = LookupAccountNameA(NULL, "oogabooga", NULL, &sid_size, NULL, &domain_size, &sid_use);
+    ok(!ret, "Expected 0, got %d\n", ret);
+    todo_wine
+    {
+        ok(GetLastError() == ERROR_NONE_MAPPED,
+           "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);
+    }
+
+    HeapFree(GetProcessHeap(), 0, psid);
+    HeapFree(GetProcessHeap(), 0, domain);
+}
+
+static void test_security_descriptor(void)
+{
+    SECURITY_DESCRIPTOR sd;
+    char buf[8192];
+    DWORD size;
+    BOOL isDefault, isPresent, ret;
+    PACL pacl;
+    PSID psid;
+
+    SetLastError(0xdeadbeef);
+    ret = InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
+    if (ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
+    {
+        skip("InitializeSecurityDescriptor is not implemented\n");
+        return;
+    }
+
+    ok(GetSecurityDescriptorOwner(&sd, &psid, &isDefault), "GetSecurityDescriptorOwner failed\n");
+    expect_eq(psid, NULL, PSID, "%p");
+    expect_eq(isDefault, FALSE, BOOL, "%d");
+    sd.Control |= SE_DACL_PRESENT | SE_SACL_PRESENT;
+
+    SetLastError(0xdeadbeef);
+    size = 5;
+    expect_eq(MakeSelfRelativeSD(&sd, buf, &size), FALSE, BOOL, "%d");
+    expect_eq(GetLastError(), ERROR_INSUFFICIENT_BUFFER, DWORD, "%u");
+    ok(size > 5, "Size not increased\n");
+    if (size <= 8192)
+    {
+        expect_eq(MakeSelfRelativeSD(&sd, buf, &size), TRUE, BOOL, "%d");
+        ok(GetSecurityDescriptorOwner(&sd, &psid, &isDefault), "GetSecurityDescriptorOwner failed\n");
+        expect_eq(psid, NULL, PSID, "%p");
+        expect_eq(isDefault, FALSE, BOOL, "%d");
+        ok(GetSecurityDescriptorGroup(&sd, &psid, &isDefault), "GetSecurityDescriptorGroup failed\n");
+        expect_eq(psid, NULL, PSID, "%p");
+        expect_eq(isDefault, FALSE, BOOL, "%d");
+        ok(GetSecurityDescriptorDacl(&sd, &isPresent, &pacl, &isDefault), "GetSecurityDescriptorDacl failed\n");
+        expect_eq(isPresent, TRUE, BOOL, "%d");
+        expect_eq(psid, NULL, PSID, "%p");
+        expect_eq(isDefault, FALSE, BOOL, "%d");
+        ok(GetSecurityDescriptorSacl(&sd, &isPresent, &pacl, &isDefault), "GetSecurityDescriptorSacl failed\n");
+        expect_eq(isPresent, TRUE, BOOL, "%d");
+        expect_eq(psid, NULL, PSID, "%p");
+        expect_eq(isDefault, FALSE, BOOL, "%d");
+    }
+}
+
+#define TEST_GRANTED_ACCESS(a,b) test_granted_access(a,b,__LINE__)
+static void test_granted_access(HANDLE handle, ACCESS_MASK access, int line)
+{
+    OBJECT_BASIC_INFORMATION obj_info;
+    NTSTATUS status;
+
+    if (!pNtQueryObject)
+    {
+        skip_(__FILE__, line)("Not NT platform - skipping tests\n");
+        return;
+    }
+
+    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);
+}
+
+#define CHECK_SET_SECURITY(o,i,e) \
+    do{ \
+        BOOL res; \
+        DWORD err; \
+        SetLastError( 0xdeadbeef ); \
+        res = SetKernelObjectSecurity( o, i, SecurityDescriptor ); \
+        err = GetLastError(); \
+        if (e == ERROR_SUCCESS) \
+            ok(res, "SetKernelObjectSecurity failed with %d\n", err); \
+        else \
+            ok(!res && err == e, "SetKernelObjectSecurity should have failed " \
+               "with %s, instead of %d\n", #e, err); \
+    }while(0)
+
+static void test_process_security(void)
+{
+    BOOL res;
+    char owner[32], group[32];
+    PSID AdminSid = NULL, UsersSid = NULL;
+    PACL Acl = NULL;
+    SECURITY_DESCRIPTOR *SecurityDescriptor = NULL;
+    char buffer[MAX_PATH];
+    PROCESS_INFORMATION info;
+    STARTUPINFOA startup;
+    SECURITY_ATTRIBUTES psa;
+    HANDLE token, event;
+    DWORD tmp;
+
+    Acl = HeapAlloc(GetProcessHeap(), 0, 256);
+    res = InitializeAcl(Acl, 256, ACL_REVISION);
+    if (!res && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
+    {
+        skip("ACLs not implemented - skipping tests\n");
+        HeapFree(GetProcessHeap(), 0, Acl);
+        return;
+    }
+    ok(res, "InitializeAcl failed with error %d\n", GetLastError());
+
+    /* get owner from the token we might be running as a user not admin */
+    res = OpenProcessToken( GetCurrentProcess(), MAXIMUM_ALLOWED, &token );
+    ok(res, "OpenProcessToken failed with error %d\n", GetLastError());
+    if (!res)
+    {
+        HeapFree(GetProcessHeap(), 0, Acl);
+        return;
+    }
+
+    res = GetTokenInformation( token, TokenOwner, owner, sizeof(owner), &tmp );
+    ok(res, "GetTokenInformation failed with error %d\n", GetLastError());
+    AdminSid = ((TOKEN_OWNER*)owner)->Owner;
+    res = GetTokenInformation( token, TokenPrimaryGroup, group, sizeof(group), &tmp );
+    ok(res, "GetTokenInformation failed with error %d\n", GetLastError());
+    UsersSid = ((TOKEN_PRIMARY_GROUP*)group)->PrimaryGroup;
+
+    CloseHandle( token );
+    if (!res)
+    {
+        HeapFree(GetProcessHeap(), 0, Acl);
+        return;
+    }
+
+    res = AddAccessDeniedAce(Acl, ACL_REVISION, PROCESS_VM_READ, AdminSid);
+    ok(res, "AddAccessDeniedAce failed with error %d\n", GetLastError());
+    res = AddAccessAllowedAce(Acl, ACL_REVISION, PROCESS_ALL_ACCESS, AdminSid);
+    ok(res, "AddAccessAllowedAce failed with error %d\n", GetLastError());
+
+    SecurityDescriptor = HeapAlloc(GetProcessHeap(), 0, SECURITY_DESCRIPTOR_MIN_LENGTH);
+    res = InitializeSecurityDescriptor(SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
+    ok(res, "InitializeSecurityDescriptor failed with error %d\n", GetLastError());
+
+    event = CreateEvent( NULL, TRUE, TRUE, "test_event" );
+    ok(event != NULL, "CreateEvent %d\n", GetLastError());
+
+    SecurityDescriptor->Revision = 0;
+    CHECK_SET_SECURITY( event, OWNER_SECURITY_INFORMATION, ERROR_UNKNOWN_REVISION );
+    SecurityDescriptor->Revision = SECURITY_DESCRIPTOR_REVISION;
+
+    CHECK_SET_SECURITY( event, OWNER_SECURITY_INFORMATION, ERROR_INVALID_SECURITY_DESCR );
+    CHECK_SET_SECURITY( event, GROUP_SECURITY_INFORMATION, ERROR_INVALID_SECURITY_DESCR );
+    CHECK_SET_SECURITY( event, SACL_SECURITY_INFORMATION, ERROR_ACCESS_DENIED );
+    CHECK_SET_SECURITY( event, DACL_SECURITY_INFORMATION, ERROR_SUCCESS );
+    /* NULL DACL is valid and means default DACL from token */
+    SecurityDescriptor->Control |= SE_DACL_PRESENT;
+    CHECK_SET_SECURITY( event, DACL_SECURITY_INFORMATION, ERROR_SUCCESS );
+
+    /* Set owner and group and dacl */
+    res = SetSecurityDescriptorOwner(SecurityDescriptor, AdminSid, FALSE);
+    ok(res, "SetSecurityDescriptorOwner failed with error %d\n", GetLastError());
+    CHECK_SET_SECURITY( event, OWNER_SECURITY_INFORMATION, ERROR_SUCCESS );
+    res = SetSecurityDescriptorGroup(SecurityDescriptor, UsersSid, FALSE);
+    ok(res, "SetSecurityDescriptorGroup failed with error %d\n", GetLastError());
+    CHECK_SET_SECURITY( event, GROUP_SECURITY_INFORMATION, ERROR_SUCCESS );
+    res = SetSecurityDescriptorDacl(SecurityDescriptor, TRUE, Acl, FALSE);
+    ok(res, "SetSecurityDescriptorDacl failed with error %d\n", GetLastError());
+    CHECK_SET_SECURITY( event, DACL_SECURITY_INFORMATION, ERROR_SUCCESS );
+
+    sprintf(buffer, "%s tests/security.c test", myARGV[0]);
+    memset(&startup, 0, sizeof(startup));
+    startup.cb = sizeof(startup);
+    startup.dwFlags = STARTF_USESHOWWINDOW;
+    startup.wShowWindow = SW_SHOWNORMAL;
+
+    psa.nLength = sizeof(psa);
+    psa.lpSecurityDescriptor = SecurityDescriptor;
+    psa.bInheritHandle = TRUE;
+
+    /* 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 );
+    winetest_wait_child_process( info.hProcess );
+
+    CloseHandle( info.hProcess );
+    CloseHandle( info.hThread );
+    CloseHandle( event );
+    HeapFree(GetProcessHeap(), 0, Acl);
+    HeapFree(GetProcessHeap(), 0, SecurityDescriptor);
+}
+
+static void test_process_security_child(void)
+{
+    HANDLE handle, handle1;
+    BOOL ret;
+    DWORD err;
+
+    handle = OpenProcess( PROCESS_TERMINATE, FALSE, GetCurrentProcessId() );
+    ok(handle != NULL, "OpenProcess(PROCESS_TERMINATE) with err:%d\n", GetLastError());
+    TEST_GRANTED_ACCESS( handle, PROCESS_TERMINATE );
+
+    ok(DuplicateHandle( GetCurrentProcess(), handle, GetCurrentProcess(),
+                        &handle1, 0, TRUE, DUPLICATE_SAME_ACCESS ),
+       "duplicating handle err:%d\n", GetLastError());
+    TEST_GRANTED_ACCESS( handle1, PROCESS_TERMINATE );
+
+    CloseHandle( handle1 );
+
+    SetLastError( 0xdeadbeef );
+    ret = DuplicateHandle( GetCurrentProcess(), handle, GetCurrentProcess(),
+                           &handle1, PROCESS_ALL_ACCESS, TRUE, 0 );
+    err = GetLastError();
+    todo_wine
+    ok(!ret && err == ERROR_ACCESS_DENIED, "duplicating handle should have failed "
+       "with STATUS_ACCESS_DENIED, instead of err:%d\n", err);
+
+    CloseHandle( handle );
+
+    /* These two should fail - they are denied by ACL */
+    handle = OpenProcess( PROCESS_VM_READ, FALSE, GetCurrentProcessId() );
+    todo_wine
+    ok(handle == NULL, "OpenProcess(PROCESS_VM_READ) should have failed\n");
+    handle = OpenProcess( PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId() );
+    todo_wine
+    ok(handle == NULL, "OpenProcess(PROCESS_ALL_ACCESS) should have failed\n");
+
+    /* Documented privilege elevation */
+    ok(DuplicateHandle( GetCurrentProcess(), GetCurrentProcess(), GetCurrentProcess(),
+                        &handle, 0, TRUE, DUPLICATE_SAME_ACCESS ),
+       "duplicating handle err:%d\n", GetLastError());
+    TEST_GRANTED_ACCESS( handle, PROCESS_ALL_ACCESS );
+
+    CloseHandle( handle );
+
+    /* Same only explicitly asking for all access rights */
+    ok(DuplicateHandle( GetCurrentProcess(), GetCurrentProcess(), GetCurrentProcess(),
+                        &handle, PROCESS_ALL_ACCESS, TRUE, 0 ),
+       "duplicating handle err:%d\n", GetLastError());
+    TEST_GRANTED_ACCESS( handle, PROCESS_ALL_ACCESS );
+    ok(DuplicateHandle( GetCurrentProcess(), handle, GetCurrentProcess(),
+                        &handle1, PROCESS_VM_READ, TRUE, 0 ),
+       "duplicating handle err:%d\n", GetLastError());
+    TEST_GRANTED_ACCESS( handle1, PROCESS_VM_READ );
+    CloseHandle( handle1 );
+    CloseHandle( handle );
+}
+
+static void test_impersonation_level(void)
+{
+    HANDLE Token, ProcessToken;
+    HANDLE Token2;
+    DWORD Size;
+    TOKEN_PRIVILEGES *Privileges;
+    TOKEN_USER *User;
+    PRIVILEGE_SET *PrivilegeSet;
+    BOOL AccessGranted;
+    BOOL ret;
+    HKEY hkey;
+    DWORD error;
+
+    pDuplicateTokenEx = (fnDuplicateTokenEx) GetProcAddress(hmod, "DuplicateTokenEx");
+    if( !pDuplicateTokenEx ) {
+        skip("DuplicateTokenEx is not available\n");
+        return;
+    }
+    SetLastError(0xdeadbeef);
+    ret = ImpersonateSelf(SecurityAnonymous);
+    if(!ret && (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED))
+    {
+        skip("ImpersonateSelf is not implemented\n");
+        return;
+    }
+    ok(ret, "ImpersonateSelf(SecurityAnonymous) failed with error %d\n", GetLastError());
+    ret = OpenThreadToken(GetCurrentThread(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY_SOURCE | TOKEN_IMPERSONATE | TOKEN_ADJUST_DEFAULT, TRUE, &Token);
+    ok(!ret, "OpenThreadToken should have failed\n");
+    error = GetLastError();
+    ok(error == ERROR_CANT_OPEN_ANONYMOUS, "OpenThreadToken on anonymous token should have returned ERROR_CANT_OPEN_ANONYMOUS instead of %d\n", error);
+    /* can't perform access check when opening object against an anonymous impersonation token */
+    todo_wine {
+    error = RegOpenKeyEx(HKEY_CURRENT_USER, "Software", 0, KEY_READ, &hkey);
+    ok(error == ERROR_INVALID_HANDLE, "RegOpenKeyEx should have failed with ERROR_INVALID_HANDLE instead of %d\n", error);
+    }
+    RevertToSelf();
+
+    ret = OpenProcessToken(GetCurrentProcess(), TOKEN_DUPLICATE, &ProcessToken);
+    ok(ret, "OpenProcessToken failed with error %d\n", GetLastError());
+
+    ret = pDuplicateTokenEx(ProcessToken,
+        TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE, NULL,
+        SecurityAnonymous, TokenImpersonation, &Token);
+    ok(ret, "DuplicateTokenEx failed with error %d\n", GetLastError());
+    /* can't increase the impersonation level */
+    ret = DuplicateToken(Token, SecurityIdentification, &Token2);
+    error = GetLastError();
+    ok(!ret && error == ERROR_BAD_IMPERSONATION_LEVEL,
+        "Duplicating a token and increasing the impersonation level should have failed with ERROR_BAD_IMPERSONATION_LEVEL instead of %d\n", error);
+    /* we can query anything from an anonymous token, including the user */
+    ret = GetTokenInformation(Token, TokenUser, NULL, 0, &Size);
+    error = GetLastError();
+    ok(!ret && error == ERROR_INSUFFICIENT_BUFFER, "GetTokenInformation(TokenUser) should have failed with ERROR_INSUFFICIENT_BUFFER instead of %d\n", error);
+    User = (TOKEN_USER *)HeapAlloc(GetProcessHeap(), 0, Size);
+    ret = GetTokenInformation(Token, TokenUser, User, Size, &Size);
+    ok(ret, "GetTokenInformation(TokenUser) failed with error %d\n", GetLastError());
+    HeapFree(GetProcessHeap(), 0, User);
+
+    /* PrivilegeCheck fails with SecurityAnonymous level */
+    ret = GetTokenInformation(Token, TokenPrivileges, NULL, 0, &Size);
+    error = GetLastError();
+    ok(!ret && error == ERROR_INSUFFICIENT_BUFFER, "GetTokenInformation(TokenPrivileges) should have failed with ERROR_INSUFFICIENT_BUFFER instead of %d\n", error);
+    Privileges = (TOKEN_PRIVILEGES *)HeapAlloc(GetProcessHeap(), 0, Size);
+    ret = GetTokenInformation(Token, TokenPrivileges, Privileges, Size, &Size);
+    ok(ret, "GetTokenInformation(TokenPrivileges) failed with error %d\n", GetLastError());
+
+    PrivilegeSet = (PRIVILEGE_SET *)HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(PRIVILEGE_SET, Privilege[Privileges->PrivilegeCount]));
+    PrivilegeSet->PrivilegeCount = Privileges->PrivilegeCount;
+    memcpy(PrivilegeSet->Privilege, Privileges->Privileges, PrivilegeSet->PrivilegeCount * sizeof(PrivilegeSet->Privilege[0]));
+    PrivilegeSet->Control = PRIVILEGE_SET_ALL_NECESSARY;
+    HeapFree(GetProcessHeap(), 0, Privileges);
+
+    ret = PrivilegeCheck(Token, PrivilegeSet, &AccessGranted);
+    error = GetLastError();
+    ok(!ret && error == ERROR_BAD_IMPERSONATION_LEVEL, "PrivilegeCheck for SecurityAnonymous token should have failed with ERROR_BAD_IMPERSONATION_LEVEL instead of %d\n", error);
+
+    CloseHandle(Token);
+
+    ret = ImpersonateSelf(SecurityIdentification);
+    ok(ret, "ImpersonateSelf(SecurityIdentification) failed with error %d\n", GetLastError());
+    ret = OpenThreadToken(GetCurrentThread(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY_SOURCE | TOKEN_IMPERSONATE | TOKEN_ADJUST_DEFAULT, TRUE, &Token);
+    ok(ret, "OpenThreadToken failed with error %d\n", GetLastError());
+
+    /* can't perform access check when opening object against an identification impersonation token */
+    error = RegOpenKeyEx(HKEY_CURRENT_USER, "Software", 0, KEY_READ, &hkey);
+    todo_wine {
+    ok(error == ERROR_INVALID_HANDLE, "RegOpenKeyEx should have failed with ERROR_INVALID_HANDLE instead of %d\n", error);
+    }
+    ret = PrivilegeCheck(Token, PrivilegeSet, &AccessGranted);
+    ok(ret, "PrivilegeCheck for SecurityIdentification failed with error %d\n", GetLastError());
+    CloseHandle(Token);
+    RevertToSelf();
+
+    ret = ImpersonateSelf(SecurityImpersonation);
+    ok(ret, "ImpersonateSelf(SecurityImpersonation) failed with error %d\n", GetLastError());
+    ret = OpenThreadToken(GetCurrentThread(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY_SOURCE | TOKEN_IMPERSONATE | TOKEN_ADJUST_DEFAULT, TRUE, &Token);
+    ok(ret, "OpenThreadToken failed with error %d\n", GetLastError());
+    error = RegOpenKeyEx(HKEY_CURRENT_USER, "Software", 0, KEY_READ, &hkey);
+    ok(error == ERROR_SUCCESS, "RegOpenKeyEx should have succeeded instead of failing with %d\n", error);
+    RegCloseKey(hkey);
+    ret = PrivilegeCheck(Token, PrivilegeSet, &AccessGranted);
+    ok(ret, "PrivilegeCheck for SecurityImpersonation failed with error %d\n", GetLastError());
+    RevertToSelf();
+
+    CloseHandle(Token);
+    CloseHandle(ProcessToken);
+
+    HeapFree(GetProcessHeap(), 0, PrivilegeSet);
+}
+
+static void test_SetEntriesInAcl(void)
+{
+    DWORD res;
+    PSID EveryoneSid = NULL, UsersSid = NULL;
+    PACL OldAcl = NULL, NewAcl;
+    SID_IDENTIFIER_AUTHORITY SIDAuthWorld = { SECURITY_WORLD_SID_AUTHORITY };
+    SID_IDENTIFIER_AUTHORITY SIDAuthNT = { SECURITY_NT_AUTHORITY };
+    EXPLICIT_ACCESSW ExplicitAccess;
+    static const WCHAR wszEveryone[] = {'E','v','e','r','y','o','n','e',0};
+
+    if (!pSetEntriesInAclW)
+    {
+        skip("SetEntriesInAclW is not available\n");
+        return;
+    }
+
+    NewAcl = (PACL)0xdeadbeef;
+    res = pSetEntriesInAclW(0, NULL, NULL, &NewAcl);
+    if(res == ERROR_CALL_NOT_IMPLEMENTED)
+    {
+        skip("SetEntriesInAclW is not implemented\n");
+        return;
+    }
+    ok(res == ERROR_SUCCESS, "SetEntriesInAclW failed: %u\n", res);
+    ok(NewAcl == NULL, "NewAcl=%p, expected NULL\n", NewAcl);
+
+    OldAcl = HeapAlloc(GetProcessHeap(), 0, 256);
+    res = InitializeAcl(OldAcl, 256, ACL_REVISION);
+    if(!res && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
+    {
+        skip("ACLs not implemented - skipping tests\n");
+        HeapFree(GetProcessHeap(), 0, OldAcl);
+        return;
+    }
+    ok(res, "InitializeAcl failed with error %d\n", GetLastError());
+
+    res = AllocateAndInitializeSid( &SIDAuthWorld, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &EveryoneSid);
+    ok(res, "AllocateAndInitializeSid failed with error %d\n", GetLastError());
+
+    res = AllocateAndInitializeSid( &SIDAuthNT, 2, SECURITY_BUILTIN_DOMAIN_RID,
+        DOMAIN_ALIAS_RID_USERS, 0, 0, 0, 0, 0, 0, &UsersSid);
+    ok(res, "AllocateAndInitializeSid failed with error %d\n", GetLastError());
+
+    res = AddAccessAllowedAce(OldAcl, ACL_REVISION, KEY_READ, UsersSid);
+    ok(res, "AddAccessAllowedAce failed with error %d\n", GetLastError());
+
+    ExplicitAccess.grfAccessPermissions = KEY_WRITE;
+    ExplicitAccess.grfAccessMode = GRANT_ACCESS;
+    ExplicitAccess.grfInheritance = NO_INHERITANCE;
+    ExplicitAccess.Trustee.pMultipleTrustee = NULL;
+    ExplicitAccess.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
+    ExplicitAccess.Trustee.TrusteeForm = TRUSTEE_IS_SID;
+    ExplicitAccess.Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
+    ExplicitAccess.Trustee.ptstrName = (LPWSTR)EveryoneSid;
+    res = pSetEntriesInAclW(1, &ExplicitAccess, OldAcl, &NewAcl);
+    ok(res == ERROR_SUCCESS, "SetEntriesInAclW failed: %u\n", res);
+    ok(NewAcl != NULL, "returned acl was NULL\n");
+    LocalFree(NewAcl);
+
+    if (PRIMARYLANGID(LANGIDFROMLCID(GetThreadLocale())) != LANG_ENGLISH)
+    {
+        skip("Non-english locale (test with hardcoded 'Everyone')\n");
+    }
+    else
+    {
+        ExplicitAccess.Trustee.TrusteeForm = TRUSTEE_IS_USER;
+        ExplicitAccess.Trustee.ptstrName = (LPWSTR)wszEveryone;
+        res = pSetEntriesInAclW(1, &ExplicitAccess, OldAcl, &NewAcl);
+        ok(res == ERROR_SUCCESS, "SetEntriesInAclW failed: %u\n", res);
+        ok(NewAcl != NULL, "returned acl was NULL\n");
+        LocalFree(NewAcl);
+
+        ExplicitAccess.Trustee.TrusteeForm = TRUSTEE_BAD_FORM;
+        res = pSetEntriesInAclW(1, &ExplicitAccess, OldAcl, &NewAcl);
+        ok(res == ERROR_INVALID_PARAMETER, "SetEntriesInAclW failed: %u\n", res);
+        ok(NewAcl == NULL, "returned acl wasn't NULL: %p\n", NewAcl);
+        LocalFree(NewAcl);
+
+        ExplicitAccess.Trustee.TrusteeForm = TRUSTEE_IS_USER;
+        ExplicitAccess.Trustee.MultipleTrusteeOperation = TRUSTEE_IS_IMPERSONATE;
+        res = pSetEntriesInAclW(1, &ExplicitAccess, OldAcl, &NewAcl);
+        ok(res == ERROR_INVALID_PARAMETER, "SetEntriesInAclW failed: %u\n", res);
+        ok(NewAcl == NULL, "returned acl wasn't NULL: %p\n", NewAcl);
+        LocalFree(NewAcl);
+
+        ExplicitAccess.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
+        ExplicitAccess.grfAccessMode = SET_ACCESS;
+        res = pSetEntriesInAclW(1, &ExplicitAccess, OldAcl, &NewAcl);
+        ok(res == ERROR_SUCCESS, "SetEntriesInAclW failed: %u\n", res);
+        ok(NewAcl != NULL, "returned acl was NULL\n");
+        LocalFree(NewAcl);
+    }
+
+    ExplicitAccess.grfAccessMode = REVOKE_ACCESS;
+    ExplicitAccess.Trustee.TrusteeForm = TRUSTEE_IS_SID;
+    ExplicitAccess.Trustee.ptstrName = (LPWSTR)UsersSid;
+    res = pSetEntriesInAclW(1, &ExplicitAccess, OldAcl, &NewAcl);
+    ok(res == ERROR_SUCCESS, "SetEntriesInAclW failed: %u\n", res);
+    ok(NewAcl != NULL, "returned acl was NULL\n");
+    LocalFree(NewAcl);
+
+    LocalFree(UsersSid);
+    LocalFree(EveryoneSid);
+    HeapFree(GetProcessHeap(), 0, OldAcl);
+}
+
+static void test_GetNamedSecurityInfoA(void)
+{
+    PSECURITY_DESCRIPTOR pSecDesc;
+    DWORD revision;
+    SECURITY_DESCRIPTOR_CONTROL control;
+    PSID owner;
+    PSID group;
+    BOOL owner_defaulted;
+    BOOL group_defaulted;
+    DWORD error;
+    BOOL ret;
+    CHAR windows_dir[MAX_PATH];
+
+    if (!pGetNamedSecurityInfoA)
+    {
+        skip("GetNamedSecurityInfoA is not available\n");
+        return;
+    }
+
+    ret = GetWindowsDirectoryA(windows_dir, MAX_PATH);
+    ok(ret, "GetWindowsDirectory failed with error %d\n", GetLastError());
+
+    SetLastError(0xdeadbeef);
+    error = pGetNamedSecurityInfoA(windows_dir, SE_FILE_OBJECT,
+        OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION,
+        NULL, NULL, NULL, NULL, &pSecDesc);
+    if (error != ERROR_SUCCESS && (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED))
+    {
+        skip("GetNamedSecurityInfoA is not implemented\n");
+        return;
+    }
+    ok(!error, "GetNamedSecurityInfo failed with error %d\n", error);
+
+    ret = GetSecurityDescriptorControl(pSecDesc, &control, &revision);
+    ok(ret, "GetSecurityDescriptorControl failed with error %d\n", GetLastError());
+    ok((control & (SE_SELF_RELATIVE|SE_DACL_PRESENT)) == (SE_SELF_RELATIVE|SE_DACL_PRESENT),
+        "control (0x%x) doesn't have (SE_SELF_RELATIVE|SE_DACL_PRESENT) flags set\n", control);
+    ok(revision == SECURITY_DESCRIPTOR_REVISION1, "revision was %d instead of 1\n", revision);
+    ret = GetSecurityDescriptorOwner(pSecDesc, &owner, &owner_defaulted);
+    ok(ret, "GetSecurityDescriptorOwner failed with error %d\n", GetLastError());
+    ok(owner != NULL, "owner should not be NULL\n");
+    ret = GetSecurityDescriptorGroup(pSecDesc, &group, &group_defaulted);
+    ok(ret, "GetSecurityDescriptorGroup failed with error %d\n", GetLastError());
+    ok(group != NULL, "group should not be NULL\n");
+}
+
+static void test_ConvertStringSecurityDescriptor(void)
+{
+    BOOL ret;
+    PSECURITY_DESCRIPTOR pSD;
+
+    if (!pConvertStringSecurityDescriptorToSecurityDescriptorA)
+    {
+        skip("ConvertStringSecurityDescriptorToSecurityDescriptor is not available\n");
+        return;
+    }
+
+    SetLastError(0xdeadbeef);
+    ret = pConvertStringSecurityDescriptorToSecurityDescriptorA(
+        "D:(A;;GA;;;WD)", 0xdeadbeef, &pSD, NULL);
+    ok(!ret && GetLastError() == ERROR_UNKNOWN_REVISION,
+        "ConvertStringSecurityDescriptorToSecurityDescriptor should have failed with ERROR_UNKNOWN_REVISION instead of %d\n",
+        GetLastError());
+
+    /* test ACE string type */
+    SetLastError(0xdeadbeef);
+    ret = pConvertStringSecurityDescriptorToSecurityDescriptorA(
+        "D:(A;;GA;;;WD)", SDDL_REVISION_1, &pSD, NULL);
+    ok(ret, "ConvertStringSecurityDescriptorToSecurityDescriptor failed with error %d\n", GetLastError());
+    LocalFree(pSD);
+
+    SetLastError(0xdeadbeef);
+    ret = pConvertStringSecurityDescriptorToSecurityDescriptorA(
+        "D:(D;;GA;;;WD)", SDDL_REVISION_1, &pSD, NULL);
+    ok(ret, "ConvertStringSecurityDescriptorToSecurityDescriptor failed with error %d\n", GetLastError());
+    LocalFree(pSD);
+
+    SetLastError(0xdeadbeef);
+    ret = pConvertStringSecurityDescriptorToSecurityDescriptorA(
+        "ERROR:(D;;GA;;;WD)", SDDL_REVISION_1, &pSD, NULL);
+    ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
+        "ConvertStringSecurityDescriptorToSecurityDescriptor should have failed with ERROR_INVALID_PARAMETER instead of %d\n",
+        GetLastError());
+
+    /* test ACE string access rights */
+    SetLastError(0xdeadbeef);
+    ret = pConvertStringSecurityDescriptorToSecurityDescriptorA(
+        "D:(A;;GA;;;WD)", SDDL_REVISION_1, &pSD, NULL);
+    ok(ret, "ConvertStringSecurityDescriptorToSecurityDescriptor failed with error %d\n", GetLastError());
+    LocalFree(pSD);
+    SetLastError(0xdeadbeef);
+    ret = pConvertStringSecurityDescriptorToSecurityDescriptorA(
+        "D:(A;;GRGWGX;;;WD)", SDDL_REVISION_1, &pSD, NULL);
+    ok(ret, "ConvertStringSecurityDescriptorToSecurityDescriptor failed with error %d\n", GetLastError());
+    LocalFree(pSD);
+    SetLastError(0xdeadbeef);
+    ret = pConvertStringSecurityDescriptorToSecurityDescriptorA(
+        "D:(A;;RCSDWDWO;;;WD)", SDDL_REVISION_1, &pSD, NULL);
+    ok(ret, "ConvertStringSecurityDescriptorToSecurityDescriptor failed with error %d\n", GetLastError());
+    LocalFree(pSD);
+    SetLastError(0xdeadbeef);
+    ret = pConvertStringSecurityDescriptorToSecurityDescriptorA(
+        "D:(A;;RPWPCCDCLCSWLODTCR;;;WD)", SDDL_REVISION_1, &pSD, NULL);
+    ok(ret, "ConvertStringSecurityDescriptorToSecurityDescriptor failed with error %d\n", GetLastError());
+    LocalFree(pSD);
+    SetLastError(0xdeadbeef);
+    ret = pConvertStringSecurityDescriptorToSecurityDescriptorA(
+        "D:(A;;FAFRFWFX;;;WD)", SDDL_REVISION_1, &pSD, NULL);
+    ok(ret, "ConvertStringSecurityDescriptorToSecurityDescriptor failed with error %d\n", GetLastError());
+    LocalFree(pSD);
+    SetLastError(0xdeadbeef);
+    ret = pConvertStringSecurityDescriptorToSecurityDescriptorA(
+        "D:(A;;KAKRKWKX;;;WD)", SDDL_REVISION_1, &pSD, NULL);
+    ok(ret, "ConvertStringSecurityDescriptorToSecurityDescriptor failed with error %d\n", GetLastError());
+    LocalFree(pSD);
+    SetLastError(0xdeadbeef);
+    ret = pConvertStringSecurityDescriptorToSecurityDescriptorA(
+        "D:(A;;0xFFFFFFFF;;;WD)", SDDL_REVISION_1, &pSD, NULL);
+    ok(ret, "ConvertStringSecurityDescriptorToSecurityDescriptor failed with error %d\n", GetLastError());
+    LocalFree(pSD);
+    SetLastError(0xdeadbeef);
+    ret = pConvertStringSecurityDescriptorToSecurityDescriptorA(
+        "S:(AU;;0xFFFFFFFF;;;WD)", SDDL_REVISION_1, &pSD, NULL);
+    ok(ret, "ConvertStringSecurityDescriptorToSecurityDescriptor failed with error %d\n", GetLastError());
+    LocalFree(pSD);
+
+    /* test ACE string access right error case */
+    SetLastError(0xdeadbeef);
+    ret = pConvertStringSecurityDescriptorToSecurityDescriptorA(
+        "D:(A;;ROB;;;WD)", SDDL_REVISION_1, &pSD, NULL);
+    todo_wine
+    ok(!ret && GetLastError() == ERROR_INVALID_ACL,
+        "ConvertStringSecurityDescriptorToSecurityDescriptor should have failed with ERROR_INVALID_ACL instead of %d\n",
+        GetLastError());
+
+    /* test ACE string SID */
+    SetLastError(0xdeadbeef);
+    ret = pConvertStringSecurityDescriptorToSecurityDescriptorA(
+        "D:(D;;GA;;;S-1-0-0)", SDDL_REVISION_1, &pSD, NULL);
+    ok(ret, "ConvertStringSecurityDescriptorToSecurityDescriptor failed with error %d\n", GetLastError());
+    LocalFree(pSD);
+
+    SetLastError(0xdeadbeef);
+    ret = pConvertStringSecurityDescriptorToSecurityDescriptorA(
+        "D:(D;;GA;;;Nonexistent account)", SDDL_REVISION_1, &pSD, NULL);
+    ok(!ret, "Expected failure, got %d\n", ret);
+    ok(GetLastError() == ERROR_INVALID_ACL || GetLastError() == ERROR_INVALID_SID,
+       "Expected ERROR_INVALID_ACL or ERROR_INVALID_SID, got %d\n", GetLastError());
+}
+
+static void test_ConvertSecurityDescriptorToString()
+{
+    SECURITY_DESCRIPTOR desc;
+    SECURITY_INFORMATION sec_info = OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION|SACL_SECURITY_INFORMATION;
+    LPSTR string;
+    DWORD size;
+    PSID psid, psid2;
+    PACL pacl;
+    char sid_buf[256];
+    char acl_buf[8192];
+    ULONG len;
+
+    if (!pConvertSecurityDescriptorToStringSecurityDescriptorA)
+    {
+        skip("ConvertSecurityDescriptorToStringSecurityDescriptor is not available\n");
+        return;
+    }
+    if (!pCreateWellKnownSid)
+    {
+        skip("CreateWellKnownSid is not available\n");
+        return;
+    }
+
+/* It seems Windows XP adds an extra character to the length of the string for each ACE in an ACL. We
+ * don't replicate this feature so we only test len >= strlen+1. */
+#define CHECK_RESULT_AND_FREE(exp_str) \
+    ok(strcmp(string, (exp_str)) == 0, "String mismatch (expected \"%s\", got \"%s\")\n", (exp_str), string); \
+    ok(len >= (lstrlen(exp_str) + 1), "Length mismatch (expected %d, got %d)\n", lstrlen(exp_str) + 1, len); \
+    LocalFree(string);
+
+#define CHECK_ONE_OF_AND_FREE(exp_str1, exp_str2) \
+    ok(strcmp(string, (exp_str1)) == 0 || strcmp(string, (exp_str2)) == 0, "String mismatch (expected\n\"%s\" or\n\"%s\", got\n\"%s\")\n", (exp_str1), (exp_str2), string); \
+    ok(len >= (strlen(string) + 1), "Length mismatch (expected %d, got %d)\n", lstrlen(string) + 1, len); \
+    LocalFree(string);
+
+    InitializeSecurityDescriptor(&desc, SECURITY_DESCRIPTOR_REVISION);
+    ok(pConvertSecurityDescriptorToStringSecurityDescriptorA(&desc, SDDL_REVISION_1, sec_info, &string, &len), "Conversion failed\n");
+    CHECK_RESULT_AND_FREE("");
+
+    size = 4096;
+    pCreateWellKnownSid(WinLocalSid, NULL, sid_buf, &size);
+    SetSecurityDescriptorOwner(&desc, (PSID)sid_buf, FALSE);
+    ok(pConvertSecurityDescriptorToStringSecurityDescriptorA(&desc, SDDL_REVISION_1, sec_info, &string, &len), "Conversion failed\n");
+    CHECK_RESULT_AND_FREE("O:S-1-2-0");
+
+    SetSecurityDescriptorOwner(&desc, (PSID)sid_buf, TRUE);
+    ok(pConvertSecurityDescriptorToStringSecurityDescriptorA(&desc, SDDL_REVISION_1, sec_info, &string, &len), "Conversion failed\n");
+    CHECK_RESULT_AND_FREE("O:S-1-2-0");
+
+    size = sizeof(sid_buf);
+    pCreateWellKnownSid(WinLocalSystemSid, NULL, sid_buf, &size);
+    SetSecurityDescriptorOwner(&desc, (PSID)sid_buf, TRUE);
+    ok(pConvertSecurityDescriptorToStringSecurityDescriptorA(&desc, SDDL_REVISION_1, sec_info, &string, &len), "Conversion failed\n");
+    CHECK_RESULT_AND_FREE("O:SY");
+
+    pConvertStringSidToSidA("S-1-5-21-93476-23408-4576", &psid);
+    SetSecurityDescriptorGroup(&desc, psid, TRUE);
+    ok(pConvertSecurityDescriptorToStringSecurityDescriptorA(&desc, SDDL_REVISION_1, sec_info, &string, &len), "Conversion failed\n");
+    CHECK_RESULT_AND_FREE("O:SYG:S-1-5-21-93476-23408-4576");
+
+    ok(pConvertSecurityDescriptorToStringSecurityDescriptorA(&desc, SDDL_REVISION_1, GROUP_SECURITY_INFORMATION, &string, &len), "Conversion failed\n");
+    CHECK_RESULT_AND_FREE("G:S-1-5-21-93476-23408-4576");
+
+    pacl = (PACL)acl_buf;
+    InitializeAcl(pacl, sizeof(acl_buf), ACL_REVISION);
+    SetSecurityDescriptorDacl(&desc, TRUE, pacl, TRUE);
+    ok(pConvertSecurityDescriptorToStringSecurityDescriptorA(&desc, SDDL_REVISION_1, sec_info, &string, &len), "Conversion failed\n");
+    CHECK_RESULT_AND_FREE("O:SYG:S-1-5-21-93476-23408-4576D:");
+
+    SetSecurityDescriptorDacl(&desc, TRUE, pacl, FALSE);
+    ok(pConvertSecurityDescriptorToStringSecurityDescriptorA(&desc, SDDL_REVISION_1, sec_info, &string, &len), "Conversion failed\n");
+    CHECK_RESULT_AND_FREE("O:SYG:S-1-5-21-93476-23408-4576D:");
+
+    pConvertStringSidToSidA("S-1-5-6", &psid2);
+    pAddAccessAllowedAceEx(pacl, ACL_REVISION, NO_PROPAGATE_INHERIT_ACE, 0xf0000000, psid2);
+    ok(pConvertSecurityDescriptorToStringSecurityDescriptorA(&desc, SDDL_REVISION_1, sec_info, &string, &len), "Conversion failed\n");
+    CHECK_RESULT_AND_FREE("O:SYG:S-1-5-21-93476-23408-4576D:(A;NP;GAGXGWGR;;;SU)");
+
+    pAddAccessAllowedAceEx(pacl, ACL_REVISION, INHERIT_ONLY_ACE|INHERITED_ACE, 0x00000003, psid2);
+    ok(pConvertSecurityDescriptorToStringSecurityDescriptorA(&desc, SDDL_REVISION_1, sec_info, &string, &len), "Conversion failed\n");
+    CHECK_RESULT_AND_FREE("O:SYG:S-1-5-21-93476-23408-4576D:(A;NP;GAGXGWGR;;;SU)(A;IOID;CCDC;;;SU)");
+
+    pAddAccessDeniedAceEx(pacl, ACL_REVISION, OBJECT_INHERIT_ACE|CONTAINER_INHERIT_ACE, 0xffffffff, psid);
+    ok(pConvertSecurityDescriptorToStringSecurityDescriptorA(&desc, SDDL_REVISION_1, sec_info, &string, &len), "Conversion failed\n");
+    CHECK_RESULT_AND_FREE("O:SYG:S-1-5-21-93476-23408-4576D:(A;NP;GAGXGWGR;;;SU)(A;IOID;CCDC;;;SU)(D;OICI;0xffffffff;;;S-1-5-21-93476-23408-4576)");
+
+
+    pacl = (PACL)acl_buf;
+    InitializeAcl(pacl, sizeof(acl_buf), ACL_REVISION);
+    SetSecurityDescriptorSacl(&desc, TRUE, pacl, FALSE);
+    ok(pConvertSecurityDescriptorToStringSecurityDescriptorA(&desc, SDDL_REVISION_1, sec_info, &string, &len), "Conversion failed\n");
+    CHECK_RESULT_AND_FREE("O:SYG:S-1-5-21-93476-23408-4576D:S:");
+
+    /* fails in win2k */
+    SetSecurityDescriptorDacl(&desc, TRUE, NULL, FALSE);
+    pAddAuditAccessAceEx(pacl, ACL_REVISION, VALID_INHERIT_FLAGS, KEY_READ|KEY_WRITE, psid2, TRUE, TRUE);
+    if (pConvertSecurityDescriptorToStringSecurityDescriptorA(&desc, SDDL_REVISION_1, sec_info, &string, &len))
+    {
+        CHECK_ONE_OF_AND_FREE("O:SYG:S-1-5-21-93476-23408-4576D:S:(AU;OICINPIOIDSAFA;CCDCLCSWRPRC;;;SU)", /* XP */
+            "O:SYG:S-1-5-21-93476-23408-4576D:NO_ACCESS_CONTROLS:(AU;OICINPIOIDSAFA;CCDCLCSWRPRC;;;SU)" /* Vista */);
+    }
+
+    /* fails in win2k */
+    pAddAuditAccessAceEx(pacl, ACL_REVISION, NO_PROPAGATE_INHERIT_ACE, FILE_GENERIC_READ|FILE_GENERIC_WRITE, psid2, TRUE, FALSE);
+    if (pConvertSecurityDescriptorToStringSecurityDescriptorA(&desc, SDDL_REVISION_1, sec_info, &string, &len))
+    {
+        CHECK_ONE_OF_AND_FREE("O:SYG:S-1-5-21-93476-23408-4576D:S:(AU;OICINPIOIDSAFA;CCDCLCSWRPRC;;;SU)(AU;NPSA;0x12019f;;;SU)", /* XP */
+            "O:SYG:S-1-5-21-93476-23408-4576D:NO_ACCESS_CONTROLS:(AU;OICINPIOIDSAFA;CCDCLCSWRPRC;;;SU)(AU;NPSA;0x12019f;;;SU)" /* Vista */);
+    }
+}
+
+static void test_PrivateObjectSecurity(void)
+{
+    SECURITY_INFORMATION sec_info = OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION|SACL_SECURITY_INFORMATION;
+    SECURITY_DESCRIPTOR_CONTROL ctrl;
+    PSECURITY_DESCRIPTOR sec;
+    DWORD dwDescSize;
+    DWORD dwRevision;
+    DWORD retSize;
+    LPSTR string;
+    ULONG len;
+    PSECURITY_DESCRIPTOR buf;
+
+    if (!pConvertStringSecurityDescriptorToSecurityDescriptorA)
+    {
+        skip("ConvertStringSecurityDescriptorToSecurityDescriptor is not available\n");
+        return;
+    }
+
+    ok(pConvertStringSecurityDescriptorToSecurityDescriptorA(
+        "O:SY"
+        "G:S-1-5-21-93476-23408-4576"
+        "D:(A;NP;GAGXGWGR;;;SU)(A;IOID;CCDC;;;SU)(D;OICI;0xffffffff;;;S-1-5-21-93476-23408-4576)"
+        "S:(AU;OICINPIOIDSAFA;CCDCLCSWRPRC;;;SU)(AU;NPSA;0x12019f;;;SU)", SDDL_REVISION_1, &sec, &dwDescSize), "Creating descriptor failed\n");
+    buf = HeapAlloc(GetProcessHeap(), 0, dwDescSize);
+    pSetSecurityDescriptorControl(sec, SE_DACL_PROTECTED, SE_DACL_PROTECTED);
+    GetSecurityDescriptorControl(sec, &ctrl, &dwRevision);
+    todo_wine expect_eq(ctrl, 0x9014, int, "%x");
+
+    ok(GetPrivateObjectSecurity(sec, GROUP_SECURITY_INFORMATION, buf, dwDescSize, &retSize),
+        "GetPrivateObjectSecurity failed (err=%u)\n", GetLastError());
+    ok(retSize <= dwDescSize, "Buffer too small (%d vs %d)\n", retSize, dwDescSize);
+    ok(pConvertSecurityDescriptorToStringSecurityDescriptorA(buf, SDDL_REVISION_1, sec_info, &string, &len), "Conversion failed\n");
+    CHECK_RESULT_AND_FREE("G:S-1-5-21-93476-23408-4576");
+    GetSecurityDescriptorControl(buf, &ctrl, &dwRevision);
+    expect_eq(ctrl, 0x8000, int, "%x");
+
+    ok(GetPrivateObjectSecurity(sec, GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION, buf, dwDescSize, &retSize),
+        "GetPrivateObjectSecurity failed (err=%u)\n", GetLastError());
+    ok(retSize <= dwDescSize, "Buffer too small (%d vs %d)\n", retSize, dwDescSize);
+    ok(pConvertSecurityDescriptorToStringSecurityDescriptorA(buf, SDDL_REVISION_1, sec_info, &string, &len), "Conversion failed err=%u\n", GetLastError());
+    CHECK_RESULT_AND_FREE("G:S-1-5-21-93476-23408-4576D:(A;NP;GAGXGWGR;;;SU)(A;IOID;CCDC;;;SU)(D;OICI;0xffffffff;;;S-1-5-21-93476-23408-4576)");
+    GetSecurityDescriptorControl(buf, &ctrl, &dwRevision);
+    expect_eq(ctrl, 0x8004, int, "%x");
+
+    ok(GetPrivateObjectSecurity(sec, sec_info, buf, dwDescSize, &retSize),
+        "GetPrivateObjectSecurity failed (err=%u)\n", GetLastError());
+    ok(retSize == dwDescSize, "Buffer too small (%d vs %d)\n", retSize, dwDescSize);
+    ok(pConvertSecurityDescriptorToStringSecurityDescriptorA(buf, SDDL_REVISION_1, sec_info, &string, &len), "Conversion failed\n");
+    CHECK_RESULT_AND_FREE("O:SY"
+        "G:S-1-5-21-93476-23408-4576"
+        "D:(A;NP;GAGXGWGR;;;SU)(A;IOID;CCDC;;;SU)(D;OICI;0xffffffff;;;S-1-5-21-93476-23408-4576)"
+        "S:(AU;OICINPIOIDSAFA;CCDCLCSWRPRC;;;SU)(AU;NPSA;0x12019f;;;SU)");
+    GetSecurityDescriptorControl(buf, &ctrl, &dwRevision);
+    expect_eq(ctrl, 0x8014, int, "%x");
+
+    SetLastError(0xdeadbeef);
+    ok(GetPrivateObjectSecurity(sec, sec_info, buf, 5, &retSize) == FALSE, "GetPrivateObjectSecurity should have failed\n");
+    ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Expected error ERROR_INSUFFICIENT_BUFFER, got %u\n", GetLastError());
+
+    LocalFree(sec);
+    HeapFree(GetProcessHeap(), 0, buf);
+}
+#undef CHECK_RESULT_AND_FREE
+#undef CHECK_ONE_OF_AND_FREE
+
+static void test_acls(void)
+{
+    char buffer[256];
+    PACL pAcl = (PACL)buffer;
+    BOOL ret;
+
+    SetLastError(0xdeadbeef);
+    ret = InitializeAcl(pAcl, sizeof(ACL) - 1, ACL_REVISION);
+    if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
+    {
+        skip("InitializeAcl is not implemented\n");
+        return;
+    }
+
+    ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "InitializeAcl with too small a buffer should have failed with ERROR_INSUFFICIENT_BUFFER instead of %d\n", GetLastError());
+
+    SetLastError(0xdeadbeef);
+    ret = InitializeAcl(pAcl, 0xffffffff, ACL_REVISION);
+    ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "InitializeAcl with too large a buffer should have failed with ERROR_INVALID_PARAMETER instead of %d\n", GetLastError());
+
+    SetLastError(0xdeadbeef);
+    ret = InitializeAcl(pAcl, sizeof(buffer), ACL_REVISION1);
+    ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "InitializeAcl(ACL_REVISION1) should have failed with ERROR_INVALID_PARAMETER instead of %d\n", GetLastError());
+
+    ret = InitializeAcl(pAcl, sizeof(buffer), ACL_REVISION2);
+    ok(ret, "InitializeAcl(ACL_REVISION2) failed with error %d\n", GetLastError());
+
+    ret = IsValidAcl(pAcl);
+    ok(ret, "IsValidAcl failed with error %d\n", GetLastError());
+
+    ret = InitializeAcl(pAcl, sizeof(buffer), ACL_REVISION3);
+    ok(ret, "InitializeAcl(ACL_REVISION3) failed with error %d\n", GetLastError());
+
+    ret = IsValidAcl(pAcl);
+    ok(ret, "IsValidAcl failed with error %d\n", GetLastError());
+
+    ret = InitializeAcl(pAcl, sizeof(buffer), ACL_REVISION4);
+    ok(ret, "InitializeAcl(ACL_REVISION4) failed with error %d\n", GetLastError());
+
+    ret = IsValidAcl(pAcl);
+    ok(ret, "IsValidAcl failed with error %d\n", GetLastError());
+
+    SetLastError(0xdeadbeef);
+    ret = InitializeAcl(pAcl, sizeof(buffer), -1);
+    ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, "InitializeAcl(-1) failed with error %d\n", GetLastError());
 }
 
 START_TEST(security)
 {
     init();
     if (!hmod) return;
+
+    if (myARGC >= 3)
+    {
+        test_process_security_child();
+        return;
+    }
     test_sid();
     test_trustee();
     test_luid();
+    test_CreateWellKnownSid();
     test_FileSecurity();
+    test_AccessCheck();
+    test_token_attr();
+    test_LookupAccountSid();
+    test_LookupAccountName();
+    test_security_descriptor();
+    test_process_security();
+    test_impersonation_level();
+    test_SetEntriesInAcl();
+    test_GetNamedSecurityInfoA();
+    test_ConvertStringSecurityDescriptor();
+    test_ConvertSecurityDescriptorToString();
+    test_PrivateObjectSecurity();
+    test_acls();
 }
diff --git a/rostests/winetests/advapi32/service.c b/rostests/winetests/advapi32/service.c
new file mode 100644 (file)
index 0000000..8ffe2e8
--- /dev/null
@@ -0,0 +1,1256 @@
+/*
+ * Unit tests for service functions
+ *
+ * Copyright (c) 2007 Paul Vriens
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winerror.h"
+#include "winreg.h"
+#include "winsvc.h"
+#include "winnls.h"
+#include "lmcons.h"
+
+#include "wine/test.h"
+
+static const CHAR spooler[] = "Spooler"; /* Should be available on all platforms */
+
+static void test_open_scm(void)
+{
+    SC_HANDLE scm_handle;
+
+    /* No access rights */
+    SetLastError(0xdeadbeef);
+    scm_handle = OpenSCManagerA(NULL, NULL, 0);
+    ok(scm_handle != NULL, "Expected success\n");
+    ok(GetLastError() == ERROR_SUCCESS    /* W2K3, Vista */ ||
+       GetLastError() == 0xdeadbeef       /* NT4, XP */ ||
+       GetLastError() == ERROR_IO_PENDING /* W2K */,
+       "Expected ERROR_SUCCESS, ERROR_IO_PENDING or 0xdeadbeef, got %d\n", GetLastError());
+    CloseServiceHandle(scm_handle);
+
+    /* Unknown database name */
+    SetLastError(0xdeadbeef);
+    scm_handle = OpenSCManagerA(NULL, "DoesNotExist", SC_MANAGER_CONNECT);
+    ok(!scm_handle, "Expected failure\n");
+    ok(GetLastError() == ERROR_INVALID_NAME, "Expected ERROR_INVALID_NAME, got %d\n", GetLastError());
+    CloseServiceHandle(scm_handle); /* Just in case */
+
+    /* MSDN says only ServiceActive is allowed, or NULL */
+    SetLastError(0xdeadbeef);
+    scm_handle = OpenSCManagerA(NULL, SERVICES_FAILED_DATABASEA, SC_MANAGER_CONNECT);
+    ok(!scm_handle, "Expected failure\n");
+    ok(GetLastError() == ERROR_DATABASE_DOES_NOT_EXIST, "Expected ERROR_DATABASE_DOES_NOT_EXIST, got %d\n", GetLastError());
+    CloseServiceHandle(scm_handle); /* Just in case */
+
+    /* Remote unknown host */
+    SetLastError(0xdeadbeef);
+    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());
+    CloseServiceHandle(scm_handle); /* Just in case */
+
+    /* Proper call with an empty hostname */
+    SetLastError(0xdeadbeef);
+    scm_handle = OpenSCManagerA("", SERVICES_ACTIVE_DATABASEA, SC_MANAGER_CONNECT);
+    ok(scm_handle != NULL, "Expected success\n");
+    ok(GetLastError() == ERROR_SUCCESS          /* W2K3, Vista */ ||
+       GetLastError() == ERROR_ENVVAR_NOT_FOUND /* NT4 */ ||
+       GetLastError() == 0xdeadbeef             /* XP */ ||
+       GetLastError() == ERROR_IO_PENDING       /* W2K */,
+       "Expected ERROR_SUCCESS, ERROR_IO_PENDING, ERROR_ENVVAR_NOT_FOUND or 0xdeadbeef, got %d\n", GetLastError());
+    CloseServiceHandle(scm_handle);
+
+    /* Again a correct one */
+    SetLastError(0xdeadbeef);
+    scm_handle = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT);
+    ok(scm_handle != NULL, "Expected success\n");
+    ok(GetLastError() == ERROR_SUCCESS    /* W2K3, Vista */ ||
+       GetLastError() == 0xdeadbeef       /* NT4, XP */ ||
+       GetLastError() == ERROR_IO_PENDING /* W2K */,
+       "Expected ERROR_SUCCESS, ERROR_IO_PENDING or 0xdeadbeef, got %d\n", GetLastError());
+    CloseServiceHandle(scm_handle);
+}
+
+static void test_open_svc(void)
+{
+    SC_HANDLE scm_handle, svc_handle;
+    CHAR displayname[4096];
+    DWORD displaysize;
+
+    /* All NULL (invalid access rights) */
+    SetLastError(0xdeadbeef);
+    svc_handle = OpenServiceA(NULL, NULL, 0);
+    ok(!svc_handle, "Expected failure\n");
+    ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
+
+    /* TODO: Add some tests with invalid handles. These produce errors on Windows but crash on Wine */
+
+    /* NULL service */
+    scm_handle = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT);
+    SetLastError(0xdeadbeef);
+    svc_handle = OpenServiceA(scm_handle, NULL, GENERIC_READ);
+    ok(!svc_handle, "Expected failure\n");
+    ok(GetLastError() == ERROR_INVALID_ADDRESS   /* W2K, XP, W2K3, Vista */ ||
+       GetLastError() == ERROR_INVALID_PARAMETER /* NT4 */,
+       "Expected ERROR_INVALID_ADDRESS or ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
+
+    /* Nonexistent service */
+    scm_handle = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT);
+    SetLastError(0xdeadbeef);
+    svc_handle = OpenServiceA(scm_handle, "deadbeef", 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());
+    CloseServiceHandle(scm_handle);
+
+    /* Proper SCM handle but different access rights */
+    scm_handle = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT);
+    SetLastError(0xdeadbeef);
+    svc_handle = OpenServiceA(scm_handle, "Spooler", GENERIC_WRITE);
+    if (!svc_handle && (GetLastError() == ERROR_ACCESS_DENIED))
+        skip("Not enough rights to get a handle to the service\n");
+    else
+    {
+        ok(svc_handle != NULL, "Expected success\n");
+        ok(GetLastError() == ERROR_SUCCESS    /* W2K3, Vista */ ||
+           GetLastError() == ERROR_IO_PENDING /* W2K */ ||
+           GetLastError() == 0xdeadbeef       /* XP, NT4 */,
+           "Expected ERROR_SUCCESS or 0xdeadbeef, got %d\n", GetLastError());
+        CloseServiceHandle(svc_handle);
+    }
+
+    /* Test to show we can't open a service with the displayname */
+
+    /* Retrieve the needed size for the buffer */
+    displaysize = 0;
+    GetServiceDisplayNameA(scm_handle, spooler, NULL, &displaysize);
+    /* Get the displayname */
+    GetServiceDisplayNameA(scm_handle, spooler, displayname, &displaysize);
+    /* Try to open the service with this displayname */
+    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());
+    /* Just in case */
+    CloseServiceHandle(svc_handle);
+
+    CloseServiceHandle(scm_handle);
+}
+
+static void test_create_delete_svc(void)
+{
+    SC_HANDLE scm_handle, svc_handle1;
+    CHAR username[UNLEN + 1], domain[MAX_PATH];
+    DWORD user_size = UNLEN + 1;
+    CHAR account[UNLEN + 3];
+    static const CHAR servicename         [] = "Winetest";
+    static const CHAR pathname            [] = "we_dont_care.exe";
+    static const CHAR empty               [] = "";
+    static const CHAR password            [] = "secret";
+    BOOL spooler_exists = FALSE;
+    BOOL ret;
+    CHAR display[4096];
+    DWORD display_size = sizeof(display);
+
+    /* Get the username and turn it into an account to be used in some tests */
+    GetUserNameA(username, &user_size);
+    /* Get the domainname to cater for that situation */
+    if (GetEnvironmentVariableA("USERDOMAIN", domain, MAX_PATH))
+        sprintf(account, "%s\\%s", domain, username);
+    else
+        sprintf(account, ".\\%s", username);
+
+    /* All NULL */
+    SetLastError(0xdeadbeef);
+    svc_handle1 = CreateServiceA(NULL, NULL, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL);
+    ok(!svc_handle1, "Expected failure\n");
+    ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
+
+    scm_handle = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT);
+
+    /* Only a valid handle to the Service Control Manager */
+    SetLastError(0xdeadbeef);
+    svc_handle1 = CreateServiceA(scm_handle, NULL, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL);
+    ok(!svc_handle1, "Expected failure\n");
+    ok(GetLastError() == ERROR_INVALID_ADDRESS   /* W2K, W2K3, XP, Vista */ ||
+       GetLastError() == ERROR_INVALID_PARAMETER /* NT4 */,
+       "Expected ERROR_INVALID_ADDRESS or ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
+
+    /* Now with a servicename */
+    SetLastError(0xdeadbeef);
+    svc_handle1 = CreateServiceA(scm_handle, servicename, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL);
+    ok(!svc_handle1, "Expected failure\n");
+    ok(GetLastError() == ERROR_INVALID_ADDRESS   /* W2K, W2K3, XP, Vista */ ||
+       GetLastError() == ERROR_INVALID_PARAMETER /* NT4 */,
+       "Expected ERROR_INVALID_ADDRESS or ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
+
+    /* Or just a binary name */
+    SetLastError(0xdeadbeef);
+    svc_handle1 = CreateServiceA(scm_handle, NULL, NULL, 0, 0, 0, 0, pathname, NULL, NULL, NULL, NULL, NULL);
+    ok(!svc_handle1, "Expected failure\n");
+    ok(GetLastError() == ERROR_INVALID_ADDRESS   /* W2K, W2K3, XP, Vista */ ||
+       GetLastError() == ERROR_INVALID_PARAMETER /* NT4 */,
+       "Expected ERROR_INVALID_ADDRESS or ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
+
+    /* Both servicename and binary name (We only have connect rights) */
+    SetLastError(0xdeadbeef);
+    svc_handle1 = CreateServiceA(scm_handle, servicename, NULL, 0, 0, 0, 0, pathname, NULL, NULL, NULL, NULL, NULL);
+    ok(!svc_handle1, "Expected failure\n");
+    ok(GetLastError() == ERROR_ACCESS_DENIED, "Expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
+
+    /* They can even be empty at this stage of parameter checking */
+    SetLastError(0xdeadbeef);
+    svc_handle1 = CreateServiceA(scm_handle, empty, NULL, 0, 0, 0, 0, pathname, NULL, NULL, NULL, NULL, NULL);
+    ok(!svc_handle1, "Expected failure\n");
+    ok(GetLastError() == ERROR_ACCESS_DENIED, "Expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
+
+    SetLastError(0xdeadbeef);
+    svc_handle1 = CreateServiceA(scm_handle, servicename, NULL, 0, 0, 0, 0, empty, NULL, NULL, NULL, NULL, NULL);
+    ok(!svc_handle1, "Expected failure\n");
+    ok(GetLastError() == ERROR_ACCESS_DENIED, "Expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
+
+    /* Open the Service Control Manager with minimal rights for creation
+     * (Verified with 'SC_MANAGER_ALL_ACCESS &~ SC_MANAGER_CREATE_SERVICE')
+     */
+    CloseServiceHandle(scm_handle);
+    SetLastError(0xdeadbeef);
+    scm_handle = OpenSCManagerA(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
+    if (!scm_handle && (GetLastError() == ERROR_ACCESS_DENIED))
+    {
+        skip("Not enough rights to get a handle to the manager\n");
+        return;
+    }
+
+    /* TODO: It looks like account (ServiceStartName) and (maybe) password are checked at this place */
+
+    /* Empty strings for servicename and binary name are checked */
+    SetLastError(0xdeadbeef);
+    svc_handle1 = CreateServiceA(scm_handle, empty, NULL, 0, 0, 0, 0, pathname, NULL, NULL, NULL, NULL, NULL);
+    ok(!svc_handle1, "Expected failure\n");
+    ok(GetLastError() == ERROR_INVALID_NAME, "Expected ERROR_INVALID_NAME, got %d\n", GetLastError());
+
+    SetLastError(0xdeadbeef);
+    svc_handle1 = CreateServiceA(scm_handle, servicename, NULL, 0, 0, 0, 0, empty, NULL, NULL, NULL, NULL, NULL);
+    ok(!svc_handle1, "Expected failure\n");
+    ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
+
+    SetLastError(0xdeadbeef);
+    svc_handle1 = CreateServiceA(scm_handle, empty, NULL, 0, 0, 0, 0, empty, NULL, NULL, NULL, NULL, NULL);
+    ok(!svc_handle1, "Expected failure\n");
+    ok(GetLastError() == ERROR_INVALID_NAME, "Expected ERROR_INVALID_NAME, got %d\n", GetLastError());
+
+    /* Valid call (as we will see later) except for the empty binary name (to proof it's indeed
+     * an ERROR_INVALID_PARAMETER)
+     */
+    SetLastError(0xdeadbeef);
+    svc_handle1 = CreateServiceA(scm_handle, servicename, NULL, 0, SERVICE_WIN32_OWN_PROCESS,
+                                 SERVICE_DISABLED, 0, empty, NULL, NULL, NULL, NULL, NULL);
+    ok(!svc_handle1, "Expected failure\n");
+    ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
+
+    /* Windows checks if the 'service type', 'access type' and the combination of them are valid, so let's test that */
+
+    /* Illegal (service-type, which is used as a mask can't have a mix. Except the one with
+     * SERVICE_INTERACTIVE_PROCESS which will be tested below in a valid call)
+     */
+    SetLastError(0xdeadbeef);
+    svc_handle1 = CreateServiceA(scm_handle, servicename, NULL, GENERIC_ALL, SERVICE_WIN32_OWN_PROCESS | SERVICE_WIN32_SHARE_PROCESS,
+                                 SERVICE_DISABLED, 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());
+
+    /* Illegal (SERVICE_INTERACTIVE_PROCESS is only allowed with SERVICE_WIN32_OWN_PROCESS or SERVICE_WIN32_SHARE_PROCESS) */
+    SetLastError(0xdeadbeef);
+    svc_handle1 = CreateServiceA(scm_handle, servicename, NULL, GENERIC_ALL, SERVICE_FILE_SYSTEM_DRIVER | SERVICE_INTERACTIVE_PROCESS,
+                                 SERVICE_DISABLED, 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());
+
+    /* Illegal (this combination is only allowed when the LocalSystem account (ServiceStartName) is used)
+     * Not having a correct account would have resulted in an ERROR_INVALID_SERVICE_ACCOUNT.
+     */
+    SetLastError(0xdeadbeef);
+    svc_handle1 = CreateServiceA(scm_handle, servicename, NULL, GENERIC_ALL, SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
+                                 SERVICE_DISABLED, 0, pathname, NULL, NULL, NULL, account, password);
+    ok(!svc_handle1, "Expected failure\n");
+    ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
+
+    /* Illegal (start-type is not a mask and should only be one of the possibilities)
+     * Remark : 'OR'-ing them could result in a valid possibility (but doesn't make sense as
+     * it's most likely not the wanted start-type)
+     */
+    SetLastError(0xdeadbeef);
+    svc_handle1 = CreateServiceA(scm_handle, servicename, NULL, GENERIC_ALL, SERVICE_WIN32_OWN_PROCESS,
+                                 SERVICE_AUTO_START | SERVICE_DISABLED, 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());
+
+    /* Illegal (SERVICE_BOOT_START and SERVICE_SYSTEM_START are only allowed for driver services) */
+    SetLastError(0xdeadbeef);
+    svc_handle1 = CreateServiceA(scm_handle, servicename, NULL, 0, SERVICE_WIN32_OWN_PROCESS,
+                                 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)
+    {
+        spooler_exists = TRUE;
+        CloseServiceHandle(svc_handle1);
+        SetLastError(0xdeadbeef);
+        svc_handle1 = CreateServiceA(scm_handle, spooler, NULL, 0, SERVICE_WIN32_OWN_PROCESS,
+                                     SERVICE_DISABLED, 0, pathname, NULL, NULL, NULL, NULL, NULL);
+        ok(!svc_handle1, "Expected failure\n");
+        ok(GetLastError() == ERROR_SERVICE_EXISTS, "Expected ERROR_SERVICE_EXISTS, got %d\n", GetLastError());
+    }
+    else
+        skip("Spooler service doesn't exist\n");
+
+    /* To find an existing displayname we check the 'Spooler' service. Although the registry
+     * doesn't show DisplayName on NT4, this call will return a displayname which is equal
+     * to the servicename and can't be used as well for a new displayname.
+     */
+    if (spooler_exists)
+    {
+        ret = GetServiceDisplayNameA(scm_handle, spooler, display, &display_size);
+
+        if (!ret)
+            skip("Could not retrieve a displayname for the Spooler service\n");
+        else
+        {
+            svc_handle1 = CreateServiceA(scm_handle, servicename, display, 0, SERVICE_WIN32_OWN_PROCESS,
+                                         SERVICE_DISABLED, 0, pathname, NULL, NULL, NULL, NULL, NULL);
+            ok(!svc_handle1, "Expected failure\n");
+            ok(GetLastError() == ERROR_DUPLICATE_SERVICE_NAME,
+               "Expected ERROR_DUPLICATE_SERVICE_NAME, got %d\n", GetLastError());
+        }
+    }
+    else
+        skip("Could not retrieve a displayname (Spooler service doesn't exist)\n");
+
+    /* Windows doesn't care about the access rights for creation (which makes
+     * sense as there is no service yet) as long as there are sufficient
+     * rights to the manager.
+     */
+    SetLastError(0xdeadbeef);
+    svc_handle1 = CreateServiceA(scm_handle, servicename, NULL, 0, SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
+                                 SERVICE_DISABLED, 0, pathname, NULL, NULL, NULL, NULL, NULL);
+    ok(svc_handle1 != NULL, "Could not create the service : %d\n", GetLastError());
+    ok(GetLastError() == ERROR_SUCCESS    /* W2K3, Vista */ ||
+       GetLastError() == 0xdeadbeef       /* NT4, XP */ ||
+       GetLastError() == ERROR_IO_PENDING /* W2K */,
+       "Expected ERROR_SUCCESS, ERROR_IO_PENDING or 0xdeadbeef, got %d\n", GetLastError());
+
+    /* DeleteService however must have proper rights */
+    SetLastError(0xdeadbeef);
+    ret = DeleteService(svc_handle1);
+    ok(!ret, "Expected failure\n");
+    ok(GetLastError() == ERROR_ACCESS_DENIED,
+       "Expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
+
+    /* Open the service with minimal rights for deletion.
+     * (Verified with 'SERVICE_ALL_ACCESS &~ DELETE')
+     */
+    CloseServiceHandle(svc_handle1);
+    svc_handle1 = OpenServiceA(scm_handle, servicename, DELETE);
+
+    /* Now that we have the proper rights, we should be able to delete */
+    SetLastError(0xdeadbeef);
+    ret = DeleteService(svc_handle1);
+    ok(ret, "Expected success\n");
+    ok(GetLastError() == ERROR_SUCCESS    /* W2K3 */ ||
+       GetLastError() == 0xdeadbeef       /* NT4, XP, Vista */ ||
+       GetLastError() == ERROR_IO_PENDING /* W2K */,
+       "Expected ERROR_SUCCESS, ERROR_IO_PENDING or 0xdeadbeef, got %d\n", GetLastError());
+
+    CloseServiceHandle(svc_handle1);
+
+    CloseServiceHandle(scm_handle);
+
+    /* Wait a while. One of the following tests also does a CreateService for the
+     * same servicename and this would result in an ERROR_SERVICE_MARKED_FOR_DELETE
+     * error if we do this to quick. Vista seems more picky then the others.
+     */
+    Sleep(1000);
+
+    /* And a final NULL check */
+    SetLastError(0xdeadbeef);
+    ret = DeleteService(NULL);
+    ok(!ret, "Expected failure\n");
+    ok(GetLastError() == ERROR_INVALID_HANDLE,
+        "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
+}
+
+static void test_get_displayname(void)
+{
+    SC_HANDLE scm_handle, svc_handle;
+    BOOL ret;
+    CHAR displayname[4096];
+    WCHAR displaynameW[2048];
+    DWORD displaysize, tempsize, tempsizeW;
+    static const CHAR deadbeef[] = "Deadbeef";
+    static const WCHAR spoolerW[] = {'S','p','o','o','l','e','r',0};
+    static const CHAR servicename[] = "Winetest";
+    static const CHAR pathname[] = "we_dont_care.exe";
+
+    /* Having NULL for the size of the buffer will crash on W2K3 */
+
+    SetLastError(0xdeadbeef);
+    ret = GetServiceDisplayNameA(NULL, NULL, NULL, &displaysize);
+    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);
+
+    SetLastError(0xdeadbeef);
+    ret = GetServiceDisplayNameA(scm_handle, NULL, NULL, &displaysize);
+    ok(!ret, "Expected failure\n");
+    ok(GetLastError() == ERROR_INVALID_ADDRESS   /* W2K, XP, W2K3, Vista */ ||
+       GetLastError() == ERROR_INVALID_PARAMETER /* NT4 */,
+       "Expected ERROR_INVALID_ADDRESS or ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
+
+    SetLastError(0xdeadbeef);
+    displaysize = sizeof(displayname);
+    ret = GetServiceDisplayNameA(scm_handle, NULL, displayname, &displaysize);
+    ok(!ret, "Expected failure\n");
+    ok(GetLastError() == ERROR_INVALID_ADDRESS   /* W2K, XP, W2K3, Vista */ ||
+       GetLastError() == ERROR_INVALID_PARAMETER /* NT4 */,
+       "Expected ERROR_INVALID_ADDRESS or ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
+
+    /* Test for nonexistent service */
+    SetLastError(0xdeadbeef);
+    displaysize = -1;
+    ret = GetServiceDisplayNameA(scm_handle, deadbeef, NULL, &displaysize);
+    ok(!ret, "Expected failure\n");
+    ok(GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST,
+       "Expected ERROR_SERVICE_DOES_NOT_EXIST, got %d\n", GetLastError());
+
+    /* Check if 'Spooler' exists */
+    svc_handle = OpenServiceA(scm_handle, spooler, GENERIC_READ);
+    if (!svc_handle)
+    {
+        skip("Spooler service doesn't exist\n");
+        CloseServiceHandle(scm_handle);
+        return;
+    }
+    CloseServiceHandle(svc_handle);
+
+    /* Retrieve the needed size for the buffer */
+    SetLastError(0xdeadbeef);
+    displaysize = -1;
+    ret = GetServiceDisplayNameA(scm_handle, spooler, NULL, &displaysize);
+    ok(!ret, "Expected failure\n");
+    ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
+       "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
+    tempsize = displaysize;
+
+    displaysize = 0;
+    ret = GetServiceDisplayNameA(scm_handle, spooler, NULL, &displaysize);
+    ok(!ret, "Expected failure\n");
+    ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
+       "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
+    ok(displaysize == tempsize, "Buffer size mismatch (%d vs %d)\n", tempsize, displaysize);
+
+    /* Buffer is too small */
+    SetLastError(0xdeadbeef);
+    displaysize = (tempsize / 2);
+    ret = GetServiceDisplayNameA(scm_handle, spooler, displayname, &displaysize);
+    ok(!ret, "Expected failure\n");
+    ok(displaysize == tempsize, "Expected the needed buffersize\n");
+    ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
+       "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
+
+    /* First try with a buffer that should be big enough to hold
+     * the ANSI string (and terminating character). This succeeds on Windows
+     *  although when asked (see above 2 tests) it will return twice the needed size.
+     */
+    SetLastError(0xdeadbeef);
+    displaysize = (tempsize / 2) + 1;
+    ret = GetServiceDisplayNameA(scm_handle, spooler, displayname, &displaysize);
+    ok(ret, "Expected success\n");
+    ok(displaysize == ((tempsize / 2) + 1), "Expected no change for the needed buffer size\n");
+    ok(GetLastError() == ERROR_SUCCESS    /* W2K3 */ ||
+       GetLastError() == ERROR_IO_PENDING /* W2K */ ||
+       GetLastError() == 0xdeadbeef       /* NT4, XP, Vista */,
+       "Expected ERROR_SUCCESS, ERROR_IO_PENDING or 0xdeadbeef, got %d\n", GetLastError());
+
+    /* Now with the original returned size */
+    SetLastError(0xdeadbeef);
+    displaysize = tempsize;
+    ret = GetServiceDisplayNameA(scm_handle, spooler, displayname, &displaysize);
+    ok(ret, "Expected success\n");
+    ok(displaysize == tempsize, "Expected no change for the needed buffer size\n");
+    ok(GetLastError() == ERROR_SUCCESS    /* W2K3 */ ||
+       GetLastError() == ERROR_IO_PENDING /* W2K */ ||
+       GetLastError() == 0xdeadbeef       /* NT4, XP, Vista */,
+       "Expected ERROR_SUCCESS, ERROR_IO_PENDING or 0xdeadbeef, got %d\n", GetLastError());
+
+    /* And with a bigger than needed buffer */
+    SetLastError(0xdeadbeef);
+    displaysize = tempsize * 2;
+    ret = GetServiceDisplayNameA(scm_handle, spooler, displayname, &displaysize);
+    ok(ret, "Expected success\n");
+    ok(GetLastError() == ERROR_SUCCESS    /* W2K3 */ ||
+       GetLastError() == ERROR_IO_PENDING /* W2K */ ||
+       GetLastError() == 0xdeadbeef       /* NT4, XP, Vista */,
+       "Expected ERROR_SUCCESS, ERROR_IO_PENDING or 0xdeadbeef, got %d\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,
+       "Expected the buffer to be twice the length of the string\n") ;
+
+    /* Do the buffer(size) tests also for GetServiceDisplayNameW */
+    SetLastError(0xdeadbeef);
+    displaysize = -1;
+    ret = GetServiceDisplayNameW(scm_handle, spoolerW, NULL, &displaysize);
+    ok(!ret, "Expected failure\n");
+    ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
+       "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
+
+    /* Buffer is too small */
+    SetLastError(0xdeadbeef);
+    tempsizeW = displaysize;
+    displaysize = tempsizeW / 2;
+    ret = GetServiceDisplayNameW(scm_handle, spoolerW, displaynameW, &displaysize);
+    ok(!ret, "Expected failure\n");
+    ok(displaysize = tempsizeW, "Expected the needed buffersize\n");
+    ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
+       "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
+
+    /* Now with the original returned size */
+    SetLastError(0xdeadbeef);
+    displaysize = tempsizeW;
+    ret = GetServiceDisplayNameW(scm_handle, spoolerW, displaynameW, &displaysize);
+    ok(!ret, "Expected failure\n");
+    ok(displaysize = tempsizeW, "Expected the needed buffersize\n");
+    ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
+       "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
+
+    /* And with a bigger than needed buffer */
+    SetLastError(0xdeadbeef);
+    displaysize = tempsizeW + 1; /* This caters for the null terminating character */
+    ret = GetServiceDisplayNameW(scm_handle, spoolerW, displaynameW, &displaysize);
+    ok(ret, "Expected success\n");
+    ok(GetLastError() == ERROR_SUCCESS    /* W2K3 */ ||
+       GetLastError() == ERROR_IO_PENDING /* W2K */ ||
+       GetLastError() == 0xdeadbeef       /* NT4, XP, Vista */,
+       "Expected ERROR_SUCCESS, ERROR_IO_PENDING or 0xdeadbeef, got %d\n", GetLastError());
+    ok(displaysize == tempsizeW, "Expected the needed buffersize\n");
+    ok(lstrlenW(displaynameW) == displaysize,
+       "Expected the buffer to be the length of the string\n") ;
+    ok(tempsize / 2 == tempsizeW,
+       "Expected the needed buffersize (in bytes) to be the same for the A and W call\n");
+
+    CloseServiceHandle(scm_handle);
+
+    /* Test for a service without a displayname (which is valid). This should return
+     * the servicename itself.
+     */
+    SetLastError(0xdeadbeef);
+    scm_handle = OpenSCManagerA(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
+    if (!scm_handle && (GetLastError() == ERROR_ACCESS_DENIED))
+    {
+        skip("Not enough rights to get a handle to the manager\n");
+        return;
+    }
+
+    SetLastError(0xdeadbeef);
+    svc_handle = CreateServiceA(scm_handle, servicename, NULL, DELETE,
+                                SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
+                                SERVICE_DISABLED, 0, pathname, NULL, NULL, NULL, NULL, NULL);
+    ok(svc_handle != NULL, "Could not create the service : %d\n", GetLastError());
+    if (!svc_handle)
+    {
+        CloseServiceHandle(scm_handle);
+        return;
+    }
+
+    /* Retrieve the needed size for the buffer */
+    SetLastError(0xdeadbeef);
+    displaysize = -1;
+    ret = GetServiceDisplayNameA(scm_handle, servicename, NULL, &displaysize);
+    ok(!ret, "Expected failure\n");
+    ok(displaysize == lstrlen(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());
+
+    /* Buffer is too small */
+    SetLastError(0xdeadbeef);
+    tempsize = displaysize;
+    displaysize = (tempsize / 2);
+    ret = GetServiceDisplayNameA(scm_handle, servicename, displayname, &displaysize);
+    ok(!ret, "Expected failure\n");
+    ok(displaysize == tempsize, "Expected the needed buffersize\n");
+    ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
+       "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
+
+    /* Get the displayname */
+    SetLastError(0xdeadbeef);
+    ret = GetServiceDisplayNameA(scm_handle, servicename, displayname, &displaysize);
+    ok(ret, "Expected success\n");
+    ok(!lstrcmpi(displayname, servicename),
+       "Expected displayname to be %s, got %s\n", servicename, displayname);
+    ok(GetLastError() == ERROR_SUCCESS    /* W2K3 */ ||
+       GetLastError() == ERROR_IO_PENDING /* W2K */ ||
+       GetLastError() == 0xdeadbeef       /* NT4, XP, Vista */,
+       "Expected ERROR_SUCCESS, ERROR_IO_PENDING or 0xdeadbeef, got %d\n", GetLastError());
+
+    /* Delete the service */
+    ret = DeleteService(svc_handle);
+    ok(ret, "Expected success\n");
+
+    CloseServiceHandle(svc_handle);
+    CloseServiceHandle(scm_handle);
+
+    /* Wait a while. Just in case one of the following tests does a CreateService again */
+    Sleep(1000);
+}
+
+static void test_get_servicekeyname(void)
+{
+    SC_HANDLE scm_handle, svc_handle;
+    CHAR servicename[4096];
+    CHAR displayname[4096];
+    WCHAR servicenameW[4096];
+    WCHAR displaynameW[4096];
+    DWORD servicesize, displaysize, tempsize;
+    BOOL ret;
+    static const CHAR deadbeef[] = "Deadbeef";
+    static const WCHAR deadbeefW[] = {'D','e','a','d','b','e','e','f',0};
+
+    /* Having NULL for the size of the buffer will crash on W2K3 */
+
+    SetLastError(0xdeadbeef);
+    ret = GetServiceKeyNameA(NULL, NULL, NULL, &servicesize);
+    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);
+
+    servicesize = 200;
+    SetLastError(0xdeadbeef);
+    ret = GetServiceKeyNameA(scm_handle, NULL, NULL, &servicesize);
+    ok(!ret, "Expected failure\n");
+    ok(GetLastError() == ERROR_INVALID_ADDRESS   /* W2K, XP, W2K3, Vista */ ||
+       GetLastError() == ERROR_INVALID_PARAMETER /* NT4 */,
+       "Expected ERROR_INVALID_ADDRESS or ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
+    todo_wine ok(servicesize == 1, "Service size expected 1, got %d\n", servicesize);
+
+    /* Valid handle and buffer but no displayname */
+    servicesize = 200;
+    SetLastError(0xdeadbeef);
+    ret = GetServiceKeyNameA(scm_handle, NULL, servicename, &servicesize);
+    ok(!ret, "Expected failure\n");
+    ok(GetLastError() == ERROR_INVALID_ADDRESS   /* W2K, XP, W2K3, Vista */ ||
+       GetLastError() == ERROR_INVALID_PARAMETER /* NT4 */,
+       "Expected ERROR_INVALID_ADDRESS or ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
+    todo_wine ok(servicesize == 200, "Service size expected 1, got %d\n", servicesize);
+
+    /* Test for nonexistent displayname */
+    SetLastError(0xdeadbeef);
+    ret = GetServiceKeyNameA(scm_handle, deadbeef, NULL, &servicesize);
+    ok(!ret, "Expected failure\n");
+    ok(GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST,
+       "Expected ERROR_SERVICE_DOES_NOT_EXIST, got %d\n", GetLastError());
+    todo_wine ok(servicesize == 1, "Service size expected 1, got %d\n", servicesize);
+
+    servicesize = 15;
+    strcpy(servicename, "ABC");
+    ret = GetServiceKeyNameA(scm_handle, deadbeef, servicename, &servicesize);
+    ok(!ret, "Expected failure\n");
+    todo_wine ok(servicesize == 15, "Service size expected 15, got %d\n", servicesize);
+    ok(servicename[0] == 0, "Service name not empty\n");
+
+    servicesize = 15;
+    servicenameW[0] = 'A';
+    ret = GetServiceKeyNameW(scm_handle, deadbeefW, servicenameW, &servicesize);
+    ok(!ret, "Expected failure\n");
+    todo_wine ok(servicesize == 15, "Service size expected 15, got %d\n", servicesize);
+    ok(servicenameW[0] == 0, "Service name not empty\n");
+
+    servicesize = 0;
+    strcpy(servicename, "ABC");
+    ret = GetServiceKeyNameA(scm_handle, deadbeef, servicename, &servicesize);
+    ok(!ret, "Expected failure\n");
+    todo_wine ok(servicesize == 1, "Service size expected 1, got %d\n", servicesize);
+    ok(servicename[0] == 'A', "Service name changed\n");
+
+    servicesize = 0;
+    servicenameW[0] = 'A';
+    ret = GetServiceKeyNameW(scm_handle, deadbeefW, servicenameW, &servicesize);
+    ok(!ret, "Expected failure\n");
+    todo_wine ok(servicesize == 2, "Service size expected 2, got %d\n", servicesize);
+    ok(servicenameW[0] == 'A', "Service name changed\n");
+
+    /* Check if 'Spooler' exists */
+    svc_handle = OpenServiceA(scm_handle, spooler, GENERIC_READ);
+    if (!svc_handle)
+    {
+        skip("Spooler service doesn't exist\n");
+        CloseServiceHandle(scm_handle);
+        return;
+    }
+    CloseServiceHandle(svc_handle);
+
+    /* Get the displayname for the 'Spooler' service */
+    GetServiceDisplayNameA(scm_handle, spooler, NULL, &displaysize);
+    GetServiceDisplayNameA(scm_handle, spooler, displayname, &displaysize);
+
+    /* Retrieve the needed size for the buffer */
+    SetLastError(0xdeadbeef);
+    servicesize = 0;
+    ret = GetServiceKeyNameA(scm_handle, displayname, NULL, &servicesize);
+    ok(!ret, "Expected failure\n");
+    ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
+       "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
+
+    /* Valid call with the correct buffersize */
+    SetLastError(0xdeadbeef);
+    tempsize = servicesize;
+    servicesize *= 2;
+    ret = GetServiceKeyNameA(scm_handle, displayname, servicename, &servicesize);
+    ok(ret, "Expected success\n");
+    ok(GetLastError() == ERROR_SUCCESS    /* W2K3 */ ||
+       GetLastError() == ERROR_IO_PENDING /* W2K */ ||
+       GetLastError() == 0xdeadbeef       /* NT4, XP, Vista */,
+       "Expected ERROR_SUCCESS, ERROR_IO_PENDING or 0xdeadbeef, got %d\n", GetLastError());
+    if (ret)
+    {
+        ok(lstrlen(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),
+           "Expected servicesize not to change if buffer not insufficient\n") ;
+    }
+
+    MultiByteToWideChar(CP_ACP, 0, displayname, -1, displaynameW, sizeof(displaynameW)/2);
+    SetLastError(0xdeadbeef);
+    servicesize *= 2;
+    ret = GetServiceKeyNameW(scm_handle, displaynameW, servicenameW, &servicesize);
+    ok(ret, "Expected success\n");
+    ok(GetLastError() == ERROR_SUCCESS    /* W2K3 */ ||
+       GetLastError() == ERROR_IO_PENDING /* W2K */ ||
+       GetLastError() == 0xdeadbeef       /* NT4, XP, Vista */,
+       "Expected ERROR_SUCCESS, ERROR_IO_PENDING or 0xdeadbeef, got %d\n", GetLastError());
+    if (ret)
+    {
+        ok(lstrlen(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") ;
+    }
+
+    SetLastError(0xdeadbeef);
+    servicesize = 3;
+    ret = GetServiceKeyNameW(scm_handle, displaynameW, servicenameW, &servicesize);
+    ok(!ret, "Expected failure\n");
+    ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER,
+       "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
+    ok(servicenameW[0] == 0, "Buffer not empty\n");
+
+    CloseServiceHandle(scm_handle);
+}
+
+static void test_close(void)
+{
+    SC_HANDLE handle;
+    BOOL ret;
+
+    /* NULL handle */
+    SetLastError(0xdeadbeef);
+    ret = CloseServiceHandle(NULL);
+    ok(!ret, "Expected failure\n");
+    ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
+
+    /* TODO: Add some tests with invalid handles. These produce errors on Windows but crash on Wine */
+
+    /* Proper call */
+    handle = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT);
+    SetLastError(0xdeadbeef);
+    ret = CloseServiceHandle(handle);
+    ok(ret, "Expected success\n");
+    ok(GetLastError() == ERROR_IO_PENDING /* W2K */ ||
+       GetLastError() == ERROR_SUCCESS    /* W2K3 */ ||
+       GetLastError() == 0xdeadbeef       /* NT4, XP, Vista */,
+       "Expected ERROR_SUCCESS, ERROR_IO_PENDING or 0xdeadbeef, got %d\n", GetLastError());
+}
+
+static void test_sequence(void)
+{
+    SC_HANDLE scm_handle, svc_handle;
+    BOOL ret;
+    QUERY_SERVICE_CONFIGA *config;
+    DWORD given, needed;
+    static const CHAR servicename [] = "Winetest";
+    static const CHAR displayname [] = "Winetest dummy service";
+    static const CHAR displayname2[] = "Winetest dummy service (2)";
+    static const CHAR pathname    [] = "we_dont_care.exe";
+    static const CHAR dependencies[] = "Master1\0Master2\0+MasterGroup1\0";
+    static const CHAR password    [] = "";
+    static const CHAR empty       [] = "";
+    static const CHAR localsystem [] = "LocalSystem";
+
+    SetLastError(0xdeadbeef);
+    scm_handle = OpenSCManagerA(NULL, NULL, GENERIC_ALL);
+
+    if (!scm_handle && (GetLastError() == ERROR_ACCESS_DENIED))
+    {
+        skip("Not enough rights to get a handle to the manager\n");
+        return;
+    }
+    else
+        ok(scm_handle != NULL, "Could not get a handle to the manager: %d\n", GetLastError());
+
+    if (!scm_handle) return;
+
+    /* Create a dummy service */
+    SetLastError(0xdeadbeef);
+    svc_handle = CreateServiceA(scm_handle, servicename, displayname, GENERIC_ALL,
+        SERVICE_INTERACTIVE_PROCESS | SERVICE_WIN32_OWN_PROCESS, SERVICE_DISABLED, SERVICE_ERROR_IGNORE,
+        pathname, NULL, NULL, dependencies, NULL, password);
+
+    if (!svc_handle && (GetLastError() == ERROR_SERVICE_EXISTS))
+    {
+        /* We try and open the service and do the rest of the tests. Some could
+         * fail if the tests were changed between these runs.
+         */
+        trace("Deletion probably didn't work last time\n");
+        SetLastError(0xdeadbeef);
+        svc_handle = OpenServiceA(scm_handle, servicename, GENERIC_ALL);
+        if (!svc_handle && (GetLastError() == ERROR_ACCESS_DENIED))
+        {
+            skip("Not enough rights to open the service\n");
+            CloseServiceHandle(scm_handle);        
+            return;
+        }
+        ok(svc_handle != NULL, "Could not open the service : %d\n", GetLastError());
+    }
+    else if (!svc_handle && (GetLastError() == ERROR_ACCESS_DENIED))
+    {
+        skip("Not enough rights to create the service\n");
+        CloseServiceHandle(scm_handle);        
+        return;
+    }
+    else
+        ok(svc_handle != NULL, "Could not create the service : %d\n", GetLastError());
+
+    if (!svc_handle) return;
+
+    /* TODO:
+     * Before we do a QueryServiceConfig we should check the registry. This will make sure
+     * that the correct keys are used.
+     */
+
+    /* Request the size for the buffer */
+    SetLastError(0xdeadbeef);
+    ret = QueryServiceConfigA(svc_handle, NULL, 0, &needed);
+    ok(!ret, "Expected failure\n");
+    ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Expected ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
+
+    config = HeapAlloc(GetProcessHeap(), 0, needed);
+    given = needed;
+    SetLastError(0xdeadbeef);
+    ret = QueryServiceConfigA(svc_handle, config, given, &needed);
+    ok(ret, "Expected success\n");
+    ok(GetLastError() == ERROR_SUCCESS    /* W2K3 */||
+       GetLastError() == 0xdeadbeef       /* NT4, XP, Vista */ ||
+       GetLastError() == ERROR_IO_PENDING /* W2K */,
+        "Expected ERROR_SUCCESS, ERROR_IO_PENDING or 0xdeadbeef, got %d\n", GetLastError());
+    todo_wine
+    {
+    ok(given == needed, "Expected the given (%d) and needed (%d) buffersizes to be equal\n", given, needed);
+    }
+    ok(config->lpBinaryPathName && config->lpLoadOrderGroup && config->lpDependencies && config->lpServiceStartName &&
+        config->lpDisplayName, "Expected all string struct members to be non-NULL\n");
+    ok(config->dwServiceType == (SERVICE_INTERACTIVE_PROCESS | SERVICE_WIN32_OWN_PROCESS),
+        "Expected SERVICE_INTERACTIVE_PROCESS | SERVICE_WIN32_OWN_PROCESS, got %d\n", config->dwServiceType);
+    ok(config->dwStartType == SERVICE_DISABLED, "Expected SERVICE_DISABLED, got %d\n", config->dwStartType);
+    ok(config->dwErrorControl == SERVICE_ERROR_IGNORE, "Expected SERVICE_ERROR_IGNORE, got %d\n", config->dwErrorControl);
+    ok(!strcmp(config->lpBinaryPathName, pathname), "Expected '%s', got '%s'\n", pathname, config->lpBinaryPathName);
+    ok(!strcmp(config->lpLoadOrderGroup, empty), "Expected an empty string, got '%s'\n", config->lpLoadOrderGroup);
+    ok(config->dwTagId == 0, "Expected 0, got %d\n", config->dwTagId);
+    /* TODO: Show the double 0 terminated string */
+    todo_wine
+    {
+    ok(!memcmp(config->lpDependencies, dependencies, sizeof(dependencies)), "Wrong string\n");
+    }
+    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());
+
+    QueryServiceConfigA(svc_handle, NULL, 0, &needed);
+    config = HeapReAlloc(GetProcessHeap(), 0, config, needed);
+    ok(QueryServiceConfigA(svc_handle, config, needed, &needed), "QueryServiceConfig failed\n");
+    ok(config->lpBinaryPathName && config->lpLoadOrderGroup && config->lpDependencies && config->lpServiceStartName &&
+        config->lpDisplayName, "Expected all string struct members to be non-NULL\n");
+    ok(config->dwServiceType == (SERVICE_INTERACTIVE_PROCESS | SERVICE_WIN32_OWN_PROCESS),
+        "Expected SERVICE_INTERACTIVE_PROCESS | SERVICE_WIN32_OWN_PROCESS, got %d\n", config->dwServiceType);
+    ok(config->dwStartType == SERVICE_DISABLED, "Expected SERVICE_DISABLED, got %d\n", config->dwStartType);
+    ok(config->dwErrorControl == SERVICE_ERROR_NORMAL, "Expected SERVICE_ERROR_NORMAL, got %d\n", config->dwErrorControl);
+    ok(!strcmp(config->lpBinaryPathName, pathname), "Expected '%s', got '%s'\n", pathname, config->lpBinaryPathName);
+    ok(!strcmp(config->lpLoadOrderGroup, "TestGroup2"), "Expected 'TestGroup2', got '%s'\n", config->lpLoadOrderGroup);
+    ok(config->dwTagId == 0, "Expected 0, got %d\n", config->dwTagId);
+    ok(!strcmp(config->lpServiceStartName, localsystem), "Expected 'LocalSystem', got '%s'\n", config->lpServiceStartName);
+    ok(!strcmp(config->lpDisplayName, displayname2), "Expected '%s', got '%s'\n", displayname2, config->lpDisplayName);
+
+    SetLastError(0xdeadbeef);
+    ret = DeleteService(svc_handle);
+    ok(ret, "Expected success\n");
+    ok(GetLastError() == ERROR_SUCCESS    /* W2K3 */||
+       GetLastError() == 0xdeadbeef       /* NT4, XP, Vista */ ||
+       GetLastError() == ERROR_IO_PENDING /* W2K */,
+        "Expected ERROR_SUCCESS, ERROR_IO_PENDING or 0xdeadbeef, got %d\n", GetLastError());
+    
+    CloseServiceHandle(svc_handle);
+
+    /* Wait a while. The following test does a CreateService again */
+    Sleep(1000);
+
+    CloseServiceHandle(scm_handle);
+    HeapFree(GetProcessHeap(), 0, config);
+}
+
+static void test_queryconfig2(void)
+{
+    SC_HANDLE scm_handle, svc_handle;
+    BOOL ret;
+    DWORD expected, needed;
+    BYTE buffer[MAX_PATH];
+    LPSERVICE_DESCRIPTIONA pConfig = (LPSERVICE_DESCRIPTIONA)buffer;
+    static const CHAR servicename [] = "Winetest";
+    static const CHAR displayname [] = "Winetest dummy service";
+    static const CHAR pathname    [] = "we_dont_care.exe";
+    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");
+        return;
+    }
+
+    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;
+    }
+
+    /* Create a dummy service */
+    SetLastError(0xdeadbeef);
+    svc_handle = CreateServiceA(scm_handle, servicename, displayname, GENERIC_ALL,
+        SERVICE_INTERACTIVE_PROCESS | SERVICE_WIN32_OWN_PROCESS, SERVICE_DISABLED, SERVICE_ERROR_IGNORE,
+        pathname, NULL, NULL, dependencies, NULL, password);
+
+    if (!svc_handle)
+    {
+        if(GetLastError() == ERROR_SERVICE_EXISTS)
+        {
+            /* We try and open the service and do the rest of the tests. Some could
+             * fail if the tests were changed between these runs.
+             */
+            trace("Deletion probably didn't work last time\n");
+            SetLastError(0xdeadbeef);
+            svc_handle = OpenServiceA(scm_handle, servicename, GENERIC_ALL);
+            if (!svc_handle)
+            {
+                if(GetLastError() == ERROR_ACCESS_DENIED)
+                    skip("Not enough rights to open the service\n");
+                else
+                    ok(FALSE, "Could not open the service : %d\n", GetLastError());
+                CloseServiceHandle(scm_handle);
+                return;
+            }
+        }
+        if (GetLastError() == ERROR_ACCESS_DENIED)
+        {
+            skip("Not enough rights to create the service\n");
+            CloseServiceHandle(scm_handle);
+            return;
+        }
+        ok(svc_handle != NULL, "Could not create the service : %d\n", GetLastError());
+       if (!svc_handle)
+        {
+            CloseServiceHandle(scm_handle);
+            return;
+        }
+    }
+    SetLastError(0xdeadbeef);
+    ret = pQueryServiceConfig2A(svc_handle,0xfff0,buffer,sizeof(SERVICE_DESCRIPTIONA),&needed);
+    ok(!ret, "expected QueryServiceConfig2A to fail\n");
+    ok(ERROR_INVALID_LEVEL == GetLastError(), "expected error ERROR_INVALID_LEVEL, got %d\n", GetLastError());
+
+    SetLastError(0xdeadbeef);
+    ret = pQueryServiceConfig2A(svc_handle,0xfff0,buffer,sizeof(SERVICE_DESCRIPTIONA),NULL);
+    ok(!ret, "expected QueryServiceConfig2A to fail\n");
+    ok(ERROR_INVALID_LEVEL == GetLastError(), "expected error ERROR_INVALID_LEVEL, got %d\n", GetLastError());
+
+    SetLastError(0xdeadbeef);
+    ret = pQueryServiceConfig2A(svc_handle, SERVICE_CONFIG_DESCRIPTION,buffer,sizeof(SERVICE_DESCRIPTIONA),NULL);
+    ok(!ret, "expected QueryServiceConfig2A to fail\n");
+    ok(ERROR_INVALID_ADDRESS == GetLastError(), "expected error ERROR_INVALID_ADDRESS, got %d\n", GetLastError());
+
+    SetLastError(0xdeadbeef);
+    ret = pQueryServiceConfig2A(svc_handle, SERVICE_CONFIG_DESCRIPTION,NULL,sizeof(SERVICE_DESCRIPTIONA),&needed);
+    ok(!ret, "expected QueryServiceConfig2A to fail\n");
+    ok((ERROR_INVALID_ADDRESS == GetLastError()) || (ERROR_INSUFFICIENT_BUFFER == GetLastError()),
+       "expected error ERROR_INVALID_ADDRESS or ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
+
+    SetLastError(0xdeadbeef);
+    ret = pQueryServiceConfig2A(svc_handle, SERVICE_CONFIG_DESCRIPTION,NULL,sizeof(SERVICE_DESCRIPTIONA),NULL);
+    ok(!ret, "expected QueryServiceConfig2A to fail\n");
+    ok(ERROR_INVALID_ADDRESS == GetLastError(), "expected error ERROR_INVALID_ADDRESS, got %d\n", GetLastError());
+
+    needed = 0;
+    SetLastError(0xdeadbeef);
+    ret = pQueryServiceConfig2A(svc_handle, SERVICE_CONFIG_DESCRIPTION,buffer,sizeof(SERVICE_DESCRIPTIONA)-1,&needed);
+    ok(!ret, "expected QueryServiceConfig2A to fail\n");
+    ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(), "expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
+    ok(needed == sizeof(SERVICE_DESCRIPTIONA), "got %d\n", needed);
+
+    needed = 0;
+    pConfig->lpDescription = (LPSTR)0xdeadbeef;
+    ret = pQueryServiceConfig2A(svc_handle, SERVICE_CONFIG_DESCRIPTION,buffer,sizeof(SERVICE_DESCRIPTIONA),&needed);
+    ok(ret, "expected QueryServiceConfig2A to succeed\n");
+    ok(needed == sizeof(SERVICE_DESCRIPTIONA), "got %d\n", needed);
+    ok(!pConfig->lpDescription, "expected lpDescription to be NULL, got %p\n", pConfig->lpDescription);
+
+    SetLastError(0xdeadbeef);
+    needed = 0;
+    ret = pQueryServiceConfig2A(svc_handle, SERVICE_CONFIG_DESCRIPTION,NULL,0,&needed);
+    ok(!ret, "expected QueryServiceConfig2A to fail\n");
+    ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(), "expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
+    ok(needed == sizeof(SERVICE_DESCRIPTIONA), "got %d\n", needed);
+
+    if(!pChangeServiceConfig2A)
+    {
+        skip("function ChangeServiceConfig2A not present\n");
+        goto cleanup;
+    }
+
+    pConfig->lpDescription = (LPSTR) description;
+    ret = pChangeServiceConfig2A(svc_handle, SERVICE_CONFIG_DESCRIPTION,buffer);
+    ok(ret, "ChangeServiceConfig2A failed\n");
+    if (!ret) {
+        goto cleanup;
+    }
+
+    SetLastError(0xdeadbeef);
+    needed = 0;
+    expected = sizeof(SERVICE_DESCRIPTIONA) + sizeof(description) * sizeof(WCHAR); /* !! */
+    ret = pQueryServiceConfig2A(svc_handle, SERVICE_CONFIG_DESCRIPTION,buffer,sizeof(SERVICE_DESCRIPTIONA),&needed);
+    ok(!ret, "expected QueryServiceConfig2A to fail\n");
+    ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(), "expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
+    ok(needed == expected, "expected needed to be %d, got %d\n", expected, needed);
+
+    SetLastError(0xdeadbeef);
+    ret = pQueryServiceConfig2A(svc_handle, SERVICE_CONFIG_DESCRIPTION,buffer,needed-1,&needed);
+    ok(!ret, "expected QueryServiceConfig2A to fail\n");
+    ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(), "expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
+
+    SetLastError(0xdeadbeef);
+    ret = pQueryServiceConfig2A(svc_handle, SERVICE_CONFIG_DESCRIPTION,buffer,needed,&needed);
+    ok(ret, "expected QueryServiceConfig2A to succeed\n");
+    ok(pConfig->lpDescription && !strcmp(description,pConfig->lpDescription),
+        "expected lpDescription to be %s, got %s\n",description ,pConfig->lpDescription);
+
+    SetLastError(0xdeadbeef);
+    ret = pQueryServiceConfig2A(svc_handle, SERVICE_CONFIG_DESCRIPTION,buffer, needed + 1,&needed);
+    ok(ret, "expected QueryServiceConfig2A to succeed\n");
+    ok(pConfig->lpDescription && !strcmp(description,pConfig->lpDescription),
+        "expected lpDescription to be %s, got %s\n",description ,pConfig->lpDescription);
+
+    if(!pQueryServiceConfig2W)
+    {
+        skip("function QueryServiceConfig2W not present\n");
+        goto cleanup;
+    }
+    SetLastError(0xdeadbeef);
+    needed = 0;
+    expected = sizeof(SERVICE_DESCRIPTIONW) + sizeof(WCHAR) * sizeof(description);
+    ret = pQueryServiceConfig2W(svc_handle, SERVICE_CONFIG_DESCRIPTION,NULL,0,&needed);
+    ok(!ret, "expected QueryServiceConfig2W to fail\n");
+    ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(), "expected error ERROR_INSUFFICIENT_BUFFER, got %d\n", GetLastError());
+    ok(needed == expected, "expected needed to be %d, got %d\n", expected, needed);
+
+    SetLastError(0xdeadbeef);
+    ret = pQueryServiceConfig2W(svc_handle, SERVICE_CONFIG_DESCRIPTION,buffer, needed,&needed);
+    ok(ret, "expected QueryServiceConfig2W to succeed\n");
+
+cleanup:
+    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;
+    static const CHAR servicename         [] = "Winetest";
+    static const CHAR pathname            [] = "we_dont_care.exe";
+    BOOL ret;
+
+    /* Get a handle to the Service Control Manager */
+    SetLastError(0xdeadbeef);
+    scm_handle = OpenSCManagerA(NULL, NULL, GENERIC_ALL);
+    if (!scm_handle && (GetLastError() == ERROR_ACCESS_DENIED))
+    {
+        skip("Not enough rights to get a handle to the manager\n");
+        return;
+    }
+
+    /* Create a service */
+    svc_handle1 = CreateServiceA(scm_handle, servicename, NULL, GENERIC_ALL,
+                                 SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
+                                 SERVICE_DISABLED, 0, pathname, NULL, NULL, NULL, NULL, NULL);
+    ok(svc_handle1 != NULL, "Expected success\n");
+
+    /* Get a handle to this new service */
+    svc_handle2 = OpenServiceA(scm_handle, servicename, GENERIC_READ);
+    ok(svc_handle2 != NULL, "Expected success\n");
+
+    /* Get another handle to this new service */
+    svc_handle3 = OpenServiceA(scm_handle, servicename, GENERIC_READ);
+    ok(svc_handle3 != NULL, "Expected success\n");
+
+    /* Check if we can close the handle to the Service Control Manager */
+    ret = CloseServiceHandle(scm_handle);
+    ok(ret, "Expected success\n");
+
+    /* Get a new handle to the Service Control Manager */
+    scm_handle = OpenSCManagerA(NULL, NULL, GENERIC_ALL);
+    ok(scm_handle != NULL, "Expected success\n");
+
+    /* Get a handle to this new service */
+    svc_handle4 = OpenServiceA(scm_handle, servicename, GENERIC_ALL);
+    ok(svc_handle4 != NULL, "Expected success\n");
+
+    /* Delete the service */
+    ret = DeleteService(svc_handle4);
+    ok(ret, "Expected success\n");
+
+    /* We cannot create the same service again as it's still marked as 'being deleted'.
+     * The reason is that we still have 4 open handles to this service even though we
+     * closed the handle to the Service Control Manager in between.
+     */
+    SetLastError(0xdeadbeef);
+    svc_handle5 = CreateServiceA(scm_handle, servicename, NULL, GENERIC_ALL,
+                                 SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
+                                 SERVICE_DISABLED, 0, pathname, NULL, NULL, NULL, NULL, NULL);
+    todo_wine
+    {
+    ok(!svc_handle5, "Expected failure\n");
+    ok(GetLastError() == ERROR_SERVICE_MARKED_FOR_DELETE,
+       "Expected ERROR_SERVICE_MARKED_FOR_DELETE, got %d\n", GetLastError());
+    }
+
+    /* FIXME: Remove this when Wine is fixed */
+    if (svc_handle5)
+    {
+        DeleteService(svc_handle5);
+        CloseServiceHandle(svc_handle5);
+    }
+
+    /* Close all the handles to the service and try again */
+    ret = CloseServiceHandle(svc_handle4);
+    ok(ret, "Expected success\n");
+    ret = CloseServiceHandle(svc_handle3);
+    ok(ret, "Expected success\n");
+    ret = CloseServiceHandle(svc_handle2);
+    ok(ret, "Expected success\n");
+    ret = CloseServiceHandle(svc_handle1);
+    ok(ret, "Expected success\n");
+
+    /* Wait a while. Doing a CreateService too soon will result again
+     * in an ERROR_SERVICE_MARKED_FOR_DELETE error.
+     */
+    Sleep(1000);
+
+    /* We succeed now as all handles are closed (tested this also with a long SLeep() */
+    svc_handle5 = CreateServiceA(scm_handle, servicename, NULL, GENERIC_ALL,
+                                 SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
+                                 SERVICE_DISABLED, 0, pathname, NULL, NULL, NULL, NULL, NULL);
+    ok(svc_handle5 != NULL, "Expected success\n");
+
+    /* Delete the service */
+    ret = DeleteService(svc_handle5);
+    ok(ret, "Expected success\n");
+
+    /* Wait a while. Just in case one of the following tests does a CreateService again */
+    Sleep(1000);
+
+    CloseServiceHandle(svc_handle5);
+    CloseServiceHandle(scm_handle);
+}
+
+START_TEST(service)
+{
+    SC_HANDLE scm_handle;
+
+    /* Bail out if we are on win98 */
+    SetLastError(0xdeadbeef);
+    scm_handle = OpenSCManagerA(NULL, NULL, GENERIC_ALL);
+
+    if (!scm_handle && (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED))
+    {
+        skip("OpenSCManagerA is not implemented, we are most likely on win9x\n");
+        return;
+    }
+    CloseServiceHandle(scm_handle);
+
+    /* First some parameter checking */
+    test_open_scm();
+    test_open_svc();
+    test_create_delete_svc();
+    test_get_displayname();
+    test_get_servicekeyname();
+    test_close();
+    /* Test the creation, querying and deletion of a service */
+    test_sequence();
+    test_queryconfig2();
+    /* The main reason for this test is to check if any refcounting is used
+     * and what the rules are
+     */
+    test_refcount();
+}
index 3ccabd8..c7fbee8 100644 (file)
@@ -6,6 +6,7 @@
 #define STANDALONE
 #include "wine/test.h"
 
+extern void func_cred(void);
 extern void func_crypt(void);
 extern void func_crypt_lmhash(void);
 extern void func_crypt_md4(void);
@@ -14,16 +15,19 @@ extern void func_crypt_sha(void);
 extern void func_lsa(void);
 extern void func_registry(void);
 extern void func_security(void);
+extern void func_service(void);
 
 const struct test winetest_testlist[] =
 {
-/*    { "crypt", func_crypt },
+    { "cred", func_cred },
+    { "crypt", func_crypt },
     { "crypt_lmhash", func_crypt_lmhash },
     { "crypt_md4", func_crypt_md4 },
     { "crypt_md5", func_crypt_md5 },
     { "crypt_sha", func_crypt_sha },
     { "lsa", func_lsa },
-*/    { "registry", func_registry },
+    { "registry", func_registry },
     { "security", func_security },
+    { "service", func_service },
     { 0, 0 }
 };
index 09e93fd..a9faacd 100644 (file)
@@ -1,7 +1,7 @@
 <?xml version="1.0"?>
 <!DOCTYPE module SYSTEM "../../../tools/rbuild/project.dtd">
 <group>
-<module name="advpack_winetest" type="win32cui" installbase="bin" installname="advpack_winetest.exe" allowwarnings="true" entrypoint="0">
+<module name="advpack_winetest" type="win32cui" installbase="bin" installname="advpack_winetest.exe" allowwarnings="true">
        <include base="advpack_winetest">.</include>
        <define name="WINVER">0x600</define>
        <define name="_WIN32_WINNT">0x600</define>
index e109a88..530c3b2 100644 (file)
@@ -103,36 +103,6 @@ static BOOL check_ini_file_attr(LPSTR filename)
     return ret;
 }
 
-#define FIELD_LEN   16
-
-static BOOL check_ini_contents(LPSTR filename, BOOL add)
-{
-    CHAR field[FIELD_LEN];
-    BOOL ret = TRUE, match;
-
-    GetPrivateProfileStringA("backup", "one", NULL, field, FIELD_LEN, filename);
-    match = !lstrcmpA(field, "-1,0,0,0,0,0,-1");
-    if ((add && !match) || (!add && match)) {
-        trace("first test: got %s\n", field);
-        ret = FALSE;
-    }
-
-    GetPrivateProfileStringA("backup", "two", NULL, field, FIELD_LEN, filename);
-    if (lstrcmpA(field, "-1,0,0,0,0,0,-1")) {
-        trace("second test: got %s\n", field);
-        ret = FALSE;
-    }
-
-    GetPrivateProfileStringA("backup", "three", NULL, field, FIELD_LEN, filename);
-    match = !lstrcmpA(field, "-1,0,0,0,0,0,-1");
-    if ((add && !match) || (!add && match)) {
-        trace("third test: got %s\n", field);
-        ret = FALSE;
-    }
-
-    return ret;
-}
-
 static void test_AddDelBackupEntry(void)
 {
     HRESULT res;
@@ -171,7 +141,6 @@ static void test_AddDelBackupEntry(void)
     res = pAddDelBackupEntry("one\0two\0three\0", "c:\\", "basename", AADBE_ADD_ENTRY);
     ok(res == S_OK, "Expected S_OK, got %d\n", res);
     ok(check_ini_file_attr(path), "Expected ini file to be hidden\n");
-    ok(check_ini_contents(path, TRUE), "Expected ini contents to match\n");
     ok(DeleteFileA(path), "Expected path to exist\n");
 
     lstrcpyA(path, CURR_DIR);
@@ -182,7 +151,6 @@ static void test_AddDelBackupEntry(void)
     res = pAddDelBackupEntry("one\0two\0three\0", "backup", "basename", AADBE_ADD_ENTRY);
     ok(res == S_OK, "Expected S_OK, got %d\n", res);
     ok(!check_ini_file_attr(path), "Expected ini file to not be hidden\n");
-    ok(!check_ini_contents(path, TRUE), "Expected ini contents to not match\n");
     ok(!DeleteFileA(path), "Expected path to not exist\n");
 
     /* try an existent, relative backup directory */
@@ -190,7 +158,6 @@ static void test_AddDelBackupEntry(void)
     res = pAddDelBackupEntry("one\0two\0three\0", "backup", "basename", AADBE_ADD_ENTRY);
     ok(res == S_OK, "Expected S_OK, got %d\n", res);
     ok(check_ini_file_attr(path), "Expected ini file to be hidden\n");
-    ok(check_ini_contents(path, TRUE), "Expected ini contents to match\n");
     ok(DeleteFileA(path), "Expected path to exist\n");
     RemoveDirectoryA("backup");
 
@@ -200,14 +167,12 @@ static void test_AddDelBackupEntry(void)
     /* try a NULL backup dir, INI is created in the windows directory */
     res = pAddDelBackupEntry("one\0two\0three\0", NULL, "basename", AADBE_ADD_ENTRY);
     ok(res == S_OK, "Expected S_OK, got %d\n", res);
-    ok(check_ini_contents(path, TRUE), "Expected ini contents to match\n");
 
     /* remove the entries with AADBE_DEL_ENTRY */
     SetFileAttributesA(path, FILE_ATTRIBUTE_NORMAL);
     res = pAddDelBackupEntry("one\0three\0", NULL, "basename", AADBE_DEL_ENTRY);
     SetFileAttributesA(path, FILE_ATTRIBUTE_NORMAL);
     ok(res == S_OK, "Expected S_OK, got %d\n", res);
-    ok(check_ini_contents(path, FALSE), "Expected ini contents to match\n");
     ok(DeleteFileA(path), "Expected path to exist\n");
 }
 
@@ -437,8 +402,10 @@ static void test_ExtractFiles(void)
 
     /* extract all files in the cab to nonexistent destination directory */
     hr = pExtractFiles("extract.cab", destFolder, 0, NULL, NULL, 0);
-    ok(hr == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND),
-       "Expected %d, got %d\n", HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), hr);
+    ok(hr == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) ||
+       hr == E_FAIL, /* win95 */
+       "Expected %08x or %08x, got %08x\n", E_FAIL,
+       HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), hr);
     ok(!DeleteFileA("dest\\a.txt"), "Expected dest\\a.txt to not exist\n");
     ok(!DeleteFileA("dest\\testdir\\c.txt"), "Expected dest\\testdir\\c.txt to not exist\n");
     ok(!RemoveDirectoryA("dest\\testdir"), "Expected dest\\testdir to not exist\n");
@@ -505,9 +472,19 @@ static void test_ExtractFiles(void)
 static void test_AdvInstallFile(void)
 {
     HRESULT hr;
+    HMODULE hmod;
     char CURR_DIR[MAX_PATH];
     char destFolder[MAX_PATH];
 
+    hmod = LoadLibrary("setupapi.dll");
+    if (!hmod)
+    {
+        skip("setupapi.dll not present\n");
+        return;
+    }
+
+    FreeLibrary(hmod);
+
     GetCurrentDirectoryA(MAX_PATH, CURR_DIR);
 
     lstrcpyA(destFolder, CURR_DIR);
index ba52b66..bddaa52 100644 (file)
@@ -273,7 +273,8 @@ static void test_ACLMulti(void)
 
     ole_ok(acl->lpVtbl->Expand(acl, exp));
     ok(acl1->expcount == 1, "expcount - expected 1, got %d\n", acl1->expcount);
-    ok(acl2->expcount == 0, "expcount - expected 0, got %d\n", acl2->expcount);
+    ok(acl2->expcount == 0 /* XP */ || acl2->expcount == 1 /* Vista */,
+        "expcount - expected 0 or 1, got %d\n", acl2->expcount);
 
     ole_ok(obj->lpVtbl->Next(obj, 15, wstrtab, &i));
     ok(i == 1, "Expected i == 1, got %d\n", i);
@@ -282,15 +283,18 @@ static void test_ACLMulti(void)
     ole_ok(obj->lpVtbl->Next(obj, 15, wstrtab, &i));
     ole_ok(acl->lpVtbl->Expand(acl, exp));
     ok(acl1->expcount == 2, "expcount - expected 1, got %d\n", acl1->expcount);
-    ok(acl2->expcount == 0, "expcount - expected 0, got %d\n", acl2->expcount);
+    ok(acl2->expcount == 0 /* XP */ || acl2->expcount == 2 /* Vista */,
+        "expcount - expected 0 or 2, got %d\n", acl2->expcount);
     acl1->expret = S_FALSE;
     ole_ok(acl->lpVtbl->Expand(acl, exp));
     ok(acl1->expcount == 3, "expcount - expected 1, got %d\n", acl1->expcount);
-    ok(acl2->expcount == 1, "expcount - expected 0, got %d\n", acl2->expcount);
+    ok(acl2->expcount == 1 /* XP */ || acl2->expcount == 3 /* Vista */,
+        "expcount - expected 0 or 3, got %d\n", acl2->expcount);
     acl1->expret = E_NOTIMPL;
     ole_ok(acl->lpVtbl->Expand(acl, exp));
     ok(acl1->expcount == 4, "expcount - expected 1, got %d\n", acl1->expcount);
-    ok(acl2->expcount == 2, "expcount - expected 0, got %d\n", acl2->expcount);
+    ok(acl2->expcount == 2 /* XP */ || acl2->expcount == 4 /* Vista */,
+        "expcount - expected 0 or 4, got %d\n", acl2->expcount);
     acl2->expret = E_OUTOFMEMORY;
     ok(acl->lpVtbl->Expand(acl, exp) == E_OUTOFMEMORY, "Unexpected Expand return\n");
     acl2->expret = E_FAIL;