Move and reshuffle reactos/regtetsts into rostests. 1/2
authorAleksey Bragin <aleksey@reactos.org>
Tue, 6 Mar 2007 11:59:18 +0000 (11:59 +0000)
committerAleksey Bragin <aleksey@reactos.org>
Tue, 6 Mar 2007 11:59:18 +0000 (11:59 +0000)
svn path=/trunk/; revision=26014

201 files changed:
rostests/directory.rbuild
rostests/regtests_by_casper/directory.rbuild [new file with mode: 0644]
rostests/regtests_by_casper/regtests/regtests.c [new file with mode: 0644]
rostests/regtests_by_casper/regtests/regtests.def [new file with mode: 0644]
rostests/regtests_by_casper/regtests/regtests.rbuild [new file with mode: 0644]
rostests/regtests_by_casper/shared/regtests.c [new file with mode: 0644]
rostests/regtests_by_casper/shared/regtests.h [new file with mode: 0644]
rostests/regtests_by_casper/shared/rtshared.rbuild [new file with mode: 0644]
rostests/win32/kernel32/directory.rbuild [new file with mode: 0644]
rostests/win32/kernel32/queuetest/queuetest.c [new file with mode: 0644]
rostests/win32/kernel32/queuetest/queuetest.rbuild [new file with mode: 0644]
rostests/win32/kmtloader/kmtloader.c [new file with mode: 0644]
rostests/win32/kmtloader/kmtloader.rbuild [new file with mode: 0644]
rostests/win32/testsets.rbuild
rostests/winetests/advapi32/advapi32.rbuild [new file with mode: 0644]
rostests/winetests/advapi32/crypt.c [new file with mode: 0644]
rostests/winetests/advapi32/crypt_lmhash.c [new file with mode: 0644]
rostests/winetests/advapi32/crypt_md4.c [new file with mode: 0644]
rostests/winetests/advapi32/crypt_md5.c [new file with mode: 0644]
rostests/winetests/advapi32/crypt_sha.c [new file with mode: 0644]
rostests/winetests/advapi32/registry.c [new file with mode: 0644]
rostests/winetests/advapi32/security.c [new file with mode: 0644]
rostests/winetests/advapi32/testlist.c [new file with mode: 0644]
rostests/winetests/cabinet/cabinet.rbuild [new file with mode: 0644]
rostests/winetests/cabinet/extract.c [new file with mode: 0644]
rostests/winetests/cabinet/testlist.c [new file with mode: 0644]
rostests/winetests/comctl32/comboex.c [new file with mode: 0644]
rostests/winetests/comctl32/comctl32.rbuild [new file with mode: 0644]
rostests/winetests/comctl32/dpa.c [new file with mode: 0644]
rostests/winetests/comctl32/header.c [new file with mode: 0644]
rostests/winetests/comctl32/imagelist.c [new file with mode: 0644]
rostests/winetests/comctl32/listview.c [new file with mode: 0644]
rostests/winetests/comctl32/monthcal.c [new file with mode: 0644]
rostests/winetests/comctl32/mru.c [new file with mode: 0644]
rostests/winetests/comctl32/progress.c [new file with mode: 0644]
rostests/winetests/comctl32/propsheet.c [new file with mode: 0644]
rostests/winetests/comctl32/propsheet.rc [new file with mode: 0644]
rostests/winetests/comctl32/subclass.c [new file with mode: 0644]
rostests/winetests/comctl32/tab.c [new file with mode: 0644]
rostests/winetests/comctl32/testlist.c [new file with mode: 0644]
rostests/winetests/comctl32/toolbar.c [new file with mode: 0644]
rostests/winetests/comctl32/tooltips.c [new file with mode: 0644]
rostests/winetests/comctl32/treeview.c [new file with mode: 0644]
rostests/winetests/comctl32/updown.c [new file with mode: 0644]
rostests/winetests/directory.rbuild [new file with mode: 0644]
rostests/winetests/gdi32/bitmap.c [new file with mode: 0755]
rostests/winetests/gdi32/brush.c [new file with mode: 0755]
rostests/winetests/gdi32/clipping.c [new file with mode: 0644]
rostests/winetests/gdi32/dc.c [new file with mode: 0644]
rostests/winetests/gdi32/font.c [new file with mode: 0644]
rostests/winetests/gdi32/gdi32.rbuild [new file with mode: 0644]
rostests/winetests/gdi32/gdiobj.c [new file with mode: 0755]
rostests/winetests/gdi32/mapping.c [new file with mode: 0644]
rostests/winetests/gdi32/metafile.c [new file with mode: 0755]
rostests/winetests/gdi32/palette.c [new file with mode: 0644]
rostests/winetests/gdi32/testlist.c [new file with mode: 0644]
rostests/winetests/icmp/icmp.c [new file with mode: 0644]
rostests/winetests/icmp/icmp.rbuild [new file with mode: 0644]
rostests/winetests/icmp/testlist.c [new file with mode: 0644]
rostests/winetests/kernel32/alloc.c [new file with mode: 0755]
rostests/winetests/kernel32/atom.c [new file with mode: 0755]
rostests/winetests/kernel32/change.c [new file with mode: 0755]
rostests/winetests/kernel32/codepage.c [new file with mode: 0755]
rostests/winetests/kernel32/comm.c [new file with mode: 0755]
rostests/winetests/kernel32/console.c [new file with mode: 0755]
rostests/winetests/kernel32/directory.c [new file with mode: 0755]
rostests/winetests/kernel32/drive.c [new file with mode: 0755]
rostests/winetests/kernel32/environ.c [new file with mode: 0755]
rostests/winetests/kernel32/file.c [new file with mode: 0755]
rostests/winetests/kernel32/format_msg.c [new file with mode: 0755]
rostests/winetests/kernel32/heap.c [new file with mode: 0755]
rostests/winetests/kernel32/interlck.c [new file with mode: 0644]
rostests/winetests/kernel32/kernel32.rbuild [new file with mode: 0644]
rostests/winetests/kernel32/locale.c [new file with mode: 0755]
rostests/winetests/kernel32/mailslot.c [new file with mode: 0755]
rostests/winetests/kernel32/module.c [new file with mode: 0755]
rostests/winetests/kernel32/path.c [new file with mode: 0755]
rostests/winetests/kernel32/pipe.c [new file with mode: 0755]
rostests/winetests/kernel32/process.c [new file with mode: 0755]
rostests/winetests/kernel32/profile.c [new file with mode: 0755]
rostests/winetests/kernel32/sync.c [new file with mode: 0755]
rostests/winetests/kernel32/testlist.c [new file with mode: 0755]
rostests/winetests/kernel32/thread.c [new file with mode: 0755]
rostests/winetests/kernel32/time.c [new file with mode: 0755]
rostests/winetests/kernel32/timer.c [new file with mode: 0755]
rostests/winetests/kernel32/virtual.c [new file with mode: 0755]
rostests/winetests/lz32/lz32.rbuild [new file with mode: 0644]
rostests/winetests/lz32/lzexpand_main.c [new file with mode: 0644]
rostests/winetests/lz32/testlist.c [new file with mode: 0644]
rostests/winetests/msi/db.c [new file with mode: 0644]
rostests/winetests/msi/format.c [new file with mode: 0644]
rostests/winetests/msi/install.c [new file with mode: 0644]
rostests/winetests/msi/msi.c [new file with mode: 0644]
rostests/winetests/msi/msi.rbuild [new file with mode: 0644]
rostests/winetests/msi/package.c [new file with mode: 0644]
rostests/winetests/msi/record.c [new file with mode: 0644]
rostests/winetests/msi/suminfo.c [new file with mode: 0644]
rostests/winetests/msi/testlist.c [new file with mode: 0644]
rostests/winetests/msvcrt/Makefile.in [new file with mode: 0644]
rostests/winetests/msvcrt/cpp.c [new file with mode: 0644]
rostests/winetests/msvcrt/dir.c [new file with mode: 0644]
rostests/winetests/msvcrt/environ.c [new file with mode: 0644]
rostests/winetests/msvcrt/file.c [new file with mode: 0644]
rostests/winetests/msvcrt/heap.c [new file with mode: 0644]
rostests/winetests/msvcrt/msvcrt.rbuild [new file with mode: 0644]
rostests/winetests/msvcrt/msvcrt_test.dsp [new file with mode: 0644]
rostests/winetests/msvcrt/printf.c [new file with mode: 0644]
rostests/winetests/msvcrt/scanf.c [new file with mode: 0644]
rostests/winetests/msvcrt/string.c [new file with mode: 0644]
rostests/winetests/msvcrt/testlist.c [new file with mode: 0644]
rostests/winetests/msvcrt/time.c [new file with mode: 0644]
rostests/winetests/ntdll/atom.c [new file with mode: 0755]
rostests/winetests/ntdll/change.c [new file with mode: 0644]
rostests/winetests/ntdll/env.c [new file with mode: 0755]
rostests/winetests/ntdll/error.c [new file with mode: 0755]
rostests/winetests/ntdll/exception.c [new file with mode: 0644]
rostests/winetests/ntdll/generated.c [new file with mode: 0755]
rostests/winetests/ntdll/info.c [new file with mode: 0755]
rostests/winetests/ntdll/large_int.c [new file with mode: 0755]
rostests/winetests/ntdll/ntdll.rbuild [new file with mode: 0644]
rostests/winetests/ntdll/ntdll_test.h [new file with mode: 0755]
rostests/winetests/ntdll/om.c [new file with mode: 0644]
rostests/winetests/ntdll/path.c [new file with mode: 0755]
rostests/winetests/ntdll/port.c [new file with mode: 0644]
rostests/winetests/ntdll/reg.c [new file with mode: 0755]
rostests/winetests/ntdll/rtl.c [new file with mode: 0755]
rostests/winetests/ntdll/rtlbitmap.c [new file with mode: 0755]
rostests/winetests/ntdll/rtlstr.c [new file with mode: 0755]
rostests/winetests/ntdll/string.c [new file with mode: 0755]
rostests/winetests/ntdll/testlist.c [new file with mode: 0644]
rostests/winetests/ntdll/time.c [new file with mode: 0755]
rostests/winetests/powrprof/powrprof.rbuild [new file with mode: 0644]
rostests/winetests/powrprof/pwrprof.c [new file with mode: 0644]
rostests/winetests/powrprof/testlist.c [new file with mode: 0644]
rostests/winetests/psapi/psapi.rbuild [new file with mode: 0644]
rostests/winetests/psapi/psapi_main.c [new file with mode: 0644]
rostests/winetests/psapi/testlist.c [new file with mode: 0644]
rostests/winetests/setupapi/devclass.c [new file with mode: 0644]
rostests/winetests/setupapi/install.c [new file with mode: 0644]
rostests/winetests/setupapi/parser.c [new file with mode: 0644]
rostests/winetests/setupapi/query.c [new file with mode: 0644]
rostests/winetests/setupapi/setupapi.rbuild [new file with mode: 0644]
rostests/winetests/setupapi/stringtable.c [new file with mode: 0644]
rostests/winetests/setupapi/testlist.c [new file with mode: 0644]
rostests/winetests/shell32/generated.c [new file with mode: 0755]
rostests/winetests/shell32/shell32.rbuild [new file with mode: 0644]
rostests/winetests/shell32/shell32_test.h [new file with mode: 0755]
rostests/winetests/shell32/shelllink.c [new file with mode: 0755]
rostests/winetests/shell32/shellpath.c [new file with mode: 0644]
rostests/winetests/shell32/shlexec.c [new file with mode: 0755]
rostests/winetests/shell32/shlfileop.c [new file with mode: 0644]
rostests/winetests/shell32/shlfolder.c [new file with mode: 0644]
rostests/winetests/shell32/string.c [new file with mode: 0755]
rostests/winetests/shell32/testlist.c [new file with mode: 0644]
rostests/winetests/shlwapi/clist.c [new file with mode: 0755]
rostests/winetests/shlwapi/clsid.c [new file with mode: 0755]
rostests/winetests/shlwapi/generated.c [new file with mode: 0755]
rostests/winetests/shlwapi/ordinal.c [new file with mode: 0755]
rostests/winetests/shlwapi/path.c [new file with mode: 0755]
rostests/winetests/shlwapi/shlwapi.rbuild [new file with mode: 0644]
rostests/winetests/shlwapi/shreg.c [new file with mode: 0755]
rostests/winetests/shlwapi/string.c [new file with mode: 0755]
rostests/winetests/shlwapi/testlist.c [new file with mode: 0755]
rostests/winetests/user32/class.c [new file with mode: 0755]
rostests/winetests/user32/clipboard.c [new file with mode: 0755]
rostests/winetests/user32/dce.c [new file with mode: 0755]
rostests/winetests/user32/dde.c [new file with mode: 0755]
rostests/winetests/user32/dialog.c [new file with mode: 0755]
rostests/winetests/user32/edit.c [new file with mode: 0755]
rostests/winetests/user32/input.c [new file with mode: 0755]
rostests/winetests/user32/listbox.c [new file with mode: 0644]
rostests/winetests/user32/menu.c [new file with mode: 0755]
rostests/winetests/user32/monitor.c [new file with mode: 0644]
rostests/winetests/user32/msg.c [new file with mode: 0755]
rostests/winetests/user32/resource.c [new file with mode: 0755]
rostests/winetests/user32/resource.rc [new file with mode: 0755]
rostests/winetests/user32/sysparams.c [new file with mode: 0755]
rostests/winetests/user32/testlist.c [new file with mode: 0644]
rostests/winetests/user32/text.c [new file with mode: 0755]
rostests/winetests/user32/user32.rbuild [new file with mode: 0644]
rostests/winetests/user32/win.c [new file with mode: 0644]
rostests/winetests/user32/winstation.c [new file with mode: 0755]
rostests/winetests/user32/wsprintf.c [new file with mode: 0755]
rostests/winetests/usp10/testlist.c [new file with mode: 0644]
rostests/winetests/usp10/usp10.c [new file with mode: 0644]
rostests/winetests/usp10/usp10.rbuild [new file with mode: 0644]
rostests/winetests/version/info.c [new file with mode: 0644]
rostests/winetests/version/testlist.c [new file with mode: 0644]
rostests/winetests/version/version.rbuild [new file with mode: 0644]
rostests/winetests/winetest/config.h [new file with mode: 0644]
rostests/winetests/winetest/dist.rc [new file with mode: 0644]
rostests/winetests/winetest/gui.c [new file with mode: 0644]
rostests/winetests/winetest/main.c [new file with mode: 0644]
rostests/winetests/winetest/port.h [new file with mode: 0644]
rostests/winetests/winetest/resource.h [new file with mode: 0644]
rostests/winetests/winetest/send.c [new file with mode: 0644]
rostests/winetests/winetest/tests.rc [new file with mode: 0644]
rostests/winetests/winetest/util.c [new file with mode: 0644]
rostests/winetests/winetest/wine.ico [new file with mode: 0644]
rostests/winetests/winetest/winetest.h [new file with mode: 0644]
rostests/winetests/winetest/winetest.rc [new file with mode: 0644]

index 961c833..53a53d8 100644 (file)
@@ -1,9 +1,15 @@
 <directory name="dxtest">\r
        <xi:include href="dxtest/directory.rbuild" />\r
 </directory>\r
+<directory name="regtests_by_casper">\r
+       <xi:include href="regtests_by_casper/directory.rbuild" />\r
+</directory>\r
 <directory name="tests">\r
        <xi:include href="tests/directory.rbuild" />\r
 </directory>\r
 <directory name="win32">\r
        <xi:include href="win32/testsets.rbuild" />\r
 </directory>\r
+<directory name="winetests">\r
+       <xi:include href="winetests/directory.rbuild" />\r
+</directory>\r
diff --git a/rostests/regtests_by_casper/directory.rbuild b/rostests/regtests_by_casper/directory.rbuild
new file mode 100644 (file)
index 0000000..cb0410a
--- /dev/null
@@ -0,0 +1,6 @@
+<directory name="regtests">\r
+       <xi:include href="regtests/regtests.rbuild" />\r
+</directory>\r
+<directory name="shared">\r
+       <xi:include href="shared/rtshared.rbuild" />\r
+</directory>\r
diff --git a/rostests/regtests_by_casper/regtests/regtests.c b/rostests/regtests_by_casper/regtests/regtests.c
new file mode 100644 (file)
index 0000000..ccda2f9
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * PROJECT:         ReactOS kernel
+ * FILE:            regtests/regtests/regtests.c
+ * PURPOSE:         Regression testing framework
+ * PROGRAMMER:      Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * UPDATE HISTORY:
+ *      23-10-2004  CSH  Created
+ */
+#include <windows.h>
+
+HMODULE STDCALL
+_GetModuleHandleA(LPCSTR lpModuleName)
+{
+  return GetModuleHandleA(lpModuleName);
+}
+
+FARPROC STDCALL
+_GetProcAddress(HMODULE hModule,
+  LPCSTR lpProcName)
+{
+  return GetProcAddress(hModule, lpProcName);
+}
+
+HINSTANCE STDCALL
+_LoadLibraryA(LPCSTR lpLibFileName)
+{
+  return LoadLibraryA(lpLibFileName);
+}
+
+VOID STDCALL
+_ExitProcess(UINT uExitCode)
+{
+  ExitProcess(uExitCode);
+}
+
+HANDLE STDCALL
+_CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, DWORD dwStackSize,
+              LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter,
+              DWORD dwCreationFlags, LPDWORD lpThreadId)
+{
+  return CreateThread(lpThreadAttributes, dwStackSize, lpStartAddress,
+                      lpParameter, dwCreationFlags, lpThreadId);
+}
+
+WINBOOL STDCALL
+_TerminateThread(HANDLE hThread, DWORD dwExitCode)
+{
+  return TerminateThread(hThread, dwExitCode);
+}
+
+DWORD STDCALL
+_WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds)
+{
+  return WaitForSingleObject(hHandle, dwMilliseconds);
+}
+
+DWORD STDCALL
+_GetLastError()
+{
+  return GetLastError();
+}
+
+VOID STDCALL
+_CloseHandle(HANDLE handle)
+{
+  CloseHandle (handle);
+}
+
+BOOL STDCALL
+_GetThreadTimes(HANDLE hThread, LPFILETIME lpCreationTime,
+                   LPFILETIME lpExitTime, LPFILETIME lpKernelTime,
+                   LPFILETIME lpUserTime)
+{
+  return GetThreadTimes(hThread, lpCreationTime, lpExitTime,
+                        lpKernelTime, lpUserTime);
+}
+
+BOOL STDCALL
+_SetPriorityClass(HANDLE hProcess, DWORD dwPriorityClass)
+{
+  return SetPriorityClass(hProcess, dwPriorityClass);
+}
+
+BOOL STDCALL
+_SetThreadPriority(HANDLE hThread, int nPriority)
+{
+  return SetThreadPriority(hThread, nPriority);
+}
+
+HANDLE STDCALL
+_GetCurrentProcess()
+{
+  return GetCurrentProcess();
+}
+
+HANDLE STDCALL
+_GetCurrentThread()
+{
+  return GetCurrentThread();
+}
+
+VOID STDCALL
+_Sleep(DWORD dwMilliseconds)
+{
+  return Sleep(dwMilliseconds);
+}
diff --git a/rostests/regtests_by_casper/regtests/regtests.def b/rostests/regtests_by_casper/regtests/regtests.def
new file mode 100644 (file)
index 0000000..cd492c3
--- /dev/null
@@ -0,0 +1,17 @@
+LIBRARY REGTESTS.DLL
+EXPORTS
+_ExitProcess@4
+_GetModuleHandleA@4
+_GetProcAddress@8
+_LoadLibraryA@4
+_CreateThread@24
+_TerminateThread@8
+_WaitForSingleObject@8
+_GetLastError@0
+_CloseHandle@4
+_GetThreadTimes@20
+_SetPriorityClass@8
+_SetThreadPriority@8
+_GetCurrentProcess@0
+_GetCurrentThread@0
+_Sleep@4
diff --git a/rostests/regtests_by_casper/regtests/regtests.rbuild b/rostests/regtests_by_casper/regtests/regtests.rbuild
new file mode 100644 (file)
index 0000000..1822536
--- /dev/null
@@ -0,0 +1,7 @@
+<module name="regtests" type="win32dll" baseaddress="${BASEADDRESS_REGTESTS}">
+       <importlibrary definition="regtests.def" />
+       <include base="regtests">.</include>
+       <define name="__USE_W32API" />
+       <library>kernel32</library>
+       <file>regtests.c</file>
+</module>
diff --git a/rostests/regtests_by_casper/shared/regtests.c b/rostests/regtests_by_casper/shared/regtests.c
new file mode 100644 (file)
index 0000000..3513911
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+ * PROJECT:         ReactOS kernel
+ * FILE:            regtests/shared/regtests.c
+ * PURPOSE:         Regression testing framework
+ * PROGRAMMER:      Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * UPDATE HISTORY:
+ *      06-07-2003  CSH  Created
+ */
+#define WIN32_NO_STATUS
+#include <windows.h>
+#define NTOS_MODE_USER
+#include <ndk/ntndk.h>
+#include <pseh/pseh.h>
+#include "regtests.h"
+
+#define NDEBUG
+#include <debug.h>
+
+typedef struct _PERFORM_TEST_ARGS
+{
+  TestOutputRoutine OutputRoutine;
+  _PTEST Test;
+  LPSTR TestName;
+  DWORD Result;
+  char Buffer[5000];
+  DWORD Time;
+} PERFORM_TEST_ARGS;
+
+int _Result;
+char *_Buffer;
+
+static LIST_ENTRY AllTests;
+
+VOID
+InitializeTests()
+{
+  InitializeListHead(&AllTests);
+}
+
+char*
+FormatExecutionTime(char *buffer, ULONG milliseconds)
+{
+  sprintf(buffer,
+         "%ldms",
+         milliseconds);
+  return buffer;
+}
+
+DWORD WINAPI
+PerformTest(PVOID _arg)
+{
+  PERFORM_TEST_ARGS *Args = (PERFORM_TEST_ARGS *)_arg;
+  _PTEST Test = Args->Test;
+
+  _SetThreadPriority(_GetCurrentThread(), THREAD_PRIORITY_IDLE);
+
+  memset(Args->Buffer, 0, sizeof(Args->Buffer));
+
+  _SEH_TRY {
+    _Result = TS_OK;
+    _Buffer = Args->Buffer;
+    (Test->Routine)(TESTCMD_RUN);
+    Args->Result = _Result;
+  } _SEH_HANDLE {
+    Args->Result = TS_FAILED;
+    sprintf(Args->Buffer, "due to exception 0x%lx", _SEH_GetExceptionCode());
+  } _SEH_END;
+  return 1;
+}
+
+VOID
+ControlNormalTest(HANDLE hThread,
+            PERFORM_TEST_ARGS *Args,
+            DWORD TimeOut)
+{
+  _FILETIME time;
+  _FILETIME executionTime;
+  DWORD status;
+
+  status = _WaitForSingleObject(hThread, TimeOut);
+  if (status == WAIT_TIMEOUT)
+  {
+    _TerminateThread(hThread, 0);
+    Args->Result = TS_TIMEDOUT;
+  }
+  status = _GetThreadTimes(hThread,
+                          &time,
+                          &time,
+                          &time,
+                          &executionTime);
+  Args->Time = executionTime.dwLowDateTime / 10000;
+}
+
+VOID
+DisplayResult(PERFORM_TEST_ARGS* Args,
+              LPSTR OutputBuffer)
+{
+  char Format[100];
+
+  if (Args->Result == TS_OK)
+    {
+      sprintf(OutputBuffer,
+              "[%s] Success [%s]\n",
+              Args->TestName,
+              FormatExecutionTime(Format,
+                                  Args->Time));
+    }
+  else if (Args->Result == TS_TIMEDOUT)
+    {
+      sprintf(OutputBuffer,
+              "[%s] Timed out [%s]\n",
+              Args->TestName,
+              FormatExecutionTime(Format,
+                                  Args->Time));
+    }
+  else
+      sprintf(OutputBuffer, "[%s] Failed (%s)\n", Args->TestName, Args->Buffer);
+
+  if (Args->OutputRoutine != NULL)
+    (*Args->OutputRoutine)(OutputBuffer);
+  else
+    DbgPrint(OutputBuffer);
+}
+
+VOID
+ControlTest(HANDLE hThread,
+            PERFORM_TEST_ARGS *Args,
+            DWORD TestType,
+            DWORD TimeOut)
+{
+  switch (TestType)
+  {
+    case TT_NORMAL:
+      ControlNormalTest(hThread, Args, TimeOut);
+      break;
+    default:
+      printf("Unknown test type %ld\n", TestType);
+      break;
+  }
+}
+
+VOID
+PerformTests(TestOutputRoutine OutputRoutine, LPSTR TestName)
+{
+  PLIST_ENTRY CurrentEntry;
+  PLIST_ENTRY NextEntry;
+  _PTEST Current;
+  PERFORM_TEST_ARGS Args;
+  HANDLE hThread;
+  char OutputBuffer[1024];
+  char Name[200];
+  DWORD TestType;
+  DWORD TimeOut;
+
+  Args.OutputRoutine = OutputRoutine;
+  Args.TestName = Name;
+  Args.Time = 0;
+
+  CurrentEntry = AllTests.Flink;
+  for (; CurrentEntry != &AllTests; CurrentEntry = NextEntry)
+    {
+      NextEntry = CurrentEntry->Flink;
+      Current = CONTAINING_RECORD(CurrentEntry, _TEST, ListEntry);
+      Args.Test = Current;
+
+      /* Get name of test */
+      memset(Name, 0, sizeof(Name));
+
+      _Result = TS_OK;
+      _Buffer = Name;
+      (Current->Routine)(TESTCMD_TESTNAME);
+      if (_Result != TS_OK)
+        {
+          if (TestName != NULL)
+            continue;
+          strcpy(Name, "Unnamed");
+        }
+
+      if ((TestName != NULL) && (_stricmp(Name, TestName) != 0))
+        continue;
+
+      TestType = TT_NORMAL;
+      _Result = TS_OK;
+      _Buffer = (char *)&TestType;
+      (Current->Routine)(TESTCMD_TESTTYPE);
+      if (_Result != TS_OK)
+        TestType = TT_NORMAL;
+
+      /* Get timeout for test */
+      TimeOut = 0;
+      _Result = TS_OK;
+      _Buffer = (char *)&TimeOut;
+      (Current->Routine)(TESTCMD_TIMEOUT);
+      if (_Result != TS_OK || TimeOut == INFINITE)
+        TimeOut = 5000;
+
+      /* Run test in a separate thread */
+      hThread = _CreateThread(NULL, 0, PerformTest, (PVOID)&Args, 0, NULL);
+      if (hThread == NULL)
+        {
+          printf("[%s] Failed (CreateThread() failed: %ld)\n",
+                 Name,
+                 _GetLastError());
+          Args.Result = TS_FAILED;
+        }
+      else
+        ControlTest(hThread, &Args, TestType, TimeOut);
+
+      DisplayResult(&Args, OutputBuffer);
+    }
+}
+
+VOID
+AddTest(TestRoutine Routine)
+{
+  _PTEST Test;
+
+  Test = (_PTEST) malloc(sizeof(_TEST));
+  if (Test == NULL)
+    {
+      DbgPrint("Out of memory");
+      return;
+    }
+
+  Test->Routine = Routine;
+
+  InsertTailList(&AllTests, &Test->ListEntry);
+}
+
+PVOID STDCALL
+FrameworkGetHook(ULONG index)
+{
+  return FrameworkGetHookInternal(index);
+}
diff --git a/rostests/regtests_by_casper/shared/regtests.h b/rostests/regtests_by_casper/shared/regtests.h
new file mode 100644 (file)
index 0000000..aa1845f
--- /dev/null
@@ -0,0 +1,384 @@
+/*
+ * PROJECT:         ReactOS kernel
+ * FILE:            regtests/shared/regtests.h
+ * PURPOSE:         Regression testing
+ * PROGRAMMER:      Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * UPDATE HISTORY:
+ *      06-07-2003  CSH  Created
+ */
+#ifndef __REGTESTS_H
+#define __REGTESTS_H
+#include <stdio.h>
+#include <string.h>
+
+typedef DWORD (STDCALL _LPTHREAD_START_ROUTINE)(LPVOID lpParameter);
+
+typedef struct __FILETIME
+{
+  DWORD dwLowDateTime;
+  DWORD dwHighDateTime;
+} _FILETIME, *_PFILETIME, *_LPFILETIME;
+
+extern void SetupOnce();
+
+#define _SetupOnce() \
+void SetupOnce()
+
+/* Valid values for Command parameter of TestRoutine */
+#define TESTCMD_RUN       0   /* Buffer contains information about what failed */
+#define TESTCMD_TESTTYPE  1   /* Buffer contains type of test */
+#define TESTCMD_TESTNAME  2   /* Buffer contains description of test */
+#define TESTCMD_TIMEOUT   3   /* Buffer contains timeout for test (DWORD, default is 5000 ms) */
+
+/* Test types */
+#define TT_NORMAL         0
+
+/* Valid values for return values of TestRoutine */
+#define TS_TIMEDOUT      ((DWORD)-2)
+#define TS_EXCEPTION     ((DWORD)-1)
+#define TS_OK             0
+#define TS_FAILED         1
+
+extern int _Result;
+extern char *_Buffer;
+
+/* Macros to simplify tests */
+#define _DispatcherTypeTimeout(FunctionName, TestName, TestType, TimeOut) \
+void \
+FunctionName(int Command) \
+{ \
+  switch (Command) \
+    { \
+      case TESTCMD_RUN: \
+        RunTest(); \
+        break; \
+      case TESTCMD_TESTTYPE: \
+        *(PDWORD)_Buffer = (DWORD)TestType; \
+        break; \
+      case TESTCMD_TESTNAME: \
+        strcpy(_Buffer, TestName); \
+        break; \
+      case TESTCMD_TIMEOUT: \
+        *(PDWORD)_Buffer = (DWORD)TimeOut; \
+        break; \
+      default: \
+        _Result = TS_FAILED; \
+        break; \
+    } \
+}
+
+#define _DispatcherTimeout(FunctionName, TestName, TimeOut) \
+  _DispatcherTypeTimeout(FunctionName, TestName, TT_NORMAL, TimeOut)
+
+#define _DispatcherType(FunctionName, TestName, TestType) \
+  _DispatcherTypeTimeout(FunctionName, TestName, TestType, 5000)
+
+#define _Dispatcher(FunctionName, TestName) \
+  _DispatcherTimeout(FunctionName, TestName, 5000)
+
+static __inline void
+AppendAssertion(char *message)
+{
+  if (strlen(_Buffer) != 0)
+    strcat(_Buffer, "\n");
+  strcat(_Buffer, message);
+  _Result = TS_FAILED;
+}
+
+#define _AssertTrue(_Condition) \
+{ \
+  if (!(_Condition)) \
+    { \
+      char _message[100]; \
+      sprintf(_message, "Condition was not true at %s:%d", \
+        __FILE__, __LINE__); \
+      AppendAssertion(_message); \
+    } \
+}
+
+#define _AssertFalse(_Condition) \
+{ \
+  if (_Condition) \
+    { \
+      char _message[100]; \
+      sprintf(_message, "Condition was not false at %s:%d", \
+        __FILE__, __LINE__); \
+      AppendAssertion(_message); \
+    } \
+}
+
+#define _AssertEqualValue(_Expected, _Actual) \
+{ \
+  ULONG __Expected = (ULONG) (_Expected); \
+  ULONG __Actual = (ULONG) (_Actual); \
+  if ((__Expected) != (__Actual)) \
+    { \
+      char _message[100]; \
+      sprintf(_message, "Expected %ld/0x%.08lx was %ld/0x%.08lx at %s:%d", \
+        (__Expected), (__Expected), (__Actual), (__Actual), __FILE__, __LINE__); \
+      AppendAssertion(_message); \
+    } \
+}
+
+#define _AssertEqualWideString(_Expected, _Actual) \
+{ \
+  LPWSTR __Expected = (LPWSTR) (_Expected); \
+  LPWSTR __Actual = (LPWSTR) (_Actual); \
+  if (wcscmp((__Expected), (__Actual)) != 0) \
+    { \
+      char _message[100]; \
+      sprintf(_message, "Expected %S was %S at %s:%d", \
+        (__Expected), (__Actual), __FILE__, __LINE__); \
+      AppendAssertion(_message); \
+    } \
+}
+
+#define _AssertNotEqualValue(_Expected, _Actual) \
+{ \
+  ULONG __Expected = (ULONG) (_Expected); \
+  ULONG __Actual = (ULONG) (_Actual); \
+  if ((__Expected) == (__Actual)) \
+    { \
+      char _message[100]; \
+      sprintf(_message, "Actual value expected to be different from %ld/0x%.08lx at %s:%d", \
+        (__Expected), (__Expected), __FILE__, __LINE__); \
+      AppendAssertion(_message); \
+    } \
+}
+
+
+/*
+ * Test routine prototype
+ * Command - The command to process
+ */
+typedef void (*TestRoutine)(int Command);
+
+/*
+ * Test output routine prototype
+ * Buffer - Address of buffer with text to output
+ */
+typedef void (*TestOutputRoutine)(char *Buffer);
+
+/*
+ * Test driver entry routine.
+*  OutputRoutine - Output routine.
+ * TestName - If NULL all tests are run. If non-NULL specifies the test to be run
+ */
+typedef void (STDCALL *TestDriverMain)(TestOutputRoutine OutputRoutine, char *TestName);
+
+typedef struct __TEST
+{
+  LIST_ENTRY ListEntry;
+  TestRoutine Routine;
+} _TEST, *_PTEST;
+
+extern VOID InitializeTests();
+extern VOID RegisterTests();
+extern VOID PerformTests(TestOutputRoutine OutputRoutine, LPSTR TestName);
+
+
+typedef struct __API_DESCRIPTION
+{
+  PCHAR FileName;
+  PCHAR FunctionName;
+  PCHAR ForwardedFunctionName;
+  PVOID FunctionAddress;
+  PVOID MockFunctionAddress;
+} _API_DESCRIPTION, *_PAPI_DESCRIPTION;
+
+extern _API_DESCRIPTION ExternalDependencies[];
+extern ULONG MaxExternalDependency;
+
+HANDLE STDCALL
+_GetModuleHandleA(LPCSTR lpModuleName);
+
+PVOID STDCALL
+_GetProcAddress(HANDLE hModule,
+  LPCSTR lpProcName);
+
+HANDLE STDCALL
+_LoadLibraryA(LPCSTR lpLibFileName);
+
+VOID STDCALL
+_ExitProcess(UINT uExitCode);
+
+HANDLE STDCALL
+_CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, DWORD dwStackSize,
+              _LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter,
+              DWORD dwCreationFlags, LPDWORD lpThreadId);
+
+BOOL STDCALL
+_TerminateThread(HANDLE hThread, DWORD dwExitCode);
+
+DWORD STDCALL
+_WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds);
+
+DWORD STDCALL
+_GetLastError();
+
+VOID STDCALL
+_CloseHandle(HANDLE handle);
+
+BOOL STDCALL
+_GetThreadTimes(HANDLE hThread,
+                _LPFILETIME lpCreationTime,
+                _LPFILETIME lpExitTime,
+                _LPFILETIME lpKernelTime,
+                _LPFILETIME lpUserTime);
+
+BOOL STDCALL
+_SetPriorityClass(HANDLE hProcess, DWORD dwPriorityClass);
+
+BOOL STDCALL
+_SetThreadPriority(HANDLE hThread, int nPriority);
+
+HANDLE STDCALL
+_GetCurrentProcess();
+
+HANDLE STDCALL
+_GetCurrentThread();
+
+VOID STDCALL
+_Sleep(DWORD dwMilliseconds);
+
+
+static __inline PCHAR
+FrameworkGetExportedFunctionNameInternal(_PAPI_DESCRIPTION ApiDescription)
+{
+  if (ApiDescription->ForwardedFunctionName != NULL)
+    {
+      return ApiDescription->ForwardedFunctionName;
+    }
+  else
+    {
+      return ApiDescription->FunctionName;
+    }
+}
+
+static __inline PVOID
+FrameworkGetFunction(_PAPI_DESCRIPTION ApiDescription)
+{
+  HANDLE hModule;
+  PVOID function = NULL;
+  PCHAR exportedFunctionName;
+
+  exportedFunctionName = FrameworkGetExportedFunctionNameInternal(ApiDescription);
+
+  hModule = _GetModuleHandleA(ApiDescription->FileName);
+  if (hModule != NULL) 
+    {
+      function = _GetProcAddress(hModule, exportedFunctionName);
+    }
+  else
+         {
+      hModule = _LoadLibraryA(ApiDescription->FileName);
+      if (hModule != NULL)
+        {
+          function = _GetProcAddress(hModule, exportedFunctionName);
+          //FreeLibrary(hModule);
+        }
+    }
+  return function;
+}
+
+static __inline PVOID
+FrameworkGetHookInternal(ULONG index)
+{
+  PVOID address;
+  PCHAR exportedFunctionName;
+
+  if (index > MaxExternalDependency)
+    return NULL;
+
+  if (ExternalDependencies[index].MockFunctionAddress != NULL)
+    return ExternalDependencies[index].MockFunctionAddress;
+
+  if (ExternalDependencies[index].FunctionAddress != NULL)
+    return ExternalDependencies[index].FunctionAddress;
+
+  exportedFunctionName = FrameworkGetExportedFunctionNameInternal(&ExternalDependencies[index]);
+
+  printf("Calling function '%s' in DLL '%s'.\n",
+    exportedFunctionName,
+    ExternalDependencies[index].FileName);
+
+  address = FrameworkGetFunction(&ExternalDependencies[index]);
+  if (address == NULL)
+    {
+      printf("Function '%s' not found in DLL '%s'.\n",
+        exportedFunctionName,
+        ExternalDependencies[index].FileName);
+    }
+  ExternalDependencies[index].FunctionAddress = address;
+  return address;
+}
+
+
+static __inline VOID
+_SetHook(PCHAR name,
+  PVOID address)
+{
+  _PAPI_DESCRIPTION api;
+  ULONG index;
+
+  for (index = 0; index <= MaxExternalDependency; index++)
+    {
+      api = &ExternalDependencies[index];
+      if (strcmp(api->FunctionName, name) == 0)
+        {
+          api->MockFunctionAddress = address;
+          return;
+        }
+    }
+}
+
+typedef struct __HOOK
+{
+  PCHAR FunctionName;
+  PVOID FunctionAddress;
+} _HOOK, *_PHOOK;
+
+static __inline VOID
+_SetHooks(_PHOOK hookTable)
+{
+  _PHOOK hook;
+
+  hook = &hookTable[0];
+  while (hook->FunctionName != NULL)
+    {
+      _SetHook(hook->FunctionName,
+        hook->FunctionAddress);
+      hook++;
+    }
+}
+
+static __inline VOID
+_UnsetHooks(_PHOOK hookTable)
+{
+  _PHOOK hook;
+
+  hook = &hookTable[0];
+  while (hook->FunctionName != NULL)
+    {
+      _SetHook(hook->FunctionName,
+        NULL);
+      hook++;
+    }
+}
+
+static __inline VOID
+_UnsetAllHooks()
+{
+  _PAPI_DESCRIPTION api;
+  ULONG index;
+
+  for (index = 0; index <= MaxExternalDependency; index++)
+    {
+      api = &ExternalDependencies[index];
+      api->MockFunctionAddress = NULL;
+    }
+}
+
+#endif /* __REGTESTS_H */
diff --git a/rostests/regtests_by_casper/shared/rtshared.rbuild b/rostests/regtests_by_casper/shared/rtshared.rbuild
new file mode 100644 (file)
index 0000000..6e5ec77
--- /dev/null
@@ -0,0 +1,5 @@
+<module name="rtshared" type="staticlibrary">
+       <include base="rtshared">.</include>
+       <define name="__USE_W32API" />
+       <file>regtests.c</file>
+</module>
diff --git a/rostests/win32/kernel32/directory.rbuild b/rostests/win32/kernel32/directory.rbuild
new file mode 100644 (file)
index 0000000..e5bf08c
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0"?>
+<!DOCTYPE project SYSTEM "tools/rbuild/project.dtd">
+<group>
+<directory name="queuetest">
+       <xi:include href="queuetest/queuetest.rbuild" />
+</directory>
+</group>
diff --git a/rostests/win32/kernel32/queuetest/queuetest.c b/rostests/win32/kernel32/queuetest/queuetest.c
new file mode 100644 (file)
index 0000000..f198465
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * PROJECT:         ReactOS Tests
+ * LICENSE:         GPL - See COPYING in the top level directory
+ * FILE:            queuetest.c
+ * PURPOSE:         Usermode QueueUserWorkItem() testing
+ * PROGRAMMERS:     Thomas Weidenmueller (w3seek@reactos.org)
+ */
+
+#include <windows.h>
+#include <stdio.h>
+
+#define WT_EXECUTEINPERSISTENTIOTHREAD 0x00000040
+BOOL WINAPI QueueUserWorkItem(LPTHREAD_START_ROUTINE,PVOID,ULONG);
+
+#define TestProc(n) \
+DWORD CALLBACK TestProc##n(void *ctx)\
+{\
+    printf("TestProc%d thread 0x%x context 0x%p\n", n, GetCurrentThreadId(), ctx);\
+    return 0;\
+}
+
+TestProc(1)
+TestProc(2)
+TestProc(3)
+TestProc(4)
+TestProc(5)
+TestProc(6)
+
+int __cdecl
+main(int argc, char* argv[])
+{
+    PVOID x = (PVOID)0x12345;
+    QueueUserWorkItem(TestProc1, x, 0);
+    QueueUserWorkItem(TestProc2, x, WT_EXECUTELONGFUNCTION);
+    QueueUserWorkItem(TestProc3, x, WT_EXECUTEINIOTHREAD);
+    QueueUserWorkItem(TestProc4, x, WT_EXECUTEINIOTHREAD | WT_EXECUTELONGFUNCTION);
+    QueueUserWorkItem(TestProc5, x, WT_EXECUTEINPERSISTENTTHREAD);
+    QueueUserWorkItem(TestProc6, x, WT_EXECUTEINPERSISTENTIOTHREAD);
+    Sleep(INFINITE);
+    return 0;
+}
diff --git a/rostests/win32/kernel32/queuetest/queuetest.rbuild b/rostests/win32/kernel32/queuetest/queuetest.rbuild
new file mode 100644 (file)
index 0000000..7211e75
--- /dev/null
@@ -0,0 +1,5 @@
+<module name="queuetest" type="win32cui" installbase="system32" installname="queuetest.exe" allowwarnings="true">
+        <define name="__USE_W32API" />
+       <library>kernel32</library>
+       <file>queuetest.c</file>
+</module>
diff --git a/rostests/win32/kmtloader/kmtloader.c b/rostests/win32/kmtloader/kmtloader.c
new file mode 100644 (file)
index 0000000..d200425
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Kernel-Mode Tests Loader (based on PnP Test Driver Loader by Filip Navara)
+ *
+ * Copyright 2004 Filip Navara <xnavara@volny.cz>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; see the file COPYING.LIB.
+ * If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/* INCLUDES *******************************************************************/
+
+#include <windows.h>
+#include <stdio.h>
+
+/* PUBLIC FUNCTIONS ***********************************************************/
+
+int main()
+{
+    SC_HANDLE schSCManager;
+    SC_HANDLE schService;
+    PWCHAR DriverName = L"KMTEST";
+    WCHAR ServiceExe[MAX_PATH];
+
+    printf("Kernel Mode Tests loader\n\n");
+    GetCurrentDirectoryW(MAX_PATH, ServiceExe);
+    wcscat(ServiceExe, L"\\kmtest.sys");
+
+    printf("Opening SC Manager...\n");
+    schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
+
+    if (schSCManager == NULL)
+    {
+        DWORD Err = GetLastError();
+        printf("OpenSCManager failed with error 0x%lx\n", Err);
+        return 0;
+    }
+
+    printf("Creating service...\n");
+    schService = CreateServiceW(
+        schSCManager,
+        DriverName,
+        DriverName,
+        SERVICE_ALL_ACCESS,
+        SERVICE_KERNEL_DRIVER,
+        SERVICE_DEMAND_START,
+        SERVICE_ERROR_NORMAL,
+        ServiceExe,
+        NULL,
+        NULL,
+        NULL,
+        NULL,
+        NULL);
+
+    if (schService == NULL)
+    {
+        printf("Opening service...\n");
+        schService = OpenServiceW(schSCManager, DriverName, SERVICE_ALL_ACCESS);
+    }
+
+    if (schService == NULL)
+    {
+        DWORD Err = GetLastError();
+        printf("Create/OpenService failed with error 0x%lx\n", Err);
+        CloseServiceHandle(schSCManager);
+        return 0;
+    }
+
+    //for (;;) ;
+
+    printf("Starting service...\n");
+    StartService(schService, 0, NULL);
+
+    printf("Cleaning up and exiting\n");
+    CloseServiceHandle(schService);
+    CloseServiceHandle(schSCManager);
+
+    return 0;
+}
diff --git a/rostests/win32/kmtloader/kmtloader.rbuild b/rostests/win32/kmtloader/kmtloader.rbuild
new file mode 100644 (file)
index 0000000..56afda2
--- /dev/null
@@ -0,0 +1,6 @@
+<module name="kmtloader" type="win32cui" installbase="system32" installname="kmtloader.exe">
+        <define name="__USE_W32API" />
+       <library>kernel32</library>
+       <library>advapi32</library>
+       <file>kmtloader.c</file>
+</module>
index 745c4b5..04e434a 100644 (file)
@@ -1,6 +1,12 @@
 <?xml version="1.0"?>
 <!DOCTYPE project SYSTEM "tools/rbuild/project.dtd">
 <group>
+<directory name="kernel32">
+       <xi:include href="kernel32/directory.rbuild" />
+</directory>
+<directory name="kmtloader">
+       <xi:include href="kmtloader/kmtloader.rbuild" />
+</directory>
 <directory name="smss">
        <xi:include href="smss/smss.rbuild" />
 </directory>
diff --git a/rostests/winetests/advapi32/advapi32.rbuild b/rostests/winetests/advapi32/advapi32.rbuild
new file mode 100644 (file)
index 0000000..a77f327
--- /dev/null
@@ -0,0 +1,10 @@
+<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>
+    <file>registry.c</file>
+    <file>security.c</file>
+    <file>testlist.c</file>
+</module>
diff --git a/rostests/winetests/advapi32/crypt.c b/rostests/winetests/advapi32/crypt.c
new file mode 100644 (file)
index 0000000..087ab46
--- /dev/null
@@ -0,0 +1,764 @@
+/*
+ * Unit tests for crypt functions
+ *
+ * Copyright (c) 2004 Michael Jung
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "wincrypt.h"
+#include "winerror.h"
+#include "winreg.h"
+
+#include "wine/test.h"
+
+static const char szRsaBaseProv[] = MS_DEF_PROV_A;
+static const char szNonExistentProv[] = "Wine Nonexistent Cryptographic Provider v11.2";
+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*);
+static BOOL (WINAPI *pCryptGetDefaultProviderA)(DWORD, DWORD*, DWORD, LPSTR, DWORD*);
+static BOOL (WINAPI *pCryptReleaseContext)(HCRYPTPROV, DWORD);
+static BOOL (WINAPI *pCryptSetProviderExA)(LPCSTR, DWORD, DWORD*, DWORD);
+static BOOL (WINAPI *pCryptCreateHash)(HCRYPTPROV, ALG_ID, HCRYPTKEY, DWORD, HCRYPTHASH*);
+static BOOL (WINAPI *pCryptDestroyHash)(HCRYPTHASH);
+static BOOL (WINAPI *pCryptGenRandom)(HCRYPTPROV, DWORD, BYTE*);
+static BOOL (WINAPI *pCryptContextAddRef)(HCRYPTPROV, DWORD*, DWORD dwFlags);
+static BOOL (WINAPI *pCryptGenKey)(HCRYPTPROV, ALG_ID, DWORD, HCRYPTKEY*);
+static BOOL (WINAPI *pCryptDestroyKey)(HCRYPTKEY);
+static BOOL (WINAPI *pCryptDecrypt)(HCRYPTKEY, HCRYPTHASH, BOOL, DWORD, BYTE*, DWORD*);
+static BOOL (WINAPI *pCryptDeriveKey)(HCRYPTPROV, ALG_ID, HCRYPTHASH, DWORD, HCRYPTKEY*);
+static BOOL (WINAPI *pCryptDuplicateHash)(HCRYPTHASH, DWORD*, DWORD, HCRYPTHASH*);
+static BOOL (WINAPI *pCryptDuplicateKey)(HCRYPTKEY, DWORD*, DWORD, HCRYPTKEY*);
+static BOOL (WINAPI *pCryptEncrypt)(HCRYPTKEY, HCRYPTHASH, BOOL, DWORD, BYTE*, DWORD*, DWORD);
+static BOOL (WINAPI *pCryptExportKey)(HCRYPTKEY, HCRYPTKEY, DWORD, DWORD, BYTE*, DWORD*);
+static BOOL (WINAPI *pCryptGetHashParam)(HCRYPTHASH, DWORD, BYTE*, DWORD*, DWORD);
+static BOOL (WINAPI *pCryptGetKeyParam)(HCRYPTKEY, DWORD, BYTE*, DWORD*, DWORD);
+static BOOL (WINAPI *pCryptGetProvParam)(HCRYPTPROV, DWORD, BYTE*, DWORD*, DWORD);
+static BOOL (WINAPI *pCryptGetUserKey)(HCRYPTPROV, DWORD, HCRYPTKEY*);
+static BOOL (WINAPI *pCryptHashData)(HCRYPTHASH, BYTE*, DWORD, DWORD);
+static BOOL (WINAPI *pCryptHashSessionKey)(HCRYPTHASH, HCRYPTKEY, DWORD);
+static BOOL (WINAPI *pCryptImportKey)(HCRYPTPROV, BYTE*, DWORD, HCRYPTKEY, DWORD, HCRYPTKEY*);
+static BOOL (WINAPI *pCryptSignHashW)(HCRYPTHASH, DWORD, LPCWSTR, DWORD, BYTE*, DWORD*);
+static BOOL (WINAPI *pCryptSetHashParam)(HCRYPTKEY, DWORD, BYTE*, DWORD);
+static BOOL (WINAPI *pCryptSetKeyParam)(HCRYPTKEY, DWORD, BYTE*, DWORD);
+static BOOL (WINAPI *pCryptSetProvParam)(HCRYPTPROV, DWORD, BYTE*, DWORD);
+static BOOL (WINAPI *pCryptVerifySignatureW)(HCRYPTHASH, BYTE*, DWORD, HCRYPTKEY, LPCWSTR, DWORD);
+
+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");
+    }
+}
+
+static void init_environment(void)
+{
+       HCRYPTPROV hProv;
+
+       /* Ensure that container "wine_test_keyset" does exist */
+       if (!pCryptAcquireContextA(&hProv, szKeySet, szRsaBaseProv, PROV_RSA_FULL, 0))
+       {
+               pCryptAcquireContextA(&hProv, szKeySet, szRsaBaseProv, PROV_RSA_FULL, CRYPT_NEWKEYSET);
+       }
+       pCryptReleaseContext(hProv, 0);
+
+       /* Ensure that container "wine_test_keyset" does exist in default PROV_RSA_FULL type provider */
+       if (!pCryptAcquireContextA(&hProv, szKeySet, NULL, PROV_RSA_FULL, 0))
+       {
+               pCryptAcquireContextA(&hProv, szKeySet, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET);
+       }
+       pCryptReleaseContext(hProv, 0);
+
+       /* Ensure that container "wine_test_bad_keyset" does not exist. */
+       if (pCryptAcquireContextA(&hProv, szBadKeySet, szRsaBaseProv, PROV_RSA_FULL, 0))
+       {
+               pCryptReleaseContext(hProv, 0);
+               pCryptAcquireContextA(&hProv, szBadKeySet, szRsaBaseProv, PROV_RSA_FULL, CRYPT_DELETEKEYSET);
+       }
+}
+
+static void clean_up_environment(void)
+{
+       HCRYPTPROV hProv;
+
+       /* Remove container "wine_test_keyset" */
+       if (pCryptAcquireContextA(&hProv, szKeySet, szRsaBaseProv, PROV_RSA_FULL, 0))
+       {
+               pCryptReleaseContext(hProv, 0);
+               pCryptAcquireContextA(&hProv, szKeySet, szRsaBaseProv, PROV_RSA_FULL, CRYPT_DELETEKEYSET);
+       }
+
+       /* Remove container "wine_test_keyset" from default PROV_RSA_FULL type provider */
+       if (pCryptAcquireContextA(&hProv, szKeySet, NULL, PROV_RSA_FULL, 0))
+       {
+               pCryptReleaseContext(hProv, 0);
+               pCryptAcquireContextA(&hProv, szKeySet, NULL, PROV_RSA_FULL, CRYPT_DELETEKEYSET);
+       }
+}
+
+static void test_acquire_context(void)
+{
+       BOOL result;
+       HCRYPTPROV hProv;
+
+       /* 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());
+
+       result = pCryptAcquireContextA(&hProv, NULL, NULL, 1000, 0);
+       ok(!result && GetLastError()==NTE_BAD_PROV_TYPE, "%ld\n", GetLastError());
+
+       result = pCryptAcquireContextA(&hProv, NULL, NULL, NON_DEF_PROV_TYPE, 0);
+       ok(!result && GetLastError()==NTE_PROV_TYPE_NOT_DEF, "%ld\n", GetLastError());
+
+       result = pCryptAcquireContextA(&hProv, szKeySet, szNonExistentProv, PROV_RSA_FULL, 0);
+       ok(!result && GetLastError()==NTE_KEYSET_NOT_DEF, "%ld\n", GetLastError());
+
+       result = pCryptAcquireContextA(&hProv, szKeySet, szRsaBaseProv, NON_DEF_PROV_TYPE, 0);
+       ok(!result && GetLastError()==NTE_PROV_TYPE_NO_MATCH, "%ld\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());
+       */
+
+       /* 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)
+               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)
+               pCryptReleaseContext(hProv, 0);
+}
+
+static void test_incorrect_api_usage(void)
+{
+    BOOL result;
+    HCRYPTPROV hProv, hProv2;
+    HCRYPTHASH hHash, hHash2;
+    HCRYPTKEY hKey, hKey2;
+    BYTE temp;
+    DWORD dwLen, dwTemp;
+
+    /* 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
+     * robust here and returns an ERROR_INVALID_PARAMETER code.
+     */
+
+    result = pCryptAcquireContextA(&hProv, szBadKeySet, szRsaBaseProv,
+                                   PROV_RSA_FULL, CRYPT_NEWKEYSET);
+    ok (result, "%08lx\n", GetLastError());
+    if (!result) return;
+
+    result = pCryptCreateHash(hProv, CALG_SHA, 0, 0, &hHash);
+    ok (result, "%ld\n", GetLastError());
+    if (!result) return;
+
+    result = pCryptGenKey(hProv, CALG_RC4, 0, &hKey);
+    ok (result, "%ld\n", GetLastError());
+    if (!result) return;
+
+    result = pCryptGenKey(hProv, CALG_RC4, 0, &hKey2);
+    ok (result, "%ld\n", GetLastError());
+    if (!result) return;
+
+    result = pCryptDestroyKey(hKey2);
+    ok (result, "%ld\n", GetLastError());
+
+    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,
+                                   CRYPT_DELETEKEYSET);
+    ok (result, "%ld\n", GetLastError());
+    if (!result) return;
+
+    result = pCryptReleaseContext(hProv, 0);
+    ok (result, "%ld\n", GetLastError());
+    if (!result) return;
+
+    result = pCryptReleaseContext(hProv, 0);
+    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%ld\n", GetLastError());
+
+    result = pCryptGenRandom(hProv, 1, &temp);
+    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%ld\n", GetLastError());
+
+#ifdef CRASHES_ON_NT40
+    result = pCryptContextAddRef(hProv, NULL, 0);
+    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%ld\n", GetLastError());
+#endif
+
+    result = pCryptCreateHash(hProv, CALG_SHA, 0, 0, &hHash2);
+    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%ld\n", GetLastError());
+
+    dwLen = 1;
+    result = pCryptDecrypt(hKey, (HCRYPTHASH)NULL, TRUE, 0, &temp, &dwLen);
+    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%ld\n", GetLastError());
+
+    dwLen = 1;
+    result = pCryptEncrypt(hKey, (HCRYPTHASH)NULL, TRUE, 0, &temp, &dwLen, 1);
+    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%ld\n", GetLastError());
+
+    result = pCryptDeriveKey(hProv, CALG_RC4, hHash, 0, &hKey2);
+    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%ld\n", GetLastError());
+
+#ifdef CRASHES_ON_NT40
+    result = pCryptDuplicateHash(hHash, NULL, 0, &hHash2);
+    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%ld\n", GetLastError());
+
+    result = pCryptDuplicateKey(hKey, NULL, 0, &hKey2);
+    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%ld\n", GetLastError());
+#endif
+
+    dwLen = 1;
+    result = pCryptExportKey(hKey, (HCRYPTPROV)NULL, 0, 0, &temp, &dwLen);
+    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%ld\n", GetLastError());
+
+    result = pCryptGenKey(hProv, CALG_RC4, 0, &hKey2);
+    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%ld\n", GetLastError());
+
+    dwLen = 1;
+    result = pCryptGetHashParam(hHash, 0, &temp, &dwLen, 0);
+    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%ld\n", GetLastError());
+
+    dwLen = 1;
+    result = pCryptGetKeyParam(hKey, 0, &temp, &dwLen, 0);
+    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%ld\n", GetLastError());
+
+    dwLen = 1;
+    result = pCryptGetProvParam(hProv, 0, &temp, &dwLen, 0);
+    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%ld\n", GetLastError());
+
+    result = pCryptGetUserKey(hProv, 0, &hKey2);
+    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%ld\n", GetLastError());
+
+    result = pCryptHashData(hHash, &temp, 1, 0);
+    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%ld\n", GetLastError());
+
+    result = pCryptHashSessionKey(hHash, hKey, 0);
+    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%ld\n", GetLastError());
+
+    result = pCryptImportKey(hProv, &temp, 1, (HCRYPTKEY)NULL, 0, &hKey2);
+    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%ld\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());
+
+    result = pCryptSetKeyParam(hKey, 0, &temp, 1);
+    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%ld\n", GetLastError());
+
+    result = pCryptSetHashParam(hHash, 0, &temp, 1);
+    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%ld\n", GetLastError());
+
+    result = pCryptSetProvParam(hProv, 0, &temp, 1);
+    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%ld\n", GetLastError());
+
+    result = pCryptVerifySignatureW(hHash, &temp, 1, hKey, NULL, 0);
+    ok (!result && (GetLastError() == ERROR_INVALID_PARAMETER ||
+        GetLastError() == ERROR_CALL_NOT_IMPLEMENTED), "%ld\n", GetLastError());
+
+    result = pCryptDestroyHash(hHash);
+    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%ld\n", GetLastError());
+
+    result = pCryptDestroyKey(hKey);
+    ok (!result && GetLastError() == ERROR_INVALID_PARAMETER, "%ld\n", GetLastError());
+}
+
+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,
+                                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);
+
+       RegCloseKey(subkey);
+       RegCloseKey(hKey);
+
+       return TRUE;
+}
+
+static void test_enum_providers(void)
+{
+       /* expected results */
+       CHAR *pszProvName = NULL;
+       DWORD cbName;
+       DWORD dwType;
+       DWORD provCount;
+       DWORD dwIndex = 0;
+
+       /* actual results */
+       CHAR *provider = NULL;
+       DWORD providerLen;
+       DWORD type;
+       DWORD count;
+       BOOL result;
+       DWORD notNull = 5;
+       DWORD notZeroFlags = 5;
+
+       if(!pCryptEnumProvidersA)
+       {
+           trace("skipping CryptEnumProviders tests\n");
+           return;
+       }
+
+       if (!FindProvRegVals(dwIndex, &dwType, &pszProvName, &cbName, &provCount))
+               return;
+
+       /* check pdwReserved flag for NULL */
+       result = pCryptEnumProvidersA(dwIndex, &notNull, 0, &type, NULL, &providerLen);
+       ok(!result && GetLastError()==ERROR_INVALID_PARAMETER, "%ld\n", GetLastError());
+
+       /* check dwFlags == 0 */
+       result = pCryptEnumProvidersA(dwIndex, NULL, notZeroFlags, &type, NULL, &providerLen);
+       ok(!result && GetLastError()==NTE_BAD_FLAGS, "%ld\n", GetLastError());
+
+       /* alloc provider to half the size required
+        * cbName holds the size required */
+       providerLen = cbName / 2;
+       if (!(provider = ((LPSTR)LocalAlloc(LMEM_ZEROINIT, providerLen))))
+               return;
+
+       result = pCryptEnumProvidersA(dwIndex, NULL, 0, &type, provider, &providerLen);
+       ok(!result && GetLastError()==ERROR_MORE_DATA, "expected %i, got %ld\n",
+               ERROR_MORE_DATA, GetLastError());
+
+       LocalFree(provider);
+
+       /* 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;
+       while(pCryptEnumProvidersA(count++, NULL, 0, &type, NULL, &providerLen))
+               ;
+       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",
+                       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;
+
+       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);
+
+       LocalFree(provider);
+}
+
+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)++;
+       ch = *pszTypeName + strlen(*pszTypeName);
+       /* Convert "Type 000" to 0, etc/ */
+       *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))
+           return FALSE;
+
+       RegCloseKey(hSubKey);
+       RegCloseKey(hKey);
+
+       return TRUE;
+}
+
+static void test_enum_provider_types()
+{
+       /* expected values */
+       DWORD dwProvType;
+       LPSTR pszTypeName = NULL;
+       DWORD cbTypeName;
+       DWORD dwTypeCount;
+
+       /* actual values */
+       DWORD index = 0;
+       DWORD provType;
+       LPSTR typeName = NULL;
+       DWORD typeNameSize;
+       DWORD typeCount;
+       DWORD result;
+       DWORD notNull = 5;
+       DWORD notZeroFlags = 5;
+
+       if(!pCryptEnumProviderTypesA)
+       {
+           trace("skipping CryptEnumProviderTypes tests\n");
+           return;
+       }
+
+       if (!FindProvTypesRegVals(index, &dwProvType, &pszTypeName, &cbTypeName, &dwTypeCount))
+       {
+           trace("could not find provider types in registry, skipping the test\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",
+               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",
+               ERROR_INVALID_PARAMETER, GetLastError());
+
+       /* alloc provider type to half the size required
+        * cbTypeName holds the size required */
+       typeNameSize = cbTypeName / 2;
+       if (!(typeName = ((LPSTR)LocalAlloc(LMEM_ZEROINIT, typeNameSize))))
+               return;
+
+       /* This test fails under Win2k SP4:
+          result = TRUE, GetLastError() == 0xdeadbeef
+       SetLastError(0xdeadbeef);
+       result = pCryptEnumProviderTypesA(index, NULL, 0, &provType, typeName, &typeNameSize);
+       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
+        * 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);
+
+       /* 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",
+                       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);
+       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);
+       if (pszTypeName)
+           ok(!strcmp(pszTypeName, typeName), "expected %s, got %s\n", pszTypeName, typeName);
+       ok(typeNameSize==cbTypeName, "expected %ld, got %ld\n", cbTypeName, typeNameSize);
+
+       LocalFree(typeName);
+}
+
+static BOOL FindDfltProvRegVals(DWORD dwProvType, DWORD dwFlags, LPSTR *pszProvName, DWORD *pcbProvName)
+{
+       HKEY hKey;
+       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);
+       if (keyname)
+       {
+               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 (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 (GetLastError() != ERROR_MORE_DATA)
+                       SetLastError(NTE_PROV_TYPE_ENTRY_BAD);
+               return FALSE;
+       }
+
+       RegCloseKey(hKey);
+
+       return TRUE;
+}
+
+static void test_get_default_provider()
+{
+       /* 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;
+       LPSTR provName = NULL;
+       DWORD provNameSize;
+       DWORD result;
+       DWORD notNull = 5;
+
+       if(!pCryptGetDefaultProviderA)
+       {
+           trace("skipping CryptGetDefaultProvider tests\n");
+           return;
+       }
+
+       FindDfltProvRegVals(dwProvType, dwFlags, &pszProvName, &cbProvName);
+
+       /* check pdwReserved for NULL */
+       result = pCryptGetDefaultProviderA(provType, &notNull, flags, provName, &provNameSize);
+       ok(!result && GetLastError()==ERROR_INVALID_PARAMETER, "expected %i, got %ld\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",
+               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",
+               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",
+               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);
+       provNameSize = cbProvName;
+
+       if (!(provName = LocalAlloc(LMEM_ZEROINIT, provNameSize)))
+               return;
+
+       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);
+
+       LocalFree(provName);
+}
+
+static void test_set_provider_ex()
+{
+       DWORD result;
+       DWORD notNull = 5;
+
+       /* results */
+       LPSTR pszProvName = NULL;
+       DWORD cbProvName;
+
+       if(!pCryptGetDefaultProviderA || !pCryptSetProviderExA)
+       {
+           trace("skipping CryptSetProviderEx tests\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",
+               ERROR_INVALID_PARAMETER, GetLastError());
+
+       /* remove the default provider and then set it to MS_DEF_PROV/PROV_RSA_FULL */
+       result = pCryptSetProviderExA(MS_DEF_PROV, PROV_RSA_FULL, NULL, CRYPT_MACHINE_DEFAULT | CRYPT_DELETE_DEFAULT);
+       ok(result, "%ld\n", GetLastError());
+
+       result = pCryptSetProviderExA(MS_DEF_PROV, PROV_RSA_FULL, NULL, CRYPT_MACHINE_DEFAULT);
+       ok(result, "%ld\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)))
+               return;
+
+       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);
+
+       LocalFree(pszProvName);
+}
+
+START_TEST(crypt)
+{
+       init_function_pointers();
+       if(pCryptAcquireContextA && pCryptReleaseContext) {
+       init_environment();
+       test_acquire_context();
+       test_incorrect_api_usage();
+       clean_up_environment();
+       }
+
+       test_enum_providers();
+       test_enum_provider_types();
+       test_get_default_provider();
+       test_set_provider_ex();
+}
diff --git a/rostests/winetests/advapi32/crypt_lmhash.c b/rostests/winetests/advapi32/crypt_lmhash.c
new file mode 100644 (file)
index 0000000..e8e3eb4
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Unit tests for SystemFunction006 (LMHash?)
+ *
+ * Copyright 2004 Hans Leidekker
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <stdio.h>
+
+#include "wine/test.h"
+#include "windef.h"
+#include "winbase.h"
+
+typedef VOID (WINAPI *fnSystemFunction006)( PCSTR passwd, PSTR lmhash );
+fnSystemFunction006 pSystemFunction006;
+
+static void test_SystemFunction006()
+{
+    static unsigned char lmhash[16 + 1];
+
+    unsigned 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 };
+
+    pSystemFunction006( passwd, lmhash );
+
+    ok( !memcmp( lmhash, expect, sizeof(expect) ),
+        "lmhash: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
+        lmhash[0], lmhash[1], lmhash[2], lmhash[3], lmhash[4], lmhash[5],
+        lmhash[6], lmhash[7], lmhash[8], lmhash[9], lmhash[10], lmhash[11],
+        lmhash[12], lmhash[13], lmhash[14], lmhash[15] );
+}
+
+START_TEST(crypt_lmhash)
+{
+    HMODULE module;
+
+    if (!(module = LoadLibrary("advapi32.dll"))) return;
+
+    pSystemFunction006 = (fnSystemFunction006)GetProcAddress( module, "SystemFunction006" );
+
+    if (!pSystemFunction006) goto out;
+
+    if (pSystemFunction006)
+        test_SystemFunction006();
+
+out:
+    FreeLibrary( module );
+}
diff --git a/rostests/winetests/advapi32/crypt_md4.c b/rostests/winetests/advapi32/crypt_md4.c
new file mode 100644 (file)
index 0000000..cee8b7d
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Unit tests for MD4 functions
+ *
+ * Copyright 2004 Hans Leidekker
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <stdio.h>
+
+#include "wine/test.h"
+#include "windef.h"
+#include "winbase.h"
+#include "winerror.h"
+
+typedef struct
+{
+    unsigned int buf[4];
+    unsigned int i[2];
+    unsigned char in[64];
+    unsigned char digest[16];
+} MD4_CTX;
+
+typedef VOID (WINAPI *fnMD4Init)( MD4_CTX *ctx );
+typedef VOID (WINAPI *fnMD4Update)( MD4_CTX *ctx, const unsigned char *src, const int len );
+typedef VOID (WINAPI *fnMD4Final)( MD4_CTX *ctx );
+
+fnMD4Init pMD4Init;
+fnMD4Update pMD4Update;
+fnMD4Final pMD4Final;
+
+#define ctxcmp( a, b ) memcmp( (char*)a, (char*)b, FIELD_OFFSET( MD4_CTX, in ) )
+
+void test_md4_ctx()
+{
+    static unsigned char message[] =
+        "In our Life there's If"
+        "In our beliefs there's Lie"
+        "In our business there is Sin"
+        "In our bodies, there is Die";
+
+    int size = strlen( message );
+    HMODULE module;
+
+    MD4_CTX ctx;
+    MD4_CTX ctx_initialized =
+    {
+        { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 },
+        { 0, 0 }
+    };
+
+    MD4_CTX ctx_update1 =
+    {
+        { 0x5e592ef7, 0xbdcb1567, 0x2b626d17, 0x7d1198bd },
+        { 0x00000338, 0 }
+    };
+
+    MD4_CTX ctx_update2 =
+    {
+        { 0x05dcfd65, 0xb3711c0d, 0x9e3369c2, 0x903ead11 },
+        { 0x00000670, 0 }
+    };
+
+    unsigned char expect[16] =
+        { 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 );
+    ok( !ctxcmp( &ctx, &ctx_initialized ), "invalid initialization\n" );
+
+    pMD4Update( &ctx, message, size );
+    ok( !ctxcmp( &ctx, &ctx_update1 ), "update doesn't work correctly\n" );
+
+    pMD4Update( &ctx, message, size );
+    ok( !ctxcmp( &ctx, &ctx_update2 ), "update doesn't work correctly\n" );
+
+    pMD4Final( &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_md4)
+{
+    test_md4_ctx();
+}
diff --git a/rostests/winetests/advapi32/crypt_md5.c b/rostests/winetests/advapi32/crypt_md5.c
new file mode 100644 (file)
index 0000000..0e46e53
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Unit tests for MD5 functions
+ *
+ * Copyright 2004 Hans Leidekker
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <stdio.h>
+
+#include "wine/test.h"
+#include "windef.h"
+#include "winbase.h"
+#include "winerror.h"
+
+typedef struct
+{
+    unsigned int i[2];
+    unsigned int buf[4];
+    unsigned char in[64];
+    unsigned char digest[16];
+} MD5_CTX;
+
+typedef VOID (WINAPI *fnMD5Init)( MD5_CTX *ctx );
+typedef VOID (WINAPI *fnMD5Update)( MD5_CTX *ctx, const unsigned char *src, const int len );
+typedef VOID (WINAPI *fnMD5Final)( MD5_CTX *ctx );
+
+fnMD5Init pMD5Init;
+fnMD5Update pMD5Update;
+fnMD5Final pMD5Final;
+
+#define ctxcmp( a, b ) memcmp( (char*)a, (char*)b, FIELD_OFFSET( MD5_CTX, in ) )
+
+void test_md5_ctx()
+{
+    static unsigned char message[] =
+        "In our Life there's If"
+        "In our beliefs there's Lie"
+        "In our business there is Sin"
+        "In our bodies, there is Die";
+
+    int size = strlen( message );
+    HMODULE module;
+
+    MD5_CTX ctx;
+    MD5_CTX ctx_initialized =
+    {
+        { 0, 0 },
+        { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 }
+    };
+
+    MD5_CTX ctx_update1 =
+    {
+        { 0x00000338, 0 },
+        { 0x068cb64d, 0xb7a05790, 0x426979ee, 0xed67e221 }
+    };
+
+    MD5_CTX ctx_update2 =
+    {
+        { 0x00000670, 0 },
+        { 0x2f7afe58, 0xcc3e9315, 0x709c465c, 0xbf6414c8 }
+    };
+
+    unsigned char expect[16] =
+        { 0x43, 0x03, 0xdd, 0x8c, 0x60, 0xd9, 0x3a, 0x22,
+          0x0b, 0x28, 0xd0, 0xb2, 0x65, 0x93, 0xd0, 0x36 };
+
+    if (!(module = LoadLibrary( "advapi32.dll" ))) return;
+
+    pMD5Init = (fnMD5Init)GetProcAddress( module, "MD5Init" );
+    pMD5Update = (fnMD5Update)GetProcAddress( module, "MD5Update" );
+    pMD5Final = (fnMD5Final)GetProcAddress( module, "MD5Final" );
+
+    if (!pMD5Init || !pMD5Update || !pMD5Final) goto out;
+
+    memset( &ctx, 0, sizeof(ctx) );
+    pMD5Init( &ctx );
+    ok( !ctxcmp( &ctx, &ctx_initialized ), "invalid initialization\n" );
+
+    pMD5Update( &ctx, message, size );
+    ok( !ctxcmp( &ctx, &ctx_update1 ), "update doesn't work correctly\n" );
+
+    pMD5Update( &ctx, message, size );
+    ok( !ctxcmp( &ctx, &ctx_update2 ), "update doesn't work correctly\n" );
+
+    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)
+{
+    test_md5_ctx();
+}
diff --git a/rostests/winetests/advapi32/crypt_sha.c b/rostests/winetests/advapi32/crypt_sha.c
new file mode 100644 (file)
index 0000000..5cf6fdb
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Unit tests for SHA functions
+ *
+ * Copyright (c) 2004 Filip Navara
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winerror.h"
+
+#include "wine/test.h"
+
+typedef struct {
+   ULONG Unknown[6];
+   ULONG State[5];
+   ULONG Count[2];
+   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;
+   static const char test_buffer[] = "In our Life there's If"
+                       "In our beliefs there's Lie"
+                       "In our business there is Sin"
+                       "In our bodies, there is Die";
+   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");
+   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;
+
+   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)
+{
+    test_sha_ctx();
+}
diff --git a/rostests/winetests/advapi32/registry.c b/rostests/winetests/advapi32/registry.c
new file mode 100644 (file)
index 0000000..6f7d1f0
--- /dev/null
@@ -0,0 +1,460 @@
+/*
+ * Unit tests for registry functions
+ *
+ * Copyright (c) 2002 Alexandre Julliard
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <assert.h>
+#include <stdarg.h>
+#include "wine/test.h"
+#include "windef.h"
+#include "winbase.h"
+#include "winreg.h"
+#include "winerror.h"
+
+static HKEY hkey_main;
+
+static const char * sTestpath1 = "%LONGSYSTEMVAR%\\subdir1";
+static const char * sTestpath2 = "%FOO%\\subdir1";
+
+/* delete key and all its subkeys */
+static DWORD delete_key( HKEY hkey )
+{
+    char name[MAX_PATH];
+    DWORD ret;
+
+    while (!(ret = RegEnumKeyA(hkey, 0, name, sizeof(name))))
+    {
+        HKEY tmp;
+        if (!(ret = RegOpenKeyExA( hkey, name, 0, KEY_ENUMERATE_SUB_KEYS, &tmp )))
+        {
+            ret = delete_key( tmp );
+            RegCloseKey( tmp );
+        }
+        if (ret) break;
+    }
+    if (ret != ERROR_NO_MORE_ITEMS) return ret;
+    RegDeleteKeyA( hkey, "" );
+    return 0;
+}
+
+static void setup_main_key(void)
+{
+    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 create_test_entries(void)
+{
+    SetEnvironmentVariableA("LONGSYSTEMVAR", "bar");
+    SetEnvironmentVariableA("FOO", "ImARatherLongButIndeedNeededString");
+
+    ok(!RegSetValueExA(hkey_main,"Test1",0,REG_EXPAND_SZ, sTestpath1, strlen(sTestpath1)+1),
+        "RegSetValueExA failed\n");
+    ok(!RegSetValueExA(hkey_main,"Test2",0,REG_SZ, sTestpath1, strlen(sTestpath1)+1),
+        "RegSetValueExA failed\n");
+    ok(!RegSetValueExA(hkey_main,"Test3",0,REG_EXPAND_SZ, sTestpath2, strlen(sTestpath2)+1),
+        "RegSetValueExA failed\n");
+}
+
+static void test_enum_value(void)
+{
+    DWORD res;
+    HKEY test_key;
+    char value[20], data[20];
+    WCHAR valueW[20], dataW[20];
+    DWORD val_count, data_count, type;
+    static const WCHAR foobarW[] = {'f','o','o','b','a','r',0};
+    static const WCHAR testW[] = {'T','e','s','t',0};
+    static const WCHAR xxxW[] = {'x','x','x','x','x','x','x','x',0};
+
+    /* 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);
+
+    /* 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 );
+    else
+        ok( !res, "RegSetValueExA returned %ld\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 );
+    res = RegSetValueExA( test_key, "Test", 0, REG_BINARY, NULL, 0 );
+    ok( ERROR_SUCCESS == res || ERROR_INVALID_PARAMETER == res, "RegSetValueExA returned %ld\n", res );
+
+    res = RegSetValueExA( test_key, "Test", 0, REG_SZ, (BYTE *)"foobar", 7 );
+    ok( res == 0, "RegSetValueExA failed error %ld\n", res );
+
+    /* overflow both name and data */
+    val_count = 2;
+    data_count = 2;
+    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 );
+    ok( !strcmp( value, "xxxxxxxxxx" ), "value set to '%s'\n", value );
+    ok( !strcmp( data, "xxxxxxxxxx" ), "data set to '%s'\n", data );
+
+    /* overflow name */
+    val_count = 3;
+    data_count = 20;
+    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 );
+    /* 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
+
+    /* overflow empty name */
+    val_count = 0;
+    data_count = 20;
+    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 );
+    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
+
+    /* overflow data */
+    val_count = 20;
+    data_count = 2;
+    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 );
+    ok( !strcmp( value, "xxxxxxxxxx" ), "value set to '%s'\n", value );
+    ok( !strcmp( data, "xxxxxxxxxx" ), "data set to '%s'\n", data );
+
+    /* no overflow */
+    val_count = 20;
+    data_count = 20;
+    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 );
+    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);
+    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 );
+
+    /* overflow both name and data */
+    val_count = 2;
+    data_count = 2;
+    type = 1234;
+    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( !memcmp( valueW, xxxW, sizeof(xxxW) ), "value modified\n" );
+    ok( !memcmp( dataW, xxxW, sizeof(xxxW) ), "data modified\n" );
+
+    /* overflow name */
+    val_count = 3;
+    data_count = 20;
+    type = 1234;
+    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( !memcmp( valueW, xxxW, sizeof(xxxW) ), "value modified\n" );
+    ok( !memcmp( dataW, xxxW, sizeof(xxxW) ), "data modified\n" );
+
+    /* overflow data */
+    val_count = 20;
+    data_count = 2;
+    type = 1234;
+    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( !memcmp( valueW, testW, sizeof(testW) ), "value is not 'Test'\n" );
+    ok( !memcmp( dataW, xxxW, sizeof(xxxW) ), "data modified\n" );
+
+    /* no overflow */
+    val_count = 20;
+    data_count = 20;
+    type = 1234;
+    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( !memcmp( valueW, testW, sizeof(testW) ), "value is not 'Test'\n" );
+    ok( !memcmp( dataW, foobarW, sizeof(foobarW) ), "data is not 'foobar'\n" );
+}
+
+static void test_query_value_ex()
+{
+    DWORD ret;
+    DWORD size;
+    DWORD type;
+
+    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);
+}
+
+static void test_reg_open_key()
+{
+    DWORD ret = 0;
+    HKEY hkResult = NULL;
+    HKEY hkPreserve = NULL;
+
+    /* successful open */
+    ret = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Test", &hkResult);
+    ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\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");
+
+    /* only send NULL hKey
+     * the value of hkResult remains unchanged
+     */
+    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);
+    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);
+}
+
+static void test_reg_close_key()
+{
+    DWORD ret = 0;
+    HKEY hkHandle;
+
+    /* successfully close key
+     * hkHandle remains changed after call to RegCloseKey
+     */
+    ret = RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Test", &hkHandle);
+    ret = RegCloseKey(hkHandle);
+    ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\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);
+
+    /* 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);
+}
+
+static void test_reg_delete_key()
+{
+    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); 
+  
+}
+
+static void test_reg_save_key()
+{
+    DWORD ret;
+
+    ret = RegSaveKey(hkey_main, "saved_key", NULL);
+    ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
+}
+
+static void test_reg_load_key()
+{
+    DWORD ret;
+    HKEY hkHandle;
+
+    ret = RegLoadKey(HKEY_LOCAL_MACHINE, "Test", "saved_key");
+    ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
+
+    ret = RegOpenKey(HKEY_LOCAL_MACHINE, "Test", &hkHandle);
+    ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
+
+    RegCloseKey(hkHandle);
+}
+
+static void test_reg_unload_key()
+{
+    DWORD ret;
+
+    ret = RegUnLoadKey(HKEY_LOCAL_MACHINE, "Test");
+    ok(ret == ERROR_SUCCESS, "expected ERROR_SUCCESS, got %ld\n", ret);
+
+    DeleteFile("saved_key");
+}
+
+static BOOL set_privileges(LPCSTR privilege, BOOL set)
+{
+    TOKEN_PRIVILEGES tp;
+    HANDLE hToken;
+    LUID luid;
+
+    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
+        return FALSE;
+
+    if(!LookupPrivilegeValue(NULL, privilege, &luid))
+    {
+        CloseHandle(hToken);
+        return FALSE;
+    }
+
+    tp.PrivilegeCount = 1;
+    tp.Privileges[0].Luid = luid;
+
+    if (set)
+        tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+    else
+        tp.Privileges[0].Attributes = 0;
+
+    AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL);
+    if (GetLastError() != ERROR_SUCCESS)
+    {
+        CloseHandle(hToken);
+        return FALSE;
+    }
+
+    CloseHandle(hToken);
+    return TRUE;
+}
+
+START_TEST(registry)
+{
+    setup_main_key();
+    create_test_entries();
+    test_enum_value();
+    test_query_value_ex();
+    test_reg_open_key();
+    test_reg_close_key();
+    test_reg_delete_key();
+
+    /* SaveKey/LoadKey require the SE_BACKUP_NAME privilege to be set */
+    if (set_privileges(SE_BACKUP_NAME, TRUE) &&
+        set_privileges(SE_RESTORE_NAME, TRUE))
+    {
+        test_reg_save_key();
+        test_reg_load_key();
+        test_reg_unload_key();
+
+        set_privileges(SE_BACKUP_NAME, FALSE);
+        set_privileges(SE_RESTORE_NAME, FALSE);
+    }
+    /* cleanup */
+    delete_key( hkey_main );
+}
diff --git a/rostests/winetests/advapi32/security.c b/rostests/winetests/advapi32/security.c
new file mode 100644 (file)
index 0000000..d47366f
--- /dev/null
@@ -0,0 +1,446 @@
+/*
+ * Unit tests for security functions
+ *
+ * Copyright (c) 2004 Mike McCormack
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#define _WIN32_WINNT 0x0501
+
+#include <stdio.h>
+
+#include "wine/test.h"
+#include "windef.h"
+#include "winbase.h"
+#include "winerror.h"
+#include "aclapi.h"
+#include "winnt.h"
+
+typedef BOOL (WINAPI *fnBuildTrusteeWithSidA)( TRUSTEE *trustee, PSID psid );
+typedef BOOL (WINAPI *fnBuildTrusteeWithNameA)( TRUSTEE *trustee, LPSTR str );
+typedef BOOL (WINAPI *fnConvertSidToStringSidA)( PSID pSid, LPSTR *str );
+typedef BOOL (WINAPI *fnConvertStringSidToSidA)( LPCSTR str, PSID pSid );
+typedef BOOL (WINAPI *fnGetFileSecurityA)(LPCSTR, SECURITY_INFORMATION,
+                                          PSECURITY_DESCRIPTOR, DWORD, LPDWORD);
+
+static HMODULE hmod;
+
+fnBuildTrusteeWithSidA   pBuildTrusteeWithSidA;
+fnBuildTrusteeWithNameA  pBuildTrusteeWithNameA;
+fnConvertSidToStringSidA pConvertSidToStringSidA;
+fnConvertStringSidToSidA pConvertStringSidToSidA;
+fnGetFileSecurityA pGetFileSecurityA;
+
+struct sidRef
+{
+    SID_IDENTIFIER_AUTHORITY auth;
+    const char *refStr;
+};
+
+static void init(void)
+{
+    hmod = GetModuleHandle("advapi32.dll");
+}
+
+void test_sid()
+{
+    struct sidRef refs[] = {
+     { { {0x00,0x00,0x33,0x44,0x55,0x66} }, "S-1-860116326-1" },
+     { { {0x00,0x00,0x01,0x02,0x03,0x04} }, "S-1-16909060-1"  },
+     { { {0x00,0x00,0x00,0x01,0x02,0x03} }, "S-1-66051-1"     },
+     { { {0x00,0x00,0x00,0x00,0x01,0x02} }, "S-1-258-1"       },
+     { { {0x00,0x00,0x00,0x00,0x00,0x02} }, "S-1-2-1"         },
+     { { {0x00,0x00,0x00,0x00,0x00,0x0c} }, "S-1-12-1"        },
+    };
+    const char noSubAuthStr[] = "S-1-5";
+    unsigned int i;
+    PSID psid = NULL;
+    BOOL r;
+    LPSTR str = NULL;
+
+    pConvertSidToStringSidA = (fnConvertSidToStringSidA)
+                    GetProcAddress( hmod, "ConvertSidToStringSidA" );
+    if( !pConvertSidToStringSidA )
+        return;
+    pConvertStringSidToSidA = (fnConvertStringSidToSidA)
+                    GetProcAddress( hmod, "ConvertStringSidToSidA" );
+    if( !pConvertStringSidToSidA )
+        return;
+
+    r = pConvertStringSidToSidA( NULL, NULL );
+    ok( !r, "expected failure with NULL parameters\n" );
+    if( GetLastError() == ERROR_CALL_NOT_IMPLEMENTED )
+        return;
+    ok( GetLastError() == ERROR_INVALID_PARAMETER,
+     "expected GetLastError() is ERROR_INVALID_PARAMETER, got %ld\n",
+     GetLastError() );
+
+    r = pConvertStringSidToSidA( refs[0].refStr, NULL );
+    ok( !r && GetLastError() == ERROR_INVALID_PARAMETER,
+     "expected GetLastError() is ERROR_INVALID_PARAMETER, got %ld\n",
+     GetLastError() );
+
+    r = pConvertStringSidToSidA( NULL, &str );
+    ok( !r && GetLastError() == ERROR_INVALID_PARAMETER,
+     "expected GetLastError() is ERROR_INVALID_PARAMETER, got %ld\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",
+     GetLastError() );
+
+    for( i = 0; i < sizeof(refs) / sizeof(refs[0]); i++ )
+    {
+        PISID pisid;
+
+        r = AllocateAndInitializeSid( &refs[i].auth, 1,1,0,0,0,0,0,0,0,
+         &psid );
+        ok( r, "failed to allocate sid\n" );
+        r = pConvertSidToStringSidA( psid, &str );
+        ok( r, "failed to convert sid\n" );
+        if (r)
+        {
+            ok( !strcmp( str, refs[i].refStr ),
+                "incorrect sid, expected %s, got %s\n", refs[i].refStr, str );
+            LocalFree( str );
+        }
+        if( psid )
+            FreeSid( psid );
+
+        r = pConvertStringSidToSidA( refs[i].refStr, &psid );
+        ok( r, "failed to parse sid string\n" );
+        pisid = (PISID)psid;
+        ok( pisid &&
+         !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",
+         refs[i].refStr,
+         MAKEWORD( pisid->IdentifierAuthority.Value[1],
+         pisid->IdentifierAuthority.Value[0] ),
+         MAKELONG( MAKEWORD( pisid->IdentifierAuthority.Value[5],
+         pisid->IdentifierAuthority.Value[4] ),
+         MAKEWORD( pisid->IdentifierAuthority.Value[3],
+         pisid->IdentifierAuthority.Value[2] ) ),
+         MAKEWORD( refs[i].auth.Value[1], refs[i].auth.Value[0] ),
+         MAKELONG( MAKEWORD( refs[i].auth.Value[5], refs[i].auth.Value[4] ),
+         MAKEWORD( refs[i].auth.Value[3], refs[i].auth.Value[2] ) ) );
+        if( psid )
+            LocalFree( psid );
+    }
+}
+
+void test_trustee()
+{
+    TRUSTEE trustee;
+    PSID psid;
+    LPSTR str = "2jjj";
+
+    SID_IDENTIFIER_AUTHORITY auth = { {0x11,0x22,0,0,0, 0} };
+
+    pBuildTrusteeWithSidA = (fnBuildTrusteeWithSidA)
+                    GetProcAddress( hmod, "BuildTrusteeWithSidA" );
+    pBuildTrusteeWithNameA = (fnBuildTrusteeWithNameA)
+                    GetProcAddress( hmod, "BuildTrusteeWithNameA" );
+    if( !pBuildTrusteeWithSidA || !pBuildTrusteeWithNameA)
+        return;
+
+    if ( ! AllocateAndInitializeSid( &auth, 1, 42, 0,0,0,0,0,0,0,&psid ) )
+    {
+        trace( "failed to init SID\n" );
+       return;
+    }
+
+    memset( &trustee, 0xff, sizeof trustee );
+    pBuildTrusteeWithSidA( &trustee, psid );
+
+    ok( trustee.pMultipleTrustee == NULL, "pMultipleTrustee wrong\n");
+    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" );
+    FreeSid( psid );
+
+    /* test BuildTrusteeWithNameA */
+    memset( &trustee, 0xff, sizeof trustee );
+    pBuildTrusteeWithNameA( &trustee, str );
+
+    ok( trustee.pMultipleTrustee == NULL, "pMultipleTrustee wrong\n");
+    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" );
+}
+
+/* If the first isn't defined, assume none is */
+#ifndef SE_MIN_WELL_KNOWN_PRIVILEGE
+#define SE_MIN_WELL_KNOWN_PRIVILEGE       2L
+#define SE_CREATE_TOKEN_PRIVILEGE         2L
+#define SE_ASSIGNPRIMARYTOKEN_PRIVILEGE   3L
+#define SE_LOCK_MEMORY_PRIVILEGE          4L
+#define SE_INCREASE_QUOTA_PRIVILEGE       5L
+#define SE_MACHINE_ACCOUNT_PRIVILEGE      6L
+#define SE_TCB_PRIVILEGE                  7L
+#define SE_SECURITY_PRIVILEGE             8L
+#define SE_TAKE_OWNERSHIP_PRIVILEGE       9L
+#define SE_LOAD_DRIVER_PRIVILEGE         10L
+#define SE_SYSTEM_PROFILE_PRIVILEGE      11L
+#define SE_SYSTEMTIME_PRIVILEGE          12L
+#define SE_PROF_SINGLE_PROCESS_PRIVILEGE 13L
+#define SE_INC_BASE_PRIORITY_PRIVILEGE   14L
+#define SE_CREATE_PAGEFILE_PRIVILEGE     15L
+#define SE_CREATE_PERMANENT_PRIVILEGE    16L
+#define SE_BACKUP_PRIVILEGE              17L
+#define SE_RESTORE_PRIVILEGE             18L
+#define SE_SHUTDOWN_PRIVILEGE            19L
+#define SE_DEBUG_PRIVILEGE               20L
+#define SE_AUDIT_PRIVILEGE               21L
+#define SE_SYSTEM_ENVIRONMENT_PRIVILEGE  22L
+#define SE_CHANGE_NOTIFY_PRIVILLEGE      23L
+#define SE_REMOTE_SHUTDOWN_PRIVILEGE     24L
+#define SE_UNDOCK_PRIVILEGE              25L
+#define SE_SYNC_AGENT_PRIVILEGE          26L
+#define SE_ENABLE_DELEGATION_PRIVILEGE   27L
+#define SE_MANAGE_VOLUME_PRIVILEGE       28L
+#define SE_IMPERSONATE_PRIVILEGE         29L
+#define SE_CREATE_GLOBAL_PRIVILEGE       30L
+#define SE_MAX_WELL_KNOWN_PRIVILEGE      SE_CREATE_GLOBAL_PRIVILEGE
+#endif /* ndef SE_MIN_WELL_KNOWN_PRIVILEGE */
+
+static void test_allocateLuid(void)
+{
+    BOOL (WINAPI *pAllocateLocallyUniqueId)(PLUID);
+    LUID luid1, luid2;
+    BOOL ret;
+
+    pAllocateLocallyUniqueId = (void*)GetProcAddress(hmod, "AllocateLocallyUniqueId");
+    if (!pAllocateLocallyUniqueId) return;
+
+    ret = pAllocateLocallyUniqueId(&luid1);
+    if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
+        return;
+
+    ok(ret,
+     "AllocateLocallyUniqueId failed: %ld\n", GetLastError());
+    ret = pAllocateLocallyUniqueId(&luid2);
+    ok( ret,
+     "AllocateLocallyUniqueId failed: %ld\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",
+     GetLastError());
+}
+
+static void test_lookupPrivilegeName(void)
+{
+    BOOL (WINAPI *pLookupPrivilegeNameA)(LPSTR, PLUID, LPSTR, LPDWORD);
+    char buf[MAX_PATH]; /* arbitrary, seems long enough */
+    DWORD cchName = sizeof(buf);
+    LUID luid = { 0, 0 };
+    LONG i;
+    BOOL ret;
+
+    /* check whether it's available first */
+    pLookupPrivilegeNameA = (void*)GetProcAddress(hmod, "LookupPrivilegeNameA");
+    if (!pLookupPrivilegeNameA) return;
+    luid.LowPart = SE_CREATE_TOKEN_PRIVILEGE;
+    ret = pLookupPrivilegeNameA(NULL, &luid, buf, &cchName);
+    if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
+        return;
+
+    /* check with a short buffer */
+    cchName = 0;
+    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",
+     GetLastError());
+    ok(cchName == strlen("SeCreateTokenPrivilege") + 1,
+     "LookupPrivilegeNameA returned an incorrect required length for\n"
+     "SeCreateTokenPrivilege (got %ld, expected %d)\n", cchName,
+     strlen("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,
+     (int)strlen("SeCreateTokenPrivilege"));
+    /* check known values */
+    for (i = SE_MIN_WELL_KNOWN_PRIVILEGE; i < SE_MAX_WELL_KNOWN_PRIVILEGE; i++)
+    {
+        luid.LowPart = i;
+        cchName = sizeof(buf);
+        ret = pLookupPrivilegeNameA(NULL, &luid, buf, &cchName);
+        ok( ret || GetLastError() == ERROR_NO_SUCH_PRIVILEGE,
+         "LookupPrivilegeNameA(0.%ld) failed: %ld\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",
+     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",
+     GetLastError());
+}
+
+struct NameToLUID
+{
+    const char *name;
+    DWORD lowPart;
+};
+
+static void test_lookupPrivilegeValue(void)
+{
+    static const struct NameToLUID privs[] = {
+     { "SeCreateTokenPrivilege", SE_CREATE_TOKEN_PRIVILEGE },
+     { "SeAssignPrimaryTokenPrivilege", SE_ASSIGNPRIMARYTOKEN_PRIVILEGE },
+     { "SeLockMemoryPrivilege", SE_LOCK_MEMORY_PRIVILEGE },
+     { "SeIncreaseQuotaPrivilege", SE_INCREASE_QUOTA_PRIVILEGE },
+     { "SeMachineAccountPrivilege", SE_MACHINE_ACCOUNT_PRIVILEGE },
+     { "SeTcbPrivilege", SE_TCB_PRIVILEGE },
+     { "SeSecurityPrivilege", SE_SECURITY_PRIVILEGE },
+     { "SeTakeOwnershipPrivilege", SE_TAKE_OWNERSHIP_PRIVILEGE },
+     { "SeLoadDriverPrivilege", SE_LOAD_DRIVER_PRIVILEGE },
+     { "SeSystemProfilePrivilege", SE_SYSTEM_PROFILE_PRIVILEGE },
+     { "SeSystemtimePrivilege", SE_SYSTEMTIME_PRIVILEGE },
+     { "SeProfileSingleProcessPrivilege", SE_PROF_SINGLE_PROCESS_PRIVILEGE },
+     { "SeIncreaseBasePriorityPrivilege", SE_INC_BASE_PRIORITY_PRIVILEGE },
+     { "SeCreatePagefilePrivilege", SE_CREATE_PAGEFILE_PRIVILEGE },
+     { "SeCreatePermanentPrivilege", SE_CREATE_PERMANENT_PRIVILEGE },
+     { "SeBackupPrivilege", SE_BACKUP_PRIVILEGE },
+     { "SeRestorePrivilege", SE_RESTORE_PRIVILEGE },
+     { "SeShutdownPrivilege", SE_SHUTDOWN_PRIVILEGE },
+     { "SeDebugPrivilege", SE_DEBUG_PRIVILEGE },
+     { "SeAuditPrivilege", SE_AUDIT_PRIVILEGE },
+     { "SeSystemEnvironmentPrivilege", SE_SYSTEM_ENVIRONMENT_PRIVILEGE },
+     { "SeChangeNotifyPrivilege", SE_CHANGE_NOTIFY_PRIVILLEGE },
+     { "SeRemoteShutdownPrivilege", SE_REMOTE_SHUTDOWN_PRIVILEGE },
+     { "SeUndockPrivilege", SE_UNDOCK_PRIVILEGE },
+     { "SeSyncAgentPrivilege", SE_SYNC_AGENT_PRIVILEGE },
+     { "SeEnableDelegationPrivilege", SE_ENABLE_DELEGATION_PRIVILEGE },
+     { "SeManageVolumePrivilege", SE_MANAGE_VOLUME_PRIVILEGE },
+     { "SeImpersonatePrivilege", SE_IMPERSONATE_PRIVILEGE },
+     { "SeCreateGlobalPrivilege", SE_CREATE_GLOBAL_PRIVILEGE },
+    };
+    BOOL (WINAPI *pLookupPrivilegeValueA)(LPCSTR, LPCSTR, PLUID);
+    int i;
+    LUID luid;
+    BOOL ret;
+
+    /* check whether it's available first */
+    pLookupPrivilegeValueA = (void*)GetProcAddress(hmod, "LookupPrivilegeValueA");
+    if (!pLookupPrivilegeValueA) return;
+    ret = pLookupPrivilegeValueA(NULL, "SeCreateTokenPrivilege", &luid);
+    if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
+        return;
+
+    /* 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",
+     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",
+     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",
+     GetLastError());
+    /* check case insensitive */
+    ret = pLookupPrivilegeValueA(NULL, "sEcREATEtOKENpRIVILEGE", &luid);
+    ok( ret,
+     "LookupPrivilegeValueA(NULL, sEcREATEtOKENpRIVILEGE, &luid) failed: %ld\n",
+     GetLastError());
+    for (i = 0; i < sizeof(privs) / sizeof(privs[0]); i++)
+    {
+        /* Not all privileges are implemented on all Windows versions, so
+         * don't worry if the call fails
+         */
+        if (pLookupPrivilegeValueA(NULL, privs[i].name, &luid))
+        {
+            ok(luid.LowPart == privs[i].lowPart,
+             "LookupPrivilegeValueA returned an invalid LUID for %s\n",
+             privs[i].name);
+        }
+    }
+}
+
+static void test_luid(void)
+{
+    test_allocateLuid();
+    test_lookupPrivilegeName();
+    test_lookupPrivilegeValue();
+}
+
+static void test_FileSecurity(void)
+{
+    char directory[MAX_PATH];
+    DWORD retval, outSize;
+    BOOL result;
+    BYTE buffer[0x40];
+
+    pGetFileSecurityA = (fnGetFileSecurityA)
+                    GetProcAddress( hmod, "GetFileSecurityA" );
+    if( !pGetFileSecurityA )
+        return;
+
+    retval = GetTempPathA(sizeof(directory), directory);
+    if (!retval) {
+        trace("GetTempPathA failed\n");
+        return;
+    }
+
+    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");
+    ok( (GetLastError() == ERROR_FILE_NOT_FOUND ) ||
+        (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) ,
+        "last error ERROR_FILE_NOT_FOUND / ERROR_CALL_NOT_IMPLEMENTED (98) "
+        "expected, got %ld\n", GetLastError());
+}
+
+START_TEST(security)
+{
+    init();
+    if (!hmod) return;
+    test_sid();
+    test_trustee();
+    test_luid();
+    test_FileSecurity();
+}
diff --git a/rostests/winetests/advapi32/testlist.c b/rostests/winetests/advapi32/testlist.c
new file mode 100644 (file)
index 0000000..3ccabd8
--- /dev/null
@@ -0,0 +1,29 @@
+/* Automatically generated file; DO NOT EDIT!! */
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+#define STANDALONE
+#include "wine/test.h"
+
+extern void func_crypt(void);
+extern void func_crypt_lmhash(void);
+extern void func_crypt_md4(void);
+extern void func_crypt_md5(void);
+extern void func_crypt_sha(void);
+extern void func_lsa(void);
+extern void func_registry(void);
+extern void func_security(void);
+
+const struct test winetest_testlist[] =
+{
+/*    { "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 },
+    { "security", func_security },
+    { 0, 0 }
+};
diff --git a/rostests/winetests/cabinet/cabinet.rbuild b/rostests/winetests/cabinet/cabinet.rbuild
new file mode 100644 (file)
index 0000000..e87353b
--- /dev/null
@@ -0,0 +1,9 @@
+<module name="cabinet_winetest" type="win32cui" installbase="bin" installname="cabinet_winetest.exe" allowwarnings="true">
+    <include base="cabinet_winetest">.</include>
+    <define name="__USE_W32API" />
+    <library>cabinet</library>
+    <library>kernel32</library>
+    <library>ntdll</library>
+    <file>extract.c</file>
+    <file>testlist.c</file>
+</module>
diff --git a/rostests/winetests/cabinet/extract.c b/rostests/winetests/cabinet/extract.c
new file mode 100644 (file)
index 0000000..a108c92
--- /dev/null
@@ -0,0 +1,388 @@
+/*
+ * Unit tests for cabinet.dll extract functions
+ *
+ * Copyright (C) 2006 James Hawkins
+ *
+ * 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 <stdio.h>
+#include <windows.h>
+#include <fci.h>
+#include "wine/test.h"
+
+/* make the max size large so there is only one cab file */
+#define MEDIA_SIZE          999999999
+#define FOLDER_THRESHOLD    900000
+
+/* The following defintions were copied from dlls/cabinet/cabinet.h
+ * because they are undocumented in windows.
+ */
+
+/* EXTRACTdest flags */
+#define EXTRACT_FILLFILELIST  0x00000001
+#define EXTRACT_EXTRACTFILES  0x00000002
+
+struct ExtractFileList {
+    LPSTR  filename;
+    struct ExtractFileList *next;
+    BOOL   unknown;  /* always 1L */
+};
+
+/* the first parameter of the function extract */
+typedef struct {
+    long   result1;          /* 0x000 */
+    long   unknown1[3];      /* 0x004 */
+    struct ExtractFileList *filelist; /* 0x010 */
+    long   filecount;        /* 0x014 */
+    long   flags;            /* 0x018 */
+    char   directory[0x104]; /* 0x01c */
+    char   lastfile[0x20c];  /* 0x120 */
+} EXTRACTDEST;
+
+/* function pointers */
+HMODULE hCabinet;
+static HRESULT (WINAPI *pExtract)(EXTRACTDEST*, LPCSTR);
+
+CHAR CURR_DIR[MAX_PATH];
+
+static void init_function_pointers(void)
+{
+    hCabinet = LoadLibraryA("cabinet.dll");
+
+    if (hCabinet)
+    {
+        pExtract = (void *)GetProcAddress(hCabinet, "Extract");
+    }
+}
+
+/* creates a file with the specified name for tests */
+static void createTestFile(const CHAR *name)
+{
+    HANDLE file;
+    DWORD written;
+
+    file = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
+    ok(file != INVALID_HANDLE_VALUE, "Failure to open file %s\n", name);
+    WriteFile(file, name, strlen(name), &written, NULL);
+    WriteFile(file, "\n", strlen("\n"), &written, NULL);
+    CloseHandle(file);
+}
+
+static void create_test_files(void)
+{
+    int len;
+
+    GetCurrentDirectoryA(MAX_PATH, CURR_DIR);
+    len = lstrlenA(CURR_DIR);
+
+    if(len && (CURR_DIR[len-1] == '\\'))
+        CURR_DIR[len-1] = 0;
+
+    createTestFile("a.txt");
+    createTestFile("b.txt");
+    CreateDirectoryA("testdir", NULL);
+    createTestFile("testdir\\c.txt");
+    createTestFile("testdir\\d.txt");
+    CreateDirectoryA("dest", NULL);
+}
+
+static void delete_test_files(void)
+{
+    DeleteFileA("a.txt");
+    DeleteFileA("b.txt");
+    DeleteFileA("testdir\\c.txt");
+    DeleteFileA("testdir\\d.txt");
+    RemoveDirectoryA("testdir");
+
+    DeleteFileA("extract.cab");
+}
+
+/* the FCI callbacks */
+
+static void *mem_alloc(ULONG cb)
+{
+    return HeapAlloc(GetProcessHeap(), 0, cb);
+}
+
+static void mem_free(void *memory)
+{
+    HeapFree(GetProcessHeap(), 0, memory);
+}
+
+static BOOL get_next_cabinet(PCCAB pccab, ULONG  cbPrevCab, void *pv)
+{
+    return TRUE;
+}
+
+static long progress(UINT typeStatus, ULONG cb1, ULONG cb2, void *pv)
+{
+    return 0;
+}
+
+static int file_placed(PCCAB pccab, char *pszFile, long cbFile,
+                       BOOL fContinuation, void *pv)
+{
+    return 0;
+}
+
+static INT_PTR fci_open(char *pszFile, int oflag, int pmode, int *err, void *pv)
+{
+    HANDLE handle;
+    DWORD dwAccess = 0;
+    DWORD dwShareMode = 0;
+    DWORD dwCreateDisposition = OPEN_EXISTING;
+    
+    dwAccess = GENERIC_READ | GENERIC_WRITE;
+    dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
+
+    if (GetFileAttributesA(pszFile) != INVALID_FILE_ATTRIBUTES)
+        dwCreateDisposition = OPEN_EXISTING;
+    else
+        dwCreateDisposition = CREATE_NEW;
+
+    handle = CreateFileA(pszFile, dwAccess, dwShareMode, NULL,
+                         dwCreateDisposition, 0, NULL);
+
+    ok(handle != INVALID_HANDLE_VALUE, "Failed to CreateFile %s\n", pszFile);
+
+    return (INT_PTR)handle;
+}
+
+static UINT fci_read(INT_PTR hf, void *memory, UINT cb, int *err, void *pv)
+{
+    HANDLE handle = (HANDLE)hf;
+    DWORD dwRead;
+    BOOL res;
+    
+    res = ReadFile(handle, memory, cb, &dwRead, NULL);
+    ok(res, "Failed to ReadFile\n");
+
+    return dwRead;
+}
+
+static UINT fci_write(INT_PTR hf, void *memory, UINT cb, int *err, void *pv)
+{
+    HANDLE handle = (HANDLE)hf;
+    DWORD dwWritten;
+    BOOL res;
+
+    res = WriteFile(handle, memory, cb, &dwWritten, NULL);
+    ok(res, "Failed to WriteFile\n");
+
+    return dwWritten;
+}
+
+static int fci_close(INT_PTR hf, int *err, void *pv)
+{
+    HANDLE handle = (HANDLE)hf;
+    ok(CloseHandle(handle), "Failed to CloseHandle\n");
+
+    return 0;
+}
+
+static long fci_seek(INT_PTR hf, long dist, int seektype, int *err, void *pv)
+{
+    HANDLE handle = (HANDLE)hf;
+    DWORD ret;
+    
+    ret = SetFilePointer(handle, dist, NULL, seektype);
+    ok(ret != INVALID_SET_FILE_POINTER, "Failed to SetFilePointer\n");
+
+    return ret;
+}
+
+static int fci_delete(char *pszFile, int *err, void *pv)
+{
+    BOOL ret = DeleteFileA(pszFile);
+    ok(ret, "Failed to DeleteFile %s\n", pszFile);
+
+    return 0;
+}
+
+static BOOL get_temp_file(char *pszTempName, int cbTempName, void *pv)
+{
+    LPSTR tempname;
+
+    tempname = HeapAlloc(GetProcessHeap(), 0, MAX_PATH);
+    GetTempFileNameA(".", "xx", 0, tempname);
+
+    if (tempname && (strlen(tempname) < (unsigned)cbTempName))
+    {
+        lstrcpyA(pszTempName, tempname);
+        HeapFree(GetProcessHeap(), 0, tempname);
+        return TRUE;
+    }
+
+    HeapFree(GetProcessHeap(), 0, tempname);
+
+    return FALSE;
+}
+
+static INT_PTR get_open_info(char *pszName, USHORT *pdate, USHORT *ptime,
+                             USHORT *pattribs, int *err, void *pv)
+{
+    BY_HANDLE_FILE_INFORMATION finfo;
+    FILETIME filetime;
+    HANDLE handle;
+    DWORD attrs;
+    BOOL res;
+
+    handle = CreateFile(pszName, GENERIC_READ, FILE_SHARE_READ, NULL,
+                        OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
+
+    ok(handle != INVALID_HANDLE_VALUE, "Failed to CreateFile %s\n", pszName);
+
+    res = GetFileInformationByHandle(handle, &finfo);
+    ok(res, "Expected GetFileInformationByHandle to succeed\n");
+   
+    FileTimeToLocalFileTime(&finfo.ftLastWriteTime, &filetime);
+    FileTimeToDosDateTime(&filetime, pdate, ptime);
+
+    attrs = GetFileAttributes(pszName);
+    ok(attrs != INVALID_FILE_ATTRIBUTES, "Failed to GetFileAttributes\n");
+
+    return (INT_PTR)handle;
+}
+
+static void add_file(HFCI hfci, char *file)
+{
+    char path[MAX_PATH];
+    BOOL res;
+
+    lstrcpyA(path, CURR_DIR);
+    lstrcatA(path, "\\");
+    lstrcatA(path, file);
+
+    res = FCIAddFile(hfci, path, file, FALSE, get_next_cabinet, progress,
+                     get_open_info, tcompTYPE_MSZIP);
+    ok(res, "Expected FCIAddFile to succeed\n");
+}
+
+static void set_cab_parameters(PCCAB pCabParams)
+{
+    ZeroMemory(pCabParams, sizeof(CCAB));
+
+    pCabParams->cb = MEDIA_SIZE;
+    pCabParams->cbFolderThresh = FOLDER_THRESHOLD;
+    pCabParams->setID = 0xbeef;
+    lstrcpyA(pCabParams->szCabPath, CURR_DIR);
+    lstrcatA(pCabParams->szCabPath, "\\");
+    lstrcpyA(pCabParams->szCab, "extract.cab");
+}
+
+static void create_cab_file(void)
+{
+    CCAB cabParams;
+    HFCI hfci;
+    ERF erf;
+    BOOL res;
+
+    set_cab_parameters(&cabParams);
+
+    hfci = FCICreate(&erf, file_placed, mem_alloc, mem_free, fci_open,
+                      fci_read, fci_write, fci_close, fci_seek, fci_delete,
+                      get_temp_file, &cabParams, NULL);
+
+    ok(hfci != NULL, "Failed to create an FCI context\n");
+
+    add_file(hfci, "a.txt");
+    add_file(hfci, "b.txt");
+    add_file(hfci, "testdir\\c.txt");
+    add_file(hfci, "testdir\\d.txt");
+
+    res = FCIFlushCabinet(hfci, FALSE, get_next_cabinet, progress);
+    ok(res, "Failed to flush the cabinet\n");
+
+    res = FCIDestroy(hfci);
+    ok(res, "Failed to destroy the cabinet\n");
+}
+
+static void test_Extract(void)
+{
+    EXTRACTDEST extractDest;
+    HRESULT res;
+
+    /* native windows crashes if
+    *   - invalid parameters are sent in
+    *   - you call EXTRACT_EXTRACTFILES without calling
+    *     EXTRACT_FILLFILELIST first or at the same time
+    */
+
+    /* try to extract all files */
+    ZeroMemory(&extractDest, sizeof(EXTRACTDEST));
+    lstrcpyA(extractDest.directory, "dest");
+    extractDest.flags = EXTRACT_FILLFILELIST | EXTRACT_EXTRACTFILES;
+    res = pExtract(&extractDest, "extract.cab");
+    ok(res == S_OK, "Expected S_OK, got %ld\n", res);
+    ok(DeleteFileA("dest\\a.txt"), "Expected dest\\a.txt to exist\n");
+    ok(DeleteFileA("dest\\b.txt"), "Expected dest\\b.txt to exist\n");
+    ok(DeleteFileA("dest\\testdir\\c.txt"), "Expected dest\\testdir\\c.txt to exist\n");
+    ok(DeleteFileA("dest\\testdir\\d.txt"), "Expected dest\\testdir\\d.txt to exist\n");
+    ok(RemoveDirectoryA("dest\\testdir"), "Expected dest\\testdir to exist\n");
+
+    /* try fill file list operation */
+    ZeroMemory(&extractDest, sizeof(EXTRACTDEST));
+    lstrcpyA(extractDest.directory, "dest");
+    extractDest.flags = EXTRACT_FILLFILELIST;
+    res = pExtract(&extractDest, "extract.cab");
+    ok(res == S_OK, "Expected S_OK, got %ld\n", res);
+    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(extractDest.filecount == 4, "Expected 4 files, got %ld\n", extractDest.filecount);
+    ok(!lstrcmpA(extractDest.lastfile, "dest\\testdir\\d.txt"),
+        "Expected last file to be dest\\testdir\\d.txt, got %s\n", extractDest.lastfile);
+
+    /* try extract files operation once file list is filled */
+    extractDest.flags = EXTRACT_EXTRACTFILES;
+    res = pExtract(&extractDest, "extract.cab");
+    ok(res == S_OK, "Expected S_OK, got %ld\n", res);
+    ok(DeleteFileA("dest\\a.txt"), "Expected dest\\a.txt to exist\n");
+    ok(DeleteFileA("dest\\b.txt"), "Expected dest\\b.txt to exist\n");
+    ok(DeleteFileA("dest\\testdir\\c.txt"), "Expected dest\\testdir\\c.txt to exist\n");
+    ok(DeleteFileA("dest\\testdir\\d.txt"), "Expected dest\\testdir\\d.txt to exist\n");
+    ok(RemoveDirectoryA("dest\\testdir"), "Expected dest\\testdir to exist\n");
+    ok(RemoveDirectoryA("dest"), "Expected dest to exist\n");
+
+    /* Extract does not extract files if the dest dir does not exist */
+    res = pExtract(&extractDest, "extract.cab");
+    ok(res == S_OK, "Expected S_OK, got %ld\n", res);
+    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");
+
+    /* remove two of the files in the list */
+    extractDest.filelist->next = extractDest.filelist->next->next;
+    extractDest.filelist->next->next = NULL;
+    CreateDirectoryA("dest", NULL);
+    res = pExtract(&extractDest, "extract.cab");
+    ok(res == S_OK, "Expected S_OK, got %ld\n", res);
+    ok(DeleteFileA("dest\\a.txt"), "Expected dest\\a.txt to exist\n");
+    ok(DeleteFileA("dest\\testdir\\c.txt"), "Expected dest\\testdir\\c.txt to exist\n");
+    ok(!DeleteFileA("dest\\b.txt"), "Expected dest\\b.txt to not exist\n");
+    ok(!DeleteFileA("dest\\testdir\\d.txt"), "Expected dest\\testdir\\d.txt to not exist\n");
+    ok(RemoveDirectoryA("dest\\testdir"), "Expected dest\\testdir to exist\n");
+    ok(RemoveDirectoryA("dest"), "Expected dest\\testdir to exist\n");
+}
+
+START_TEST(extract)
+{
+    init_function_pointers();
+    create_test_files();
+    create_cab_file();
+
+    test_Extract();
+
+    delete_test_files();
+}
diff --git a/rostests/winetests/cabinet/testlist.c b/rostests/winetests/cabinet/testlist.c
new file mode 100644 (file)
index 0000000..b837786
--- /dev/null
@@ -0,0 +1,13 @@
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+#define STANDALONE
+#include "wine/test.h"
+
+extern void func_extract(void);
+
+const struct test winetest_testlist[] =
+{
+    { "extract", func_extract },
+    { 0, 0 }
+};
diff --git a/rostests/winetests/comctl32/comboex.c b/rostests/winetests/comctl32/comboex.c
new file mode 100644 (file)
index 0000000..106a80e
--- /dev/null
@@ -0,0 +1,238 @@
+/* Unit test suite for comboex control.
+ *
+ * Copyright 2005 Jason Edmeades
+ *
+ * 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 <assert.h>
+#include <windows.h>
+#include <commctrl.h>
+
+#include "wine/test.h"
+
+static HWND hComboExParentWnd;
+static HINSTANCE hMainHinst;
+static const char ComboExTestClass[] = "ComboExTestClass";
+
+#define MAX_CHARS 100
+static char *textBuffer = NULL;
+
+static HWND createComboEx(DWORD style) {
+   return CreateWindowExA(0, WC_COMBOBOXEXA, NULL, style, 0, 0, 300, 300,
+            hComboExParentWnd, NULL, hMainHinst, NULL);
+}
+
+static LONG addItem(HWND cbex, int idx, LPTSTR text) {
+    COMBOBOXEXITEM cbexItem;
+    memset(&cbexItem, 0x00, sizeof(cbexItem));
+    cbexItem.mask = CBEIF_TEXT;
+    cbexItem.iItem = idx;
+    cbexItem.pszText    = text;
+    cbexItem.cchTextMax = 0;
+    return (LONG)SendMessage(cbex, CBEM_INSERTITEM, 0,(LPARAM)&cbexItem);
+}
+
+static LONG setItem(HWND cbex, int idx, LPTSTR text) {
+    COMBOBOXEXITEM cbexItem;
+    memset(&cbexItem, 0x00, sizeof(cbexItem));
+    cbexItem.mask = CBEIF_TEXT;
+    cbexItem.iItem = idx;
+    cbexItem.pszText    = text;
+    cbexItem.cchTextMax = 0;
+    return (LONG)SendMessage(cbex, CBEM_SETITEM, 0,(LPARAM)&cbexItem);
+}
+
+static LONG delItem(HWND cbex, int idx) {
+    return (LONG)SendMessage(cbex, CBEM_DELETEITEM, (LPARAM)idx, 0);
+}
+
+static LONG getItem(HWND cbex, int idx, COMBOBOXEXITEM *cbItem) {
+    memset(cbItem, 0x00, sizeof(COMBOBOXEXITEM));
+    cbItem->mask = CBEIF_TEXT;
+    cbItem->pszText      = textBuffer;
+    cbItem->iItem        = idx;
+    cbItem->cchTextMax   = 100;
+    return (LONG)SendMessage(cbex, CBEM_GETITEM, 0, (LPARAM)cbItem);
+}
+
+static void test_comboboxex(void) {
+    HWND myHwnd = 0;
+    LONG res = -1;
+    COMBOBOXEXITEM cbexItem;
+    static TCHAR first_item[]        = {'F','i','r','s','t',' ','I','t','e','m',0},
+                 second_item[]       = {'S','e','c','o','n','d',' ','I','t','e','m',0},
+                 third_item[]        = {'T','h','i','r','d',' ','I','t','e','m',0},
+                 middle_item[]       = {'B','e','t','w','e','e','n',' ','F','i','r','s','t',' ','a','n','d',' ',
+                                        'S','e','c','o','n','d',' ','I','t','e','m','s',0},
+                 replacement_item[]  = {'B','e','t','w','e','e','n',' ','F','i','r','s','t',' ','a','n','d',' ',
+                                        'S','e','c','o','n','d',' ','I','t','e','m','s',0},
+                 out_of_range_item[] = {'O','u','t',' ','o','f',' ','R','a','n','g','e',' ','I','t','e','m',0};
+
+    /* Allocate space for result */
+    textBuffer = malloc(MAX_CHARS);
+
+    /* Basic comboboxex test */
+    myHwnd = createComboEx(WS_BORDER | WS_VISIBLE | WS_CHILD | CBS_DROPDOWN);
+
+    /* Add items onto the end of the combobox */
+    res = addItem(myHwnd, -1, first_item);
+    ok(res == 0, "Adding simple item failed (%ld)\n", res);
+    res = addItem(myHwnd, -1, second_item);
+    ok(res == 1, "Adding simple item failed (%ld)\n", res);
+    res = addItem(myHwnd, 2, third_item);
+    ok(res == 2, "Adding simple item failed (%ld)\n", res);
+    res = addItem(myHwnd, 1, middle_item);
+    ok(res == 1, "Inserting simple item failed (%ld)\n", res);
+
+    /* Add an item completely out of range */
+    res = addItem(myHwnd, 99, out_of_range_item);
+    ok(res == -1, "Adding using out of range index worked unexpectedly (%ld)\n", res);
+    res = addItem(myHwnd, 5, out_of_range_item);
+    ok(res == -1, "Adding using out of range index worked unexpectedly (%ld)\n", res);
+    /* Removed: Causes traps on Windows XP
+       res = addItem(myHwnd, -2, "Out Of Range Item");
+       ok(res == -1, "Adding out of range worked unexpectedly (%ld)\n", res);
+     */
+
+    /* Get an item completely out of range */ 
+    res = getItem(myHwnd, 99, &cbexItem); 
+    ok(res == 0, "Getting item using out of range index worked unexpectedly (%ld, %s)\n", res, cbexItem.pszText);
+    res = getItem(myHwnd, 4, &cbexItem); 
+    ok(res == 0, "Getting item using out of range index worked unexpectedly (%ld, %s)\n", res, cbexItem.pszText);
+    res = getItem(myHwnd, -2, &cbexItem); 
+    ok(res == 0, "Getting item using out of range index worked unexpectedly (%ld, %s)\n", res, cbexItem.pszText);
+
+    /* Get an item in range */ 
+    res = getItem(myHwnd, 0, &cbexItem); 
+    ok(res != 0, "Getting item using valid index failed unexpectedly (%ld)\n", res);
+    ok(strcmp(first_item, cbexItem.pszText) == 0, "Getting item returned wrong string (%s)\n", cbexItem.pszText);
+
+    res = getItem(myHwnd, 1, &cbexItem); 
+    ok(res != 0, "Getting item using valid index failed unexpectedly (%ld)\n", res);
+    ok(strcmp(middle_item, cbexItem.pszText) == 0, "Getting item returned wrong string (%s)\n", cbexItem.pszText);
+
+    res = getItem(myHwnd, 2, &cbexItem); 
+    ok(res != 0, "Getting item using valid index failed unexpectedly (%ld)\n", res);
+    ok(strcmp(second_item, cbexItem.pszText) == 0, "Getting item returned wrong string (%s)\n", cbexItem.pszText);
+
+    res = getItem(myHwnd, 3, &cbexItem); 
+    ok(res != 0, "Getting item using valid index failed unexpectedly (%ld)\n", res);
+    ok(strcmp(third_item, cbexItem.pszText) == 0, "Getting item returned wrong string (%s)\n", cbexItem.pszText);
+
+    /* Set an item completely out of range */ 
+    res = setItem(myHwnd, 99, replacement_item); 
+    ok(res == 0, "Setting item using out of range index worked unexpectedly (%ld)\n", res);
+    res = setItem(myHwnd, 4, replacement_item); 
+    ok(res == 0, "Setting item using out of range index worked unexpectedly (%ld)\n", res);
+    res = setItem(myHwnd, -2, replacement_item); 
+    ok(res == 0, "Setting item using out of range index worked unexpectedly (%ld)\n", res);
+
+    /* Set an item in range */ 
+    res = setItem(myHwnd, 0, replacement_item);
+    ok(res != 0, "Setting first item failed (%ld)\n", res);
+    res = setItem(myHwnd, 3, replacement_item);
+    ok(res != 0, "Setting last item failed (%ld)\n", res);
+
+    /* Remove items completely out of range (4 items in control at this point) */
+    res = delItem(myHwnd, -1);
+    ok(res == CB_ERR, "Deleting using out of range index worked unexpectedly (%ld)\n", res);
+    res = delItem(myHwnd, 4);
+    ok(res == CB_ERR, "Deleting using out of range index worked unexpectedly (%ld)\n", res);
+
+    /* Remove items in range (4 items in control at this point) */
+    res = delItem(myHwnd, 3);
+    ok(res == 3, "Deleting using out of range index failed (%ld)\n", res);
+    res = delItem(myHwnd, 0);
+    ok(res == 2, "Deleting using out of range index failed (%ld)\n", res);
+    res = delItem(myHwnd, 0);
+    ok(res == 1, "Deleting using out of range index failed (%ld)\n", res);
+    res = delItem(myHwnd, 0);
+    ok(res == 0, "Deleting using out of range index failed (%ld)\n", res);
+
+    /* Remove from an empty box */
+    res = delItem(myHwnd, 0);
+    ok(res == CB_ERR, "Deleting using out of range index worked unexpectedly (%ld)\n", res);
+
+
+    /* Cleanup */
+    free(textBuffer);
+
+}
+
+LRESULT CALLBACK ComboExTestWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    switch(msg) {
+    
+    case WM_DESTROY:
+        PostQuitMessage(0);
+        break;
+  
+    default:
+        return DefWindowProcA(hWnd, msg, wParam, lParam);
+    }
+    
+    return 0L;
+}
+
+static void init(void) {
+    WNDCLASSA wc;
+    INITCOMMONCONTROLSEX icex;
+
+    icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
+    icex.dwICC   = ICC_USEREX_CLASSES;
+    InitCommonControlsEx(&icex);
+
+    wc.style = CS_HREDRAW | CS_VREDRAW;
+    wc.cbClsExtra = 0;
+    wc.cbWndExtra = 0;
+    wc.hInstance = GetModuleHandleA(NULL);
+    wc.hIcon = NULL;
+    wc.hCursor = LoadCursorA(NULL, MAKEINTRESOURCEA(IDC_ARROW));
+    wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
+    wc.lpszMenuName = NULL;
+    wc.lpszClassName = ComboExTestClass;
+    wc.lpfnWndProc = ComboExTestWndProc;
+    RegisterClassA(&wc);
+
+    hComboExParentWnd = CreateWindowExA(0, ComboExTestClass, "ComboEx test", WS_OVERLAPPEDWINDOW, 
+      CW_USEDEFAULT, CW_USEDEFAULT, 680, 260, NULL, NULL, GetModuleHandleA(NULL), 0);
+    assert(hComboExParentWnd != NULL);
+
+    hMainHinst = GetModuleHandleA(NULL);
+
+}
+
+static void cleanup(void)
+{
+    MSG msg;
+    
+    PostMessageA(hComboExParentWnd, WM_CLOSE, 0, 0);
+    while (GetMessageA(&msg,0,0,0)) {
+        TranslateMessage(&msg);
+        DispatchMessageA(&msg);
+    }
+    
+    UnregisterClassA(ComboExTestClass, GetModuleHandleA(NULL));
+}
+
+START_TEST(comboex)
+{
+    init();
+
+    test_comboboxex();
+
+    cleanup();
+}
diff --git a/rostests/winetests/comctl32/comctl32.rbuild b/rostests/winetests/comctl32/comctl32.rbuild
new file mode 100644 (file)
index 0000000..407eac3
--- /dev/null
@@ -0,0 +1,29 @@
+<module name="comctl32_winetest" type="win32cui" installbase="bin" installname="comctl32_winetest.exe" allowwarnings="true">
+    <include base="comctl32_winetest">.</include>
+    <define name="__USE_W32API" />
+    <library>shlwapi</library>
+    <library>ole32</library>
+    <library>comctl32</library>
+    <library>ntdll</library>
+    <library>gdi32</library>
+    <library>user32</library>
+    <library>kernel32</library>
+    <library>advapi32</library>
+    <file>comboex.c</file>
+    <file>dpa.c</file>
+    <file>header.c</file>
+    <file>imagelist.c</file>
+    <file>listview.c</file>
+    <file>monthcal.c</file>
+    <file>mru.c</file>
+    <file>progress.c</file>
+    <file>propsheet.c</file>
+    <file>subclass.c</file>
+    <file>tab.c</file>
+    <file>testlist.c</file>
+    <file>toolbar.c</file>
+    <file>tooltips.c</file>
+    <file>treeview.c</file>
+    <file>updown.c</file>
+    <file>propsheet.rc</file>
+</module>
diff --git a/rostests/winetests/comctl32/dpa.c b/rostests/winetests/comctl32/dpa.c
new file mode 100644 (file)
index 0000000..8febf61
--- /dev/null
@@ -0,0 +1,439 @@
+/*
+ * Unit tests for DPA functions
+ *
+ * Copyright 2003 Uwe Bonnes
+ * Copyright 2005 Felix Nawothnig
+ *
+ * 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
+ */
+
+#define COBJMACROS
+
+#include <stdarg.h>
+
+#include "windows.h"
+#include "commctrl.h"
+#include "objidl.h"
+
+#include "wine/test.h"
+
+#define DPAM_NOSORT 0x1
+#define DPAM_INSERT 0x4
+#define DPAM_DELETE 0x8
+
+typedef struct _ITEMDATA
+{
+    INT   iPos;
+    PVOID pvData;
+} ITEMDATA, *LPITEMDATA;
+
+typedef PVOID   (CALLBACK *PFNDPAMERGE)(UINT,PVOID,PVOID,LPARAM);
+typedef HRESULT (CALLBACK *PFNDPASTM)(LPITEMDATA,IStream*,LPARAM);
+
+static HDPA    (WINAPI *pDPA_Clone)(const HDPA,const HDPA);
+static HDPA    (WINAPI *pDPA_Create)(INT);
+static HDPA    (WINAPI *pDPA_CreateEx)(INT,HANDLE);
+static PVOID   (WINAPI *pDPA_DeleteAllPtrs)(const HDPA);
+static PVOID   (WINAPI *pDPA_DeletePtr)(const HDPA,INT);
+static BOOL    (WINAPI *pDPA_Destroy)(const HDPA);
+static VOID    (WINAPI *pDPA_DestroyCallback)(HDPA,PFNDPAENUMCALLBACK,PVOID);
+static VOID    (WINAPI *pDPA_EnumCallback)(HDPA,PFNDPAENUMCALLBACK,PVOID); 
+static INT     (WINAPI *pDPA_GetPtr)(const HDPA,INT);
+static INT     (WINAPI *pDPA_GetPtrIndex)(const HDPA,PVOID);
+static BOOL    (WINAPI *pDPA_Grow)(HDPA,INT);
+static INT     (WINAPI *pDPA_InsertPtr)(const HDPA,INT,PVOID);
+static HRESULT (WINAPI *pDPA_LoadStream)(HDPA*,PFNDPASTM,IStream*,LPARAM);
+static BOOL    (WINAPI *pDPA_Merge)(const HDPA,const HDPA,DWORD,PFNDPACOMPARE,PFNDPAMERGE,LPARAM);
+static HRESULT (WINAPI *pDPA_SaveStream)(HDPA,PFNDPASTM,IStream*,LPARAM);
+static INT     (WINAPI *pDPA_Search)(HDPA,PVOID,INT,PFNDPACOMPARE,LPARAM,UINT);
+static BOOL    (WINAPI *pDPA_SetPtr)(const HDPA,INT,PVOID);
+static BOOL    (WINAPI *pDPA_Sort)(const HDPA,PFNDPACOMPARE,LPARAM);
+
+#define COMCTL32_GET_PROC(func, ord) \
+  ((p ## func = (PVOID)GetProcAddress(hcomctl32,(LPCSTR)ord)) ? 1 \
+   : (trace( #func " not exported\n"), 0)) 
+
+static BOOL InitFunctionPtrs(HMODULE hcomctl32)
+{
+    /* 4.00+ */
+    if(COMCTL32_GET_PROC(DPA_Clone, 331) &&
+       COMCTL32_GET_PROC(DPA_Create, 328) &&
+       COMCTL32_GET_PROC(DPA_CreateEx, 340) &&
+       COMCTL32_GET_PROC(DPA_DeleteAllPtrs, 337) &&
+       COMCTL32_GET_PROC(DPA_DeletePtr, 336) &&
+       COMCTL32_GET_PROC(DPA_Destroy, 329) &&
+       COMCTL32_GET_PROC(DPA_GetPtr, 332) &&
+       COMCTL32_GET_PROC(DPA_GetPtrIndex, 333) &&
+       COMCTL32_GET_PROC(DPA_Grow, 330) &&
+       COMCTL32_GET_PROC(DPA_InsertPtr, 334) &&
+       COMCTL32_GET_PROC(DPA_Search, 339) &&
+       COMCTL32_GET_PROC(DPA_SetPtr, 335) &&
+       COMCTL32_GET_PROC(DPA_Sort, 338))
+    {
+        /* 4.71+ */
+        COMCTL32_GET_PROC(DPA_DestroyCallback, 386) &&
+        COMCTL32_GET_PROC(DPA_EnumCallback, 385) &&
+        COMCTL32_GET_PROC(DPA_LoadStream, 9) &&
+        COMCTL32_GET_PROC(DPA_Merge, 11) &&
+        COMCTL32_GET_PROC(DPA_SaveStream, 10);
+
+        return TRUE;
+    }
+
+    return FALSE;
+}
+
+/* Callbacks */
+static INT CALLBACK CB_CmpLT(PVOID p1, PVOID p2, LPARAM lp)
+{
+    ok(lp == 0xdeadbeef, "lp=%ld\n", lp);
+    return p1 < p2 ? -1 : p1 > p2 ? 1 : 0;
+}
+
+static INT CALLBACK CB_CmpGT(PVOID p1, PVOID p2, LPARAM lp)
+{
+    ok(lp == 0xdeadbeef, "lp=%ld\n", lp);
+    return p1 > p2 ? -1 : p1 < p2 ? 1 : 0;
+}
+
+static PVOID CALLBACK CB_MergeInsertSrc(UINT op, PVOID p1, PVOID p2, LPARAM lp)
+{
+    ok(lp == 0xdeadbeef, "lp=%ld\n", lp);
+    return p1;
+}        
+
+static PVOID CALLBACK CB_MergeDeleteOddSrc(UINT op, PVOID p1, PVOID p2, LPARAM lp)
+{
+    ok(lp == 0xdeadbeef, "lp=%ld\n", lp);
+    return ((PCHAR)p2)+1;
+}
+
+static INT nEnum;
+
+static INT CALLBACK CB_EnumFirstThree(PVOID pItem, PVOID lp)
+{   
+    INT i;
+
+    i = pDPA_GetPtrIndex(lp, pItem);
+    ok(i == nEnum, "i=%d nEnum=%d\n", i, nEnum);
+    nEnum++;
+    pDPA_SetPtr(lp, i, (PVOID)7);
+    return pItem != (PVOID)3;
+}
+
+static HRESULT CALLBACK CB_Save(LPITEMDATA pInfo, IStream *pStm, LPARAM lp)
+{
+    HRESULT hRes;
+    
+    ok(lp == 0xdeadbeef, "lp=%ld\n", lp);
+    hRes = IStream_Write(pStm, &pInfo->iPos, sizeof(INT), NULL);
+    ok(hRes == S_OK, "hRes=0x%lx\n", hRes);
+    hRes = IStream_Write(pStm, &pInfo->pvData, sizeof(PVOID), NULL);
+    ok(hRes == S_OK, "hRes=0x%lx\n", hRes);
+    return S_OK;
+}
+
+static HRESULT CALLBACK CB_Load(LPITEMDATA pInfo, IStream *pStm, LPARAM lp)
+{
+    HRESULT hRes;
+    INT iOldPos;
+    
+    iOldPos = pInfo->iPos;
+    ok(lp == 0xdeadbeef, "lp=%ld\n", lp);
+    hRes = IStream_Read(pStm, &pInfo->iPos, sizeof(INT), NULL);
+    ok(hRes == S_OK, "hRes=0x%lx\n", hRes);
+    ok(pInfo->iPos == iOldPos, "iPos=%d iOldPos=%d\n", pInfo->iPos, iOldPos);
+    hRes = IStream_Read(pStm, &pInfo->pvData, sizeof(PVOID), NULL);
+    ok(hRes == S_OK, "hRes=0x%lx\n", hRes);
+    return S_OK;
+}
+
+static BOOL CheckDPA(HDPA dpa, DWORD dwIn, PDWORD pdwOut)
+{
+    DWORD dwOut = 0;
+    INT i;
+
+    for(i = 0; i < 8;)
+    {
+        ULONG_PTR ulItem = (ULONG_PTR)pDPA_GetPtr(dpa, i++);
+        if(!ulItem) break;
+        dwOut = dwOut << 4 | (ulItem & 0xf);
+    }
+    
+    *pdwOut = dwOut;
+
+    if(dwOut != dwIn)
+    {
+        pDPA_DeleteAllPtrs(dpa);
+        
+        do
+        {
+            pDPA_InsertPtr(dpa, 0, (PVOID)(dwIn & 0xf));
+            dwIn >>= 4;
+        }
+        while(dwIn);
+        
+        return FALSE;
+    }
+    
+    return TRUE;
+}
+
+static void test_dpa(void)
+{
+    SYSTEM_INFO si;
+    HANDLE hHeap;
+    HDPA dpa, dpa2, dpa3;
+    INT ret, i;
+    PVOID p;
+    DWORD dw, dw2, dw3;
+    HRESULT hRes;
+    
+    GetSystemInfo(&si);
+    hHeap = HeapCreate(0, 1, 2);
+    ok(hHeap != NULL, "error=%ld\n", GetLastError());
+    dpa3 = pDPA_CreateEx(0, hHeap);
+    ok(dpa3 != NULL, "\n");
+    ret = pDPA_Grow(dpa3, si.dwPageSize + 1);
+    todo_wine ok(!ret && GetLastError() == ERROR_NOT_ENOUGH_MEMORY, 
+       "ret=%d error=%ld\n", ret, GetLastError());
+        
+    dpa = pDPA_Create(0);
+    ok(dpa != NULL, "\n");
+
+    /* Set item with out of bound index */
+    ok(pDPA_SetPtr(dpa, 1, (PVOID)6), "\n");
+    /* Fill the greated gap */
+    ok(pDPA_SetPtr(dpa, 0, (PVOID)5), "\n");
+    ok(CheckDPA(dpa, 0x56, &dw), "dw=0x%lx\n", dw);
+    
+    /* Prepend item */
+    ret = pDPA_InsertPtr(dpa, 1, (PVOID)1);
+    ok(ret == 1, "ret=%d\n", ret);
+    /* Append item using correct index */
+    ret = pDPA_InsertPtr(dpa, 3, (PVOID)3);
+    ok(ret == 3, "ret=%d\n", ret);
+    /* Append item using out of bound index */
+    ret = pDPA_InsertPtr(dpa, 5, (PVOID)2);
+    ok(ret == 4, "ret=%d\n", ret);
+    /* Append item using DPA_APPEND */ 
+    ret = pDPA_InsertPtr(dpa, DPA_APPEND, (PVOID)4);
+    ok(ret == 5, "ret=%d\n", ret);
+
+    ok(CheckDPA(dpa, 0x516324, &dw), "dw=0x%lx\n", dw);
+
+    for(i = 1; i <= 6; i++)
+    {
+        INT j, k;
+        k = pDPA_GetPtrIndex(dpa, (PVOID)i);
+        /* Linear searches should work on unsorted DPAs */
+        j = pDPA_Search(dpa, (PVOID)i, 0, CB_CmpLT, 0xdeadbeef, 0);
+        ok(j == k, "j=%d k=%d\n", j, k);
+    }
+
+    /* Sort DPA */
+    ok(pDPA_Sort(dpa, CB_CmpGT, 0xdeadbeef), "\n");
+    ok(CheckDPA(dpa, 0x654321, &dw), "dw=0x%lx\n", dw);
+    
+    /* Clone into a new DPA */
+    dpa2 = pDPA_Clone(dpa, NULL);
+    ok(dpa2 != NULL, "\n");
+    /* The old data should have been preserved */
+    ok(CheckDPA(dpa2, 0x654321, &dw2), "dw=0x%lx\n", dw2);
+    ok(pDPA_Sort(dpa, CB_CmpLT, 0xdeadbeef), "\n");
+    
+    /* Test if the DPA itself was really copied */
+    ok(CheckDPA(dpa,  0x123456, &dw),  "dw=0x%lx\n",  dw );
+    ok(CheckDPA(dpa2, 0x654321, &dw2), "dw2=0x%lx\n", dw2);
+
+    /* Clone into an old DPA */
+    p = NULL; SetLastError(ERROR_SUCCESS);
+    p = pDPA_Clone(dpa, dpa3);
+    ok(p == dpa3, "p=%p\n", p);
+    ok(CheckDPA(dpa3, 0x123456, &dw3), "dw3=0x%lx\n", dw3);
+
+    for(i = 1; i <= 6; i++)
+    {
+        INT j;
+
+        /* The array is in order so ptr == index+1 */
+        j = pDPA_GetPtrIndex(dpa, (PVOID)i);
+        ok(j+1 == i, "j=%d i=%d\n", j, i);
+        j = pDPA_Search(dpa, (PVOID)i, 0, CB_CmpLT, 0xdeadbeef, DPAS_SORTED);
+        ok(j+1 == i, "j=%d i=%d\n", j, i);
+
+        /* Linear searches respect iStart ... */
+        j = pDPA_Search(dpa, (PVOID)i, i+1, CB_CmpLT, 0xdeadbeef, 0);
+        ok(j == DPA_ERR, "j=%d\n", j);
+        /* ... but for a binary search it's ignored */
+        j = pDPA_Search(dpa, (PVOID)i, i+1, CB_CmpLT, 0xdeadbeef, DPAS_SORTED);
+        todo_wine ok(j+1 == i, "j=%d i=%d\n", j, i);
+    }
+    
+    /* Try to get the index of a nonexistent item */
+    i = pDPA_GetPtrIndex(dpa, (PVOID)7);
+    ok(i == DPA_ERR, "i=%d\n", i);
+    
+    /* Try to delete out of bound indexes */
+    p = pDPA_DeletePtr(dpa, -1);
+    ok(p == NULL, "p=%p\n", p);
+    p = pDPA_DeletePtr(dpa, 6);
+    ok(p == NULL, "p=%p\n", p);
+
+    /* Delete the third item */
+    p = pDPA_DeletePtr(dpa, 2);
+    ok(p == (PVOID)3, "p=%p\n", p);
+    ok(CheckDPA(dpa, 0x12456, &dw), "dw=0x%lx\n", dw);
+
+    /* Check where to re-insert the deleted item */
+    i = pDPA_Search(dpa, (PVOID)3, 0, 
+                    CB_CmpLT, 0xdeadbeef, DPAS_SORTED|DPAS_INSERTAFTER);
+    ok(i == 2, "i=%d\n", i);
+    /* DPAS_INSERTBEFORE works just like DPAS_INSERTAFTER */
+    i = pDPA_Search(dpa, (PVOID)3, 0,
+                    CB_CmpLT, 0xdeadbeef, DPAS_SORTED|DPAS_INSERTBEFORE);
+    ok(i == 2, "i=%d\n", i);
+    /* without DPAS_INSERTBEFORE/AFTER */
+    i = pDPA_Search(dpa, (PVOID)3, 0,
+                    CB_CmpLT, 0xdeadbeef, DPAS_SORTED);
+    ok(i == -1, "i=%d\n", i);
+
+    /* Re-insert the item */
+    ret = pDPA_InsertPtr(dpa, 2, (PVOID)3);
+    ok(ret == 2, "ret=%d i=%d\n", ret, 2);
+    ok(CheckDPA(dpa, 0x123456, &dw), "dw=0x%lx\n", dw);
+    
+    /* When doing a binary search while claiming reverse order all indexes
+     * should be bogus */
+    for(i = 0; i < 6; i++)
+    {
+        INT j = pDPA_Search(dpa, (PVOID)i, 0, CB_CmpGT, 0xdeadbeef,
+                            DPAS_SORTED|DPAS_INSERTBEFORE);
+        ok(j != i, "i=%d\n", i);
+    }
+
+    if(pDPA_Merge)
+    {
+        /* Delete all even entries from dpa */
+        p = pDPA_DeletePtr(dpa, 1);
+        p = pDPA_DeletePtr(dpa, 2);
+        p = pDPA_DeletePtr(dpa, 3);
+        ok(CheckDPA(dpa, 0x135, &dw), "dw=0x%lx\n", dw);
+    
+        /* Delete all odd entries from dpa2 */
+        pDPA_Merge(dpa2, dpa, DPAM_DELETE, 
+                   CB_CmpLT, CB_MergeDeleteOddSrc, 0xdeadbeef);
+        todo_wine ok(CheckDPA(dpa2, 0x246, &dw2), "dw=0x%lx\n", dw2);
+    
+        /* Merge dpa3 into dpa2 and dpa */
+        pDPA_Merge(dpa, dpa3, DPAM_INSERT|DPAM_NOSORT, 
+                   CB_CmpLT, CB_MergeInsertSrc, 0xdeadbeef);
+        pDPA_Merge(dpa2, dpa3, DPAM_INSERT|DPAM_NOSORT, 
+                   CB_CmpLT, CB_MergeInsertSrc, 0xdeadbeef);
+    
+        ok(CheckDPA(dpa,  0x123456, &dw ), "dw=0x%lx\n",  dw);
+        ok(CheckDPA(dpa2, 0x123456, &dw2), "dw2=0x%lx\n", dw2);
+        ok(CheckDPA(dpa3, 0x123456, &dw3), "dw3=0x%lx\n", dw3);
+    }
+
+    if(pDPA_EnumCallback)
+    {
+        nEnum = 0;
+        pDPA_EnumCallback(dpa2, CB_EnumFirstThree, (PVOID)dpa2);
+        ok(CheckDPA(dpa2, 0x777456, &dw2), "dw=0x%lx\n", dw2);
+        ok(nEnum == 3, "nEnum=%d\n", nEnum);
+    }
+    
+    /* Setting item with huge index should work */
+    ok(pDPA_SetPtr(dpa2, 0x12345, (PVOID)0xdeadbeef), "\n");
+    ret = pDPA_GetPtrIndex(dpa2, (PVOID)0xdeadbeef);
+    ok(ret == 0x12345, "ret=%d\n", ret);
+          
+    pDPA_DeleteAllPtrs(dpa2);
+    ok(CheckDPA(dpa2, 0, &dw2), "dw2=0x%lx\n", dw2);
+    pDPA_Destroy(dpa2);
+
+    if(pDPA_DestroyCallback)
+    {
+        nEnum = 0;
+        pDPA_DestroyCallback(dpa3, CB_EnumFirstThree, dpa3);
+        ok(nEnum == 3, "nEnum=%d\n", nEnum);
+    }
+    else pDPA_Destroy(dpa3);
+
+    if(!pDPA_SaveStream)
+        goto skip_stream_tests;
+
+    hRes = CoInitialize(NULL);
+    if(hRes == S_OK)
+    {
+        static const WCHAR szStg[] = { 'S','t','g',0 };
+        IStorage* pStg = NULL;
+        IStream* pStm = NULL;
+        LARGE_INTEGER liZero;
+        DWORD dwMode;
+        liZero.QuadPart = 0;
+
+        dwMode = STGM_DIRECT|STGM_CREATE|STGM_READWRITE|STGM_SHARE_EXCLUSIVE;
+        hRes = StgCreateDocfile(NULL, dwMode|STGM_DELETEONRELEASE, 0, &pStg);
+        ok(hRes == S_OK, "hRes=0x%lx\n", hRes);
+
+        hRes = IStorage_CreateStream(pStg, szStg, dwMode, 0, 0, &pStm);
+        ok(hRes == S_OK, "hRes=0x%lx\n", hRes);
+
+        hRes = pDPA_SaveStream(dpa, CB_Save, pStm, 0xdeadbeef);
+        todo_wine ok(hRes == S_OK, "hRes=0x%lx\n", hRes);
+        pDPA_Destroy(dpa);
+        
+        hRes = IStream_Seek(pStm, liZero, STREAM_SEEK_SET, NULL);
+        ok(hRes == S_OK, "hRes=0x%lx\n", hRes);
+        hRes = pDPA_LoadStream(&dpa, CB_Load, pStm, 0xdeadbeef);
+        todo_wine ok(hRes == S_OK, "hRes=0x%lx\n", hRes);
+        todo_wine ok(CheckDPA(dpa, 0x123456, &dw), "dw=0x%lx\n", dw);
+        pDPA_Destroy(dpa);
+
+        ret = IStream_Release(pStm);
+        ok(!ret, "ret=%d\n", ret);
+       
+        ret = IStorage_Release(pStg);
+        ok(!ret, "ret=%d\n", ret);
+
+        CoUninitialize();
+    }
+    else ok(0, "hResult: %ld\n", hRes);
+
+skip_stream_tests:
+    pDPA_Destroy(dpa);
+}
+
+START_TEST(dpa)
+{
+    HMODULE hcomctl32;
+
+    hcomctl32 = GetModuleHandleA("comctl32.dll");
+
+    if(!hcomctl32)
+    {
+        ok(0, "error=%ld\n", GetLastError());
+        return;
+    }
+
+    if(InitFunctionPtrs(hcomctl32))
+        test_dpa();
+    else
+        trace("skipping tests\n");
+
+    FreeLibrary(hcomctl32);
+}
diff --git a/rostests/winetests/comctl32/header.c b/rostests/winetests/comctl32/header.c
new file mode 100644 (file)
index 0000000..0084a71
--- /dev/null
@@ -0,0 +1,550 @@
+/* Unit test suite for header control.
+ *
+ * Copyright 2005 Vijay Kiran Kamuju 
+ *
+ * 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 <windows.h>
+#include <commctrl.h>
+#include <assert.h>
+
+#include "wine/test.h"
+
+typedef struct tagEXPECTEDNOTIFY
+{
+    INT iCode;
+    BOOL fUnicode;
+    HDITEMA hdItem;
+} EXPECTEDNOTIFY;
+
+EXPECTEDNOTIFY expectedNotify[10];
+INT nExpectedNotify = 0;
+INT nReceivedNotify = 0;
+INT unexpectedNotify[10];
+INT nUnexpectedNotify = 0;
+
+static HWND hHeaderParentWnd;
+static HWND hWndHeader;
+#define MAX_CHARS 100
+
+static void expect_notify(INT iCode, BOOL fUnicode, HDITEMA *lpItem)
+{
+    assert(nExpectedNotify < 10);
+    expectedNotify[nExpectedNotify].iCode = iCode;
+    expectedNotify[nExpectedNotify].fUnicode = fUnicode;
+    expectedNotify[nExpectedNotify].hdItem = *lpItem;
+    nExpectedNotify++;
+}
+
+static void dont_expect_notify(INT iCode)
+{
+    assert(nUnexpectedNotify < 10);
+    unexpectedNotify[nUnexpectedNotify++] = iCode;
+}
+
+static BOOL notifies_received(void)
+{
+    BOOL fRet = (nExpectedNotify == nReceivedNotify);
+    nExpectedNotify = nReceivedNotify = 0;
+    nUnexpectedNotify = 0;
+    return fRet;
+}
+
+static LONG addItem(HWND hdex, int idx, LPCSTR text)
+{
+    HDITEMA hdItem;
+    hdItem.mask       = HDI_TEXT | HDI_WIDTH;
+    hdItem.cxy        = 100;
+    hdItem.pszText    = (LPSTR)text;
+    hdItem.cchTextMax = 0;
+    return (LONG)SendMessage(hdex, HDM_INSERTITEMA, (WPARAM)idx, (LPARAM)&hdItem);
+}
+
+static LONG setItem(HWND hdex, int idx, LPCSTR text, BOOL fCheckNotifies)
+{
+    LONG ret;
+    HDITEMA hdexItem;
+    hdexItem.mask       = HDI_TEXT;
+    hdexItem.pszText    = (LPSTR)text;
+    hdexItem.cchTextMax = 0;
+    if (fCheckNotifies)
+    {
+        expect_notify(HDN_ITEMCHANGINGA, FALSE, &hdexItem);
+        expect_notify(HDN_ITEMCHANGEDA, FALSE, &hdexItem);
+    }
+    ret = (LONG)SendMessage(hdex, HDM_SETITEMA, (WPARAM)idx, (LPARAM)&hdexItem);
+    if (fCheckNotifies)
+        ok(notifies_received(), "setItem(): not all expected notifies were received\n");
+    return ret;
+}
+
+static LONG setItemUnicodeNotify(HWND hdex, int idx, LPCSTR text, LPCWSTR wText)
+{
+    LONG ret;
+    HDITEMA hdexItem;
+    HDITEMW hdexNotify;
+    hdexItem.mask       = HDI_TEXT;
+    hdexItem.pszText    = (LPSTR)text;
+    hdexItem.cchTextMax = 0;
+    
+    hdexNotify.mask    = HDI_TEXT;
+    hdexNotify.pszText = (LPWSTR)wText;
+    
+    expect_notify(HDN_ITEMCHANGINGW, TRUE, (HDITEMA*)&hdexNotify);
+    expect_notify(HDN_ITEMCHANGEDW, TRUE, (HDITEMA*)&hdexNotify);
+    ret = (LONG)SendMessage(hdex, HDM_SETITEMA, (WPARAM)idx, (LPARAM)&hdexItem);
+    ok(notifies_received(), "setItemUnicodeNotify(): not all expected notifies were received\n");
+    return ret;
+}
+
+static LONG delItem(HWND hdex, int idx)
+{
+    return (LONG)SendMessage(hdex, HDM_DELETEITEM, (WPARAM)idx, 0);
+}
+
+static LONG getItemCount(HWND hdex)
+{
+    return (LONG)SendMessage(hdex, HDM_GETITEMCOUNT, 0, 0);
+}
+
+static LONG getItem(HWND hdex, int idx, LPSTR textBuffer)
+{
+    HDITEMA hdItem;
+    hdItem.mask         = HDI_TEXT;
+    hdItem.pszText      = textBuffer;
+    hdItem.cchTextMax   = MAX_CHARS;
+    return (LONG)SendMessage(hdex, HDM_GETITEMA, (WPARAM)idx, (LPARAM)&hdItem);
+}
+
+static void addReadDelItem(HWND hdex, HDITEMA *phdiCreate, int maskRead, HDITEMA *phdiRead)
+{
+    ok(SendMessage(hdex, HDM_INSERTITEMA, (WPARAM)0, (LPARAM)phdiCreate)!=-1, "Adding item failed\n");
+    ZeroMemory(phdiRead, sizeof(HDITEMA));
+    phdiRead->mask = maskRead;
+    ok(SendMessage(hdex, HDM_GETITEMA, (WPARAM)0, (LPARAM)phdiRead)!=0, "Getting item data failed\n");
+    ok(SendMessage(hdex, HDM_DELETEITEM, (WPARAM)0, (LPARAM)0)!=0, "Deleteing item failed\n");
+}
+
+static HWND create_header_control (void)
+{
+    HWND handle;
+    HDLAYOUT hlayout;
+    RECT rectwin;
+    WINDOWPOS winpos;
+
+    handle = CreateWindowEx(0, WC_HEADER, NULL,
+                           WS_CHILD|WS_BORDER|WS_VISIBLE|HDS_BUTTONS|HDS_HORZ,
+                           0, 0, 0, 0,
+                           hHeaderParentWnd, NULL, NULL, NULL);
+    assert(handle);
+
+    if (winetest_interactive)
+       ShowWindow (hHeaderParentWnd, SW_SHOW);
+
+    GetClientRect(hHeaderParentWnd,&rectwin);
+    hlayout.prc = &rectwin;
+    hlayout.pwpos = &winpos;
+    SendMessageA(handle,HDM_LAYOUT,0,(LPARAM) &hlayout);
+    SetWindowPos(handle, winpos.hwndInsertAfter, winpos.x, winpos.y, 
+                 winpos.cx, winpos.cy, 0);
+
+    return handle;
+}
+
+static void compare_items(INT iCode, HDITEMA *hdi1, HDITEMA *hdi2, BOOL fUnicode)
+{
+    ok(hdi1->mask == hdi2->mask, "Notify %d mask mismatch (%08x != %08x)\n", iCode, hdi1->mask, hdi2->mask);
+    if (hdi1->mask & HDI_WIDTH)
+    {
+        ok(hdi1->cxy == hdi2->cxy, "Notify %d cxy mismatch (%08x != %08x)\n", iCode, hdi1->cxy, hdi2->cxy);
+    }
+    if (hdi1->mask & HDI_TEXT)
+    {
+        if (hdi1->pszText == LPSTR_TEXTCALLBACKA)
+        {
+            ok(hdi1->pszText == LPSTR_TEXTCALLBACKA, "Notify %d - only one item is LPSTR_TEXTCALLBACK\n", iCode);
+        }
+        else
+        if (fUnicode)
+        {
+            char buf1[260];
+            char buf2[260];
+            WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)hdi1->pszText, -1, buf1, 260, NULL, NULL);
+            WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)hdi2->pszText, -1, buf2, 260, NULL, NULL);
+            ok(lstrcmpW((LPWSTR)hdi1->pszText, (LPWSTR)hdi2->pszText)==0,
+                "Notify %d text mismatch (L\"%s\" vs L\"%s\")\n",
+                    iCode, buf1, buf2);
+        }
+        else
+        {
+            ok(strcmp(hdi1->pszText, hdi2->pszText)==0,
+                "Notify %d text mismatch (\"%s\" vs \"%s\")\n",
+                    iCode, hdi1->pszText, hdi2->pszText);
+            }
+    }
+}
+
+static const char *str_items[] =
+    {"First Item", "Second Item", "Third Item", "Fourth Item", "Replace Item", "Out Of Range Item"};
+    
+static const char pszUniTestA[] = "TST";
+static const WCHAR pszUniTestW[] = {'T','S','T',0};
+
+
+#define TEST_GET_ITEM(i,c)\
+{   res = getItem(hWndHeader, i, buffer);\
+    ok(res != 0, "Getting item[%d] using valid index failed unexpectedly (%ld)\n", i, res);\
+    ok(strcmp(str_items[c], buffer) == 0, "Getting item[%d] returned \"%s\" expecting \"%s\"\n", i, buffer, str_items[c]);\
+}
+
+#define TEST_GET_ITEMCOUNT(i)\
+{   res = getItemCount(hWndHeader);\
+    ok(res == i, "Got Item Count as %ld\n", res);\
+}
+
+static void check_auto_format(void)
+{
+    HDITEMA hdiCreate;
+    HDITEMA hdiRead;
+    static CHAR text[] = "Test";
+    ZeroMemory(&hdiCreate, sizeof(HDITEMA));
+
+    /* Windows implicitly sets some format bits in INSERTITEM */
+
+    /* HDF_STRING is automatically set and cleared for no text */
+    hdiCreate.mask = HDI_TEXT|HDI_WIDTH|HDI_FORMAT;
+    hdiCreate.pszText = text;
+    hdiCreate.cxy = 100;
+    hdiCreate.fmt=HDF_CENTER;
+    addReadDelItem(hWndHeader, &hdiCreate, HDI_FORMAT, &hdiRead);
+    ok(hdiRead.fmt == (HDF_STRING|HDF_CENTER), "HDF_STRING not set automatically (fmt=%x)\n", hdiRead.fmt);
+
+    hdiCreate.mask = HDI_WIDTH|HDI_FORMAT;
+    hdiCreate.pszText = text;
+    hdiCreate.fmt = HDF_CENTER|HDF_STRING;
+    addReadDelItem(hWndHeader, &hdiCreate, HDI_FORMAT, &hdiRead);
+    ok(hdiRead.fmt == (HDF_CENTER), "HDF_STRING should be automatically cleared (fmt=%x)\n", hdiRead.fmt);
+
+    /* HDF_BITMAP is automatically set and cleared for a NULL bitmap or no bitmap */
+    hdiCreate.mask = HDI_BITMAP|HDI_WIDTH|HDI_FORMAT;
+    hdiCreate.hbm = CreateBitmap(16, 16, 1, 8, NULL);
+    hdiCreate.fmt = HDF_CENTER;
+    addReadDelItem(hWndHeader, &hdiCreate, HDI_FORMAT, &hdiRead);
+    ok(hdiRead.fmt == (HDF_BITMAP|HDF_CENTER), "HDF_BITMAP not set automatically (fmt=%x)\n", hdiRead.fmt);
+    DeleteObject(hdiCreate.hbm);
+
+    hdiCreate.hbm = NULL;
+    hdiCreate.fmt = HDF_CENTER|HDF_BITMAP;
+    addReadDelItem(hWndHeader, &hdiCreate, HDI_FORMAT, &hdiRead);
+    ok(hdiRead.fmt == HDF_CENTER, "HDF_BITMAP not cleared automatically for NULL bitmap (fmt=%x)\n", hdiRead.fmt);
+
+    hdiCreate.mask = HDI_WIDTH|HDI_FORMAT;
+    hdiCreate.fmt = HDF_CENTER|HDF_BITMAP;
+    addReadDelItem(hWndHeader, &hdiCreate, HDI_FORMAT, &hdiRead);
+    ok(hdiRead.fmt == HDF_CENTER, "HDF_BITMAP not cleared automatically for no bitmap (fmt=%x)\n", hdiRead.fmt);
+
+    /* HDF_IMAGE is automatically set but not cleared */
+    hdiCreate.mask = HDI_IMAGE|HDI_WIDTH|HDI_FORMAT;
+    hdiCreate.iImage = 17;
+    addReadDelItem(hWndHeader, &hdiCreate, HDI_FORMAT, &hdiRead);
+    ok(hdiRead.fmt == (HDF_IMAGE|HDF_CENTER), "HDF_IMAGE not set automatically (fmt=%x)\n", hdiRead.fmt);
+
+    hdiCreate.mask = HDI_WIDTH|HDI_FORMAT;
+    hdiCreate.fmt = HDF_CENTER|HDF_IMAGE;
+    hdiCreate.iImage = 0;
+    addReadDelItem(hWndHeader, &hdiCreate, HDI_FORMAT, &hdiRead);
+    ok(hdiRead.fmt == (HDF_CENTER|HDF_IMAGE), "HDF_IMAGE shouldn't be cleared automatically (fmt=%x)\n", hdiRead.fmt);
+}
+
+static void check_auto_fields(void)
+{
+    HDITEMA hdiCreate;
+    HDITEMA hdiRead;
+    static CHAR text[] = "Test";
+    LRESULT res;
+
+    /* Windows stores the format, width, lparam even if they are not in the item's mask */
+    ZeroMemory(&hdiCreate, sizeof(HDITEMA));
+    hdiCreate.mask = HDI_TEXT;
+    hdiCreate.cxy = 100;
+    hdiCreate.pszText = text;
+    addReadDelItem(hWndHeader, &hdiCreate, HDI_WIDTH, &hdiRead);
+    TEST_GET_ITEMCOUNT(6);
+    ok(hdiRead.cxy == hdiCreate.cxy, "cxy should be automatically set\n");
+
+    ZeroMemory(&hdiCreate, sizeof(HDITEMA));
+    hdiCreate.mask = HDI_TEXT;
+    hdiCreate.pszText = text;
+    hdiCreate.lParam = 0x12345678;
+    addReadDelItem(hWndHeader, &hdiCreate, HDI_LPARAM, &hdiRead);
+    TEST_GET_ITEMCOUNT(6);
+    ok(hdiRead.lParam == hdiCreate.lParam, "lParam should be automatically set\n");
+
+    ZeroMemory(&hdiCreate, sizeof(HDITEMA));
+    hdiCreate.mask = HDI_TEXT;
+    hdiCreate.pszText = text;
+    hdiCreate.fmt = HDF_STRING|HDF_CENTER;
+    addReadDelItem(hWndHeader, &hdiCreate, HDI_FORMAT, &hdiRead);
+    TEST_GET_ITEMCOUNT(6);
+    ok(hdiRead.fmt == hdiCreate.fmt, "fmt should be automatically set\n");
+
+    /* others fields are not set */
+    ZeroMemory(&hdiCreate, sizeof(HDITEMA));
+    hdiCreate.mask = HDI_TEXT;
+    hdiCreate.pszText = text;
+    hdiCreate.hbm = CreateBitmap(16, 16, 1, 8, NULL);
+    addReadDelItem(hWndHeader, &hdiCreate, HDI_BITMAP, &hdiRead);
+    TEST_GET_ITEMCOUNT(6);
+    ok(hdiRead.hbm == NULL, "hbm should not be automatically set\n");
+    DeleteObject(hdiCreate.hbm);
+
+    ZeroMemory(&hdiCreate, sizeof(HDITEMA));
+    hdiCreate.mask = HDI_IMAGE;
+    hdiCreate.iImage = 17;
+    hdiCreate.pszText = text;
+    addReadDelItem(hWndHeader, &hdiCreate, HDI_TEXT, &hdiRead);
+    TEST_GET_ITEMCOUNT(6);
+    ok(hdiRead.pszText==NULL, "pszText shouldn't be automatically set\n");
+
+    /* field from comctl >4.0 not tested as the system probably won't touch them */
+}
+
+static void check_mask(void)
+{
+    HDITEMA hdi;
+    static CHAR text[] = "ABC";
+    LRESULT ret;
+
+    /* don't create items if the mask is zero */
+    ZeroMemory(&hdi, sizeof(hdi));
+    hdi.mask = 0;
+    hdi.cxy = 200;
+    hdi.pszText = text;
+    hdi.fmt = 0;
+    hdi.iOrder = 0;
+    hdi.lParam = 17;
+    hdi.cchTextMax = 260;
+    ret = SendMessage(hWndHeader, HDM_INSERTITEM, (WPARAM)0, (LPARAM)&hdi);
+    ok(ret == -1, "Creating an item with a zero mask should have failed\n");
+    if (ret != -1) SendMessage(hWndHeader, HDM_DELETEITEM, (WPARAM)0, (LPARAM)0);
+
+    /* with a non-zero mask creation will succeed */
+    ZeroMemory(&hdi, sizeof(hdi));
+    hdi.mask = HDI_LPARAM;
+    ret = SendMessage(hWndHeader, HDM_INSERTITEM, (WPARAM)0, (LPARAM)&hdi);
+    ok(ret != -1, "Adding item with non-zero mask failed\n");
+    if (ret != -1)
+        SendMessage(hWndHeader, HDM_DELETEITEM, (WPARAM)0, (LPARAM)0);
+
+    /* in SETITEM if the mask contains a unknown bit, it is ignored */
+    ZeroMemory(&hdi, sizeof(hdi));
+    hdi.mask = 0x08000000 | HDI_LPARAM | HDI_IMAGE;
+    hdi.lParam = 133;
+    hdi.iImage = 17;
+    ret = SendMessage(hWndHeader, HDM_INSERTITEM, (WPARAM)0, (LPARAM)&hdi);
+    ok(ret != -1, "Adding item failed\n");
+
+    if (ret != -1)
+    {
+        /* check result */
+        ZeroMemory(&hdi, sizeof(hdi));
+        hdi.mask = HDI_LPARAM | HDI_IMAGE;
+        SendMessage(hWndHeader, HDM_GETITEM, (WPARAM)0, (LPARAM)&hdi);
+        ok(hdi.lParam == 133, "comctl32 4.0 field not set\n");
+        ok(hdi.iImage == 17, "comctl32 >4.0 field not set\n");
+
+        /* but in GETITEM if an unknown bit is set, comctl32 uses only version 4.0 fields */
+        ZeroMemory(&hdi, sizeof(hdi));
+        hdi.mask = 0x08000000 | HDI_LPARAM | HDI_IMAGE;
+        SendMessage(hWndHeader, HDM_GETITEM, (WPARAM)0, (LPARAM)&hdi);
+        ok(hdi.lParam == 133, "comctl32 4.0 field not read\n");
+        ok(hdi.iImage == 0, "comctl32 >4.0 field shouldn't be read\n");
+
+        SendMessage(hWndHeader, HDM_DELETEITEM, (WPARAM)0, (LPARAM)0);
+    }
+}
+
+static void test_header_control (void)
+{
+    LONG res;
+    static char buffer[MAX_CHARS];
+    int i;
+
+    hWndHeader = create_header_control ();
+
+    for (i = 3; i >= 0; i--)
+    {
+        TEST_GET_ITEMCOUNT(3-i);
+        res = addItem(hWndHeader, 0, str_items[i]);
+        ok(res == 0, "Adding simple item failed (%ld)\n", res);
+    }
+
+    TEST_GET_ITEMCOUNT(4);
+    res = addItem(hWndHeader, 99, str_items[i+1]);
+    ok(res != -1, "Adding Out of Range item should fail with -1 got (%ld)\n", res);
+    TEST_GET_ITEMCOUNT(5);
+    res = addItem(hWndHeader, 5, str_items[i+1]);
+    ok(res != -1, "Adding Out of Range item should fail with -1 got (%ld)\n", res);
+    TEST_GET_ITEMCOUNT(6);
+
+    for (i = 0; i < 4; i++) { TEST_GET_ITEM(i,i); TEST_GET_ITEMCOUNT(6); }
+
+    res=getItem(hWndHeader, 99, buffer);
+    ok(res == 0, "Getting Out of Range item should fail with 0 (%ld), got %s\n", res,buffer);
+    res=getItem(hWndHeader, 5, buffer);
+    ok(res == 1, "Getting Out of Range item should fail with 1 (%ld), got %s\n", res,buffer);
+    res=getItem(hWndHeader, -2, buffer);
+    ok(res == 0, "Getting Out of Range item should fail with 0 (%ld), got %s\n", res,buffer);
+
+    if (winetest_interactive)
+    {
+        UpdateWindow(hHeaderParentWnd);
+        UpdateWindow(hWndHeader);
+    }
+
+    TEST_GET_ITEMCOUNT(6);
+    res=setItem(hWndHeader, 99, str_items[5], FALSE);
+    ok(res == 0, "Setting Out of Range item should fail with 0 (%ld)\n", res);
+    res=setItem(hWndHeader, 5, str_items[5], TRUE);
+    ok(res == 1, "Setting Out of Range item should fail with 1 (%ld)\n", res);
+    res=setItem(hWndHeader, -2, str_items[5], FALSE);
+    ok(res == 0, "Setting Out of Range item should fail with 0 (%ld)\n", res);
+    TEST_GET_ITEMCOUNT(6);
+
+    for (i = 0; i < 4; i++)
+    {
+        res = setItem(hWndHeader, i, str_items[4], TRUE);
+        ok(res != 0, "Setting %d item failed (%ld)\n", i+1, res);
+        TEST_GET_ITEM(i, 4);
+        TEST_GET_ITEMCOUNT(6);
+    }
+    
+    SendMessageA(hWndHeader, HDM_SETUNICODEFORMAT, (WPARAM)TRUE, 0);
+    setItemUnicodeNotify(hWndHeader, 3, pszUniTestA, pszUniTestW);
+    SendMessageA(hWndHeader, WM_NOTIFYFORMAT, (WPARAM)hHeaderParentWnd, (LPARAM)NF_REQUERY);
+    setItem(hWndHeader, 3, str_items[4], TRUE);
+    
+    dont_expect_notify(HDN_GETDISPINFOA);
+    dont_expect_notify(HDN_GETDISPINFOW);
+    addItem(hWndHeader, 0, LPSTR_TEXTCALLBACKA);
+    setItem(hWndHeader, 0, str_items[4], TRUE);
+    /* unexpected notifies cleared by notifies_received in setItem */
+    dont_expect_notify(HDN_GETDISPINFOA);
+    dont_expect_notify(HDN_GETDISPINFOW);
+    setItem(hWndHeader, 0, LPSTR_TEXTCALLBACKA, TRUE);
+    /* unexpected notifies cleared by notifies_received in setItem */
+    delItem(hWndHeader, 0);
+
+    check_auto_format();
+    TEST_GET_ITEMCOUNT(6);
+    check_auto_fields();
+    TEST_GET_ITEMCOUNT(6);
+    check_mask();
+    TEST_GET_ITEMCOUNT(6);
+
+    res = delItem(hWndHeader, 5);
+    ok(res == 1, "Deleting Out of Range item should fail with 1 (%ld)\n", res);
+    res = delItem(hWndHeader, -2);
+    ok(res == 0, "Deleting Out of Range item should fail with 0 (%ld)\n", res);
+    TEST_GET_ITEMCOUNT(5);
+
+    res = delItem(hWndHeader, 3);
+    ok(res != 0, "Deleting using out of range index failed (%ld)\n", res);
+    TEST_GET_ITEMCOUNT(4);
+    res = delItem(hWndHeader, 0);
+    ok(res != 0, "Deleting using out of range index failed (%ld)\n", res);
+    TEST_GET_ITEMCOUNT(3);
+    res = delItem(hWndHeader, 0);
+    ok(res != 0, "Deleting using out of range index failed (%ld)\n", res);
+    TEST_GET_ITEMCOUNT(2);
+    res = delItem(hWndHeader, 0);
+    ok(res != 0, "Deleting using out of range index failed (%ld)\n", res);
+    TEST_GET_ITEMCOUNT(1);
+
+    DestroyWindow(hWndHeader);
+}
+
+
+LRESULT CALLBACK HeaderTestWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    switch(msg) {
+
+    case WM_NOTIFY:
+    {
+        NMHEADERA *hdr = (NMHEADER *)lParam;
+        EXPECTEDNOTIFY *expected;
+        int i;
+        
+        for (i=0; i<nUnexpectedNotify; i++)
+            ok(hdr->hdr.code != unexpectedNotify[i], "Received invalid notify %d\n", hdr->hdr.code);
+        
+        if (nReceivedNotify >= nExpectedNotify || hdr->hdr.hwndFrom != hWndHeader )
+            break;
+
+        expected = &expectedNotify[nReceivedNotify];
+        if (hdr->hdr.code != expected->iCode)
+            break;
+        
+        nReceivedNotify++;
+        compare_items(hdr->hdr.code, &expected->hdItem, hdr->pitem, expected->fUnicode);
+        break;
+    }
+    
+    case WM_DESTROY:
+        PostQuitMessage(0);
+        break;
+  
+    default:
+        return DefWindowProcA(hWnd, msg, wParam, lParam);
+    }
+    
+    return 0L;
+}
+
+static void init(void) {
+    WNDCLASSA wc;
+    INITCOMMONCONTROLSEX icex;
+
+    icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
+    icex.dwICC  = ICC_USEREX_CLASSES;
+    InitCommonControlsEx(&icex);
+
+    wc.style = CS_HREDRAW | CS_VREDRAW;
+    wc.cbClsExtra = 0;
+    wc.cbWndExtra = 0;
+    wc.hInstance = GetModuleHandleA(NULL);
+    wc.hIcon = NULL;
+    wc.hCursor = LoadCursorA(NULL, MAKEINTRESOURCEA(IDC_ARROW));
+    wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
+    wc.lpszMenuName = NULL;
+    wc.lpszClassName = "HeaderTestClass";
+    wc.lpfnWndProc = HeaderTestWndProc;
+    RegisterClassA(&wc);
+
+    hHeaderParentWnd = CreateWindowExA(0, "HeaderTestClass", "Header test", WS_OVERLAPPEDWINDOW, 
+      CW_USEDEFAULT, CW_USEDEFAULT, 680, 260, NULL, NULL, GetModuleHandleA(NULL), 0);
+    assert(hHeaderParentWnd != NULL);
+}
+
+START_TEST(header)
+{
+    init();
+
+    test_header_control();
+
+    DestroyWindow(hHeaderParentWnd);
+}
diff --git a/rostests/winetests/comctl32/imagelist.c b/rostests/winetests/comctl32/imagelist.c
new file mode 100644 (file)
index 0000000..0ecb03a
--- /dev/null
@@ -0,0 +1,560 @@
+/* Unit test suite for imagelist control.
+ *
+ * Copyright 2004 Michael Stefaniuc
+ * Copyright 2002 Mike McCormack for CodeWeavers
+ *
+ * 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 <assert.h>
+#include <windows.h>
+#include <commctrl.h>
+#include <stdio.h>
+
+#include "wine/test.h"
+
+#undef VISIBLE
+
+#ifdef VISIBLE
+#define WAIT Sleep (1000)
+#define REDRAW(hwnd) RedrawWindow (hwnd, NULL, 0, RDW_UPDATENOW)
+#else
+#define WAIT
+#define REDRAW(hwnd)
+#endif
+
+
+static BOOL (WINAPI *pImageList_DrawIndirect)(IMAGELISTDRAWPARAMS*) = NULL;
+
+static HDC desktopDC;
+static HINSTANCE hinst;
+
+/* These macros build cursor/bitmap data in 4x4 pixel blocks */
+#define B(x,y) ((x?0xf0:0)|(y?0xf:0))
+#define ROW1(a,b,c,d,e,f,g,h) B(a,b),B(c,d),B(e,f),B(g,h)
+#define ROW32(a,b,c,d,e,f,g,h) ROW1(a,b,c,d,e,f,g,h), ROW1(a,b,c,d,e,f,g,h), \
+  ROW1(a,b,c,d,e,f,g,h), ROW1(a,b,c,d,e,f,g,h)
+#define ROW2(a,b,c,d,e,f,g,h,i,j,k,l) ROW1(a,b,c,d,e,f,g,h),B(i,j),B(k,l)
+#define ROW48(a,b,c,d,e,f,g,h,i,j,k,l) ROW2(a,b,c,d,e,f,g,h,i,j,k,l), \
+  ROW2(a,b,c,d,e,f,g,h,i,j,k,l), ROW2(a,b,c,d,e,f,g,h,i,j,k,l), \
+  ROW2(a,b,c,d,e,f,g,h,i,j,k,l)
+
+static const BYTE empty_bits[48*48/8];
+
+static const BYTE icon_bits[32*32/8] =
+{
+  ROW32(0,0,0,0,0,0,0,0),
+  ROW32(0,0,1,1,1,1,0,0),
+  ROW32(0,1,1,1,1,1,1,0),
+  ROW32(0,1,1,0,0,1,1,0),
+  ROW32(0,1,1,0,0,1,1,0),
+  ROW32(0,1,1,1,1,1,1,0),
+  ROW32(0,0,1,1,1,1,0,0),
+  ROW32(0,0,0,0,0,0,0,0)
+};
+
+static const BYTE bitmap_bits[48*48/8] =
+{
+  ROW48(0,0,0,0,0,0,0,0,0,0,0,0),
+  ROW48(0,1,1,1,1,1,1,1,1,1,1,0),
+  ROW48(0,1,1,0,0,0,0,0,0,1,1,0),
+  ROW48(0,1,0,0,0,0,0,0,1,0,1,0),
+  ROW48(0,1,0,0,0,0,0,1,0,0,1,0),
+  ROW48(0,1,0,0,0,0,1,0,0,0,1,0),
+  ROW48(0,1,0,0,0,1,0,0,0,0,1,0),
+  ROW48(0,1,0,0,1,0,0,0,0,0,1,0),
+  ROW48(0,1,0,1,0,0,0,0,0,0,1,0),
+  ROW48(0,1,1,0,0,0,0,0,0,1,1,0),
+  ROW48(0,1,1,1,1,1,1,1,1,1,1,0),
+  ROW48(0,0,0,0,0,0,0,0,0,0,0,0)
+};
+
+static HIMAGELIST createImageList(int cx, int cy)
+{
+    /* Create an ImageList and put an image into it */
+    HIMAGELIST himl = ImageList_Create(cx, cy, ILC_COLOR, 1, 1);
+    HBITMAP hbm = CreateBitmap(48, 48, 1, 1, bitmap_bits);
+    ImageList_Add(himl, hbm, NULL);
+    return himl;
+}
+
+static HWND create_a_window(void)
+{
+    char className[] = "bmwnd";
+    char winName[]   = "Test Bitmap";
+    HWND hWnd;
+    static int registered = 0;
+
+    if (!registered)
+    {
+        WNDCLASSA cls;
+
+        cls.style         = CS_HREDRAW | CS_VREDRAW | CS_GLOBALCLASS;
+        cls.lpfnWndProc   = DefWindowProcA;
+        cls.cbClsExtra    = 0;
+        cls.cbWndExtra    = 0;
+        cls.hInstance     = 0;
+        cls.hIcon         = LoadIconA (0, (LPSTR)IDI_APPLICATION);
+        cls.hCursor       = LoadCursorA (0, (LPSTR)IDC_ARROW);
+        cls.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
+        cls.lpszMenuName  = 0;
+        cls.lpszClassName = className;
+
+        RegisterClassA (&cls);
+        registered = 1;
+    }
+
+    /* Setup window */
+    hWnd = CreateWindowA (className, winName,
+       WS_OVERLAPPEDWINDOW ,
+       CW_USEDEFAULT, CW_USEDEFAULT, 300, 300, 0,
+       0, hinst, 0);
+
+#ifdef VISIBLE
+    ShowWindow (hWnd, SW_SHOW);
+#endif
+    REDRAW(hWnd);
+    WAIT;
+
+    return hWnd;
+}
+
+static HDC show_image(HWND hwnd, HIMAGELIST himl, int idx, int size,
+                      LPCSTR loc, BOOL clear)
+{
+    HDC hdc = NULL;
+#ifdef VISIBLE
+    if (!himl) return NULL;
+
+    SetWindowText(hwnd, loc);
+    hdc = GetDC(hwnd);
+    ImageList_Draw(himl, idx, hdc, 0, 0, ILD_TRANSPARENT);
+
+    REDRAW(hwnd);
+    WAIT;
+
+    if (clear)
+    {
+        BitBlt(hdc, 0, 0, size, size, hdc, size+1, size+1, SRCCOPY);
+        ReleaseDC(hwnd, hdc);
+        hdc = NULL;
+    }
+#endif /* VISIBLE */
+    return hdc;
+}
+
+/* Useful for checking differences */
+#if 0
+static void dump_bits(const BYTE *p, const BYTE *q, int size)
+{
+  int i, j;
+
+  size /= 8;
+
+  for (i = 0; i < size * 2; i++)
+  {
+      printf("|");
+      for (j = 0; j < size; j++)
+          printf("%c%c", p[j] & 0xf0 ? 'X' : ' ', p[j] & 0xf ? 'X' : ' ');
+      printf(" -- ");
+      for (j = 0; j < size; j++)
+          printf("%c%c", q[j] & 0xf0 ? 'X' : ' ', q[j] & 0xf ? 'X' : ' ');
+      printf("|\n");
+      p += size * 4;
+      q += size * 4;
+  }
+  printf("\n");
+}
+#endif
+
+static void check_bits(HWND hwnd, HIMAGELIST himl, int idx, int size,
+                       const BYTE *checkbits, LPCSTR loc)
+{
+#ifdef VISIBLE
+    BYTE bits[100*100/8];
+    COLORREF c;
+    HDC hdc;
+    int x, y, i = -1;
+
+    if (!himl) return;
+
+    memset(bits, 0, sizeof(bits));
+    hdc = show_image(hwnd, himl, idx, size, loc, FALSE);
+
+    c = GetPixel(hdc, 0, 0);
+
+    for (y = 0; y < size; y ++)
+    {
+        for (x = 0; x < size; x++)
+        {
+            if (!(x & 0x7)) i++;
+            if (GetPixel(hdc, x, y) != c) bits[i] |= (0x80 >> (x & 0x7));
+        }
+    }
+
+    BitBlt(hdc, 0, 0, size, size, hdc, size+1, size+1, SRCCOPY);
+    ReleaseDC(hwnd, hdc);
+
+    ok (memcmp(bits, checkbits, (size * size)/8) == 0,
+        "%s: bits different\n", loc);
+    if (memcmp(bits, checkbits, (size * size)/8))
+        dump_bits(bits, checkbits, size);
+#endif /* VISIBLE */
+}
+
+static void testHotspot (void)
+{
+    struct hotspot {
+        int dx;
+        int dy;
+    };
+
+#define SIZEX1 47
+#define SIZEY1 31
+#define SIZEX2 11
+#define SIZEY2 17
+#define HOTSPOTS_MAX 4       /* Number of entries in hotspots */
+    static const struct hotspot hotspots[HOTSPOTS_MAX] = {
+        { 10, 7 },
+        { SIZEX1, SIZEY1 },
+        { -9, -8 },
+        { -7, 35 }
+    };
+    int i, j, ret;
+    HIMAGELIST himl1 = createImageList(SIZEX1, SIZEY1);
+    HIMAGELIST himl2 = createImageList(SIZEX2, SIZEY2);
+    HWND hwnd = create_a_window();
+
+
+    for (i = 0; i < HOTSPOTS_MAX; i++) {
+        for (j = 0; j < HOTSPOTS_MAX; j++) {
+            int dx1 = hotspots[i].dx;
+            int dy1 = hotspots[i].dy;
+            int dx2 = hotspots[j].dx;
+            int dy2 = hotspots[j].dy;
+            int correctx, correcty, newx, newy;
+            char loc[256];
+            HIMAGELIST himlNew;
+            POINT ppt;
+
+            ret = ImageList_BeginDrag(himl1, 0, dx1, dy1);
+            ok(ret != 0, "BeginDrag failed for { %d, %d }\n", dx1, dy1);
+            sprintf(loc, "BeginDrag (%d,%d)\n", i, j);
+            show_image(hwnd, himl1, 0, max(SIZEX1, SIZEY1), loc, TRUE);
+
+            /* check merging the dragged image with a second image */
+            ret = ImageList_SetDragCursorImage(himl2, 0, dx2, dy2);
+            ok(ret != 0, "SetDragCursorImage failed for {%d, %d}{%d, %d}\n",
+                    dx1, dy1, dx2, dy2);
+            sprintf(loc, "SetDragCursorImage (%d,%d)\n", i, j);
+            show_image(hwnd, himl2, 0, max(SIZEX2, SIZEY2), loc, TRUE);
+
+            /* check new hotspot, it should be the same like the old one */
+            himlNew = ImageList_GetDragImage(NULL, &ppt);
+            ok(ppt.x == dx1 && ppt.y == dy1,
+                    "Expected drag hotspot [%d,%d] got [%ld,%ld]\n",
+                    dx1, dy1, ppt.x, ppt.y);
+            /* check size of new dragged image */
+            ImageList_GetIconSize(himlNew, &newx, &newy);
+            correctx = max(SIZEX1, max(SIZEX2 + dx2, SIZEX1 - dx2));
+            correcty = max(SIZEY1, max(SIZEY2 + dy2, SIZEY1 - dy2));
+            ok(newx == correctx && newy == correcty,
+                    "Expected drag image size [%d,%d] got [%d,%d]\n",
+                    correctx, correcty, newx, newy);
+            sprintf(loc, "GetDragImage (%d,%d)\n", i, j);
+            show_image(hwnd, himlNew, 0, max(correctx, correcty), loc, TRUE);
+            ImageList_EndDrag();
+        }
+    }
+#undef SIZEX1
+#undef SIZEY1
+#undef SIZEX2
+#undef SIZEY2
+#undef HOTSPOTS_MAX
+    DestroyWindow(hwnd);
+}
+
+static BOOL DoTest1(void)
+{
+    HIMAGELIST himl ;
+
+    HICON hicon1 ;
+    HICON hicon2 ;
+    HICON hicon3 ;
+
+    /* create an imagelist to play with */
+    himl = ImageList_Create(84,84,0x10,0,3);
+    ok(himl!=0,"failed to create imagelist\n");
+
+    /* load the icons to add to the image list */
+    hicon1 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
+    ok(hicon1 != 0, "no hicon1\n");
+    hicon2 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
+    ok(hicon2 != 0, "no hicon2\n");
+    hicon3 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
+    ok(hicon3 != 0, "no hicon3\n");
+
+    /* remove when nothing exists */
+    ok(!ImageList_Remove(himl,0),"removed nonexistent icon\n");
+    /* removing everything from an empty imagelist should succeed */
+    ok(ImageList_RemoveAll(himl),"removed nonexistent icon\n");
+
+    /* add three */
+    ok(0==ImageList_AddIcon(himl, hicon1),"failed to add icon1\n");
+    ok(1==ImageList_AddIcon(himl, hicon2),"failed to add icon2\n");
+    ok(2==ImageList_AddIcon(himl, hicon3),"failed to add icon3\n");
+
+    /* remove an index out of range */
+    ok(!ImageList_Remove(himl,4711),"removed nonexistent icon\n");
+
+    /* remove three */
+    ok(ImageList_Remove(himl,0),"can't remove 0\n");
+    ok(ImageList_Remove(himl,0),"can't remove 0\n");
+    ok(ImageList_Remove(himl,0),"can't remove 0\n");
+
+    /* remove one extra */
+    ok(!ImageList_Remove(himl,0),"removed nonexistent icon\n");
+
+    /* destroy it */
+    ok(ImageList_Destroy(himl),"destroy imagelist failed\n");
+
+    /* icons should be deleted by the imagelist */
+    ok(!DeleteObject(hicon1),"icon 1 wasn't deleted\n");
+    ok(!DeleteObject(hicon2),"icon 2 wasn't deleted\n");
+    ok(!DeleteObject(hicon3),"icon 3 wasn't deleted\n");
+
+    return TRUE;
+}
+
+static BOOL DoTest2(void)
+{
+    HIMAGELIST himl ;
+
+    HICON hicon1 ;
+    HICON hicon2 ;
+    HICON hicon3 ;
+
+    /* create an imagelist to play with */
+    himl = ImageList_Create(84,84,0x10,0,3);
+    ok(himl!=0,"failed to create imagelist\n");
+
+    /* load the icons to add to the image list */
+    hicon1 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
+    ok(hicon1 != 0, "no hicon1\n");
+    hicon2 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
+    ok(hicon2 != 0, "no hicon2\n");
+    hicon3 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
+    ok(hicon3 != 0, "no hicon3\n");
+
+    /* add three */
+    ok(0==ImageList_AddIcon(himl, hicon1),"failed to add icon1\n");
+    ok(1==ImageList_AddIcon(himl, hicon2),"failed to add icon2\n");
+    ok(2==ImageList_AddIcon(himl, hicon3),"failed to add icon3\n");
+
+    /* destroy it */
+    ok(ImageList_Destroy(himl),"destroy imagelist failed\n");
+
+    /* icons should be deleted by the imagelist */
+    ok(!DeleteObject(hicon1),"icon 1 wasn't deleted\n");
+    ok(!DeleteObject(hicon2),"icon 2 wasn't deleted\n");
+    ok(!DeleteObject(hicon3),"icon 3 wasn't deleted\n");
+
+    return TRUE;
+}
+
+static BOOL DoTest3(void)
+{
+    HIMAGELIST himl;
+
+    HBITMAP hbm1;
+    HBITMAP hbm2;
+    HBITMAP hbm3;
+
+    IMAGELISTDRAWPARAMS imldp;
+    HDC hdc;
+    HWND hwndfortest;
+
+    if (!pImageList_DrawIndirect)
+    {
+        HMODULE hComCtl32 = LoadLibraryA("comctl32.dll");
+        pImageList_DrawIndirect = (void*)GetProcAddress(hComCtl32, "ImageList_DrawIndirect");
+        if (!pImageList_DrawIndirect)
+        {
+            trace("ImageList_DrawIndirect not available, skipping test\n");
+            return TRUE;
+        }
+    }
+
+    hwndfortest = create_a_window();
+    hdc = GetDC(hwndfortest);
+    ok(hdc!=NULL, "couldn't get DC\n");
+
+    /* create an imagelist to play with */
+    himl = ImageList_Create(48,48,0x10,0,3);
+    ok(himl!=0,"failed to create imagelist\n");
+
+    /* load the icons to add to the image list */
+    hbm1 = CreateBitmap(48, 48, 1, 1, bitmap_bits);
+    ok(hbm1 != 0, "no bitmap 1\n");
+    hbm2 = CreateBitmap(48, 48, 1, 1, bitmap_bits);
+    ok(hbm2 != 0, "no bitmap 2\n");
+    hbm3 = CreateBitmap(48, 48, 1, 1, bitmap_bits);
+    ok(hbm3 != 0, "no bitmap 3\n");
+
+    /* add three */
+    ok(0==ImageList_Add(himl, hbm1, 0),"failed to add bitmap 1\n");
+    ok(1==ImageList_Add(himl, hbm2, 0),"failed to add bitmap 2\n");
+
+    ok(ImageList_SetImageCount(himl,3),"Setimage count failed\n");
+    /*ok(2==ImageList_Add(himl, hbm3, NULL),"failed to add bitmap 3\n"); */
+    ok(ImageList_Replace(himl, 2, hbm3, 0),"failed to replace bitmap 3\n");
+
+    memset(&imldp, 0, sizeof (imldp));
+    ok(!pImageList_DrawIndirect(&imldp), "zero data succeeded!\n");
+    imldp.cbSize = sizeof (imldp);
+    ok(!pImageList_DrawIndirect(&imldp), "zero hdc succeeded!\n");
+    imldp.hdcDst = hdc;
+    ok(!pImageList_DrawIndirect(&imldp),"zero himl succeeded!\n");
+    imldp.himl = himl;
+    if (!pImageList_DrawIndirect(&imldp))
+    {
+      /* Earlier versions of native comctl32 use a smaller structure */
+      imldp.cbSize -= 3 * sizeof(DWORD);
+      ok(pImageList_DrawIndirect(&imldp),"DrawIndirect should succeed\n");
+    }
+    REDRAW(hwndfortest);
+    WAIT;
+
+    imldp.fStyle = SRCCOPY;
+    imldp.rgbBk = CLR_DEFAULT;
+    imldp.rgbFg = CLR_DEFAULT;
+    imldp.y = 100;
+    imldp.x = 100;
+    ok(pImageList_DrawIndirect(&imldp),"should succeed\n");
+    imldp.i ++;
+    ok(pImageList_DrawIndirect(&imldp),"should succeed\n");
+    imldp.i ++;
+    ok(pImageList_DrawIndirect(&imldp),"should succeed\n");
+    imldp.i ++;
+    ok(!pImageList_DrawIndirect(&imldp),"should fail\n");
+
+    /* remove three */
+    ok(ImageList_Remove(himl, 0), "removing 1st bitmap\n");
+    ok(ImageList_Remove(himl, 0), "removing 2nd bitmap\n");
+    ok(ImageList_Remove(himl, 0), "removing 3rd bitmap\n");
+
+    /* destroy it */
+    ok(ImageList_Destroy(himl),"destroy imagelist failed\n");
+
+    /* bitmaps should not be deleted by the imagelist */
+    ok(DeleteObject(hbm1),"bitmap 1 can't be deleted\n");
+    ok(DeleteObject(hbm2),"bitmap 2 can't be deleted\n");
+    ok(DeleteObject(hbm3),"bitmap 3 can't be deleted\n");
+
+    ReleaseDC(hwndfortest, hdc);
+    DestroyWindow(hwndfortest);
+
+    return TRUE;
+}
+
+static void testMerge(void)
+{
+    HIMAGELIST himl1, himl2, hmerge;
+    HICON hicon1;
+    HWND hwnd = create_a_window();
+
+    himl1 = ImageList_Create(32,32,0,0,3);
+    ok(himl1 != NULL,"failed to create himl1\n");
+
+    himl2 = ImageList_Create(32,32,0,0,3);
+    ok(himl2 != NULL,"failed to create himl2\n");
+
+    hicon1 = CreateIcon(hinst, 32, 32, 1, 1, icon_bits, icon_bits);
+    ok(hicon1 != NULL, "failed to create hicon1\n");
+
+    if (!himl1 || !himl2 || !hicon1)
+        return;
+
+    ok(0==ImageList_AddIcon(himl2, hicon1),"add icon1 to himl2 failed\n");
+    check_bits(hwnd, himl2, 0, 32, icon_bits, "add icon1 to himl2");
+
+    /* If himl1 has no images, merge still succeeds */
+    hmerge = ImageList_Merge(himl1, -1, himl2, 0, 0, 0);
+    ok(hmerge != NULL, "merge himl1,-1 failed\n");
+    check_bits(hwnd, hmerge, 0, 32, empty_bits, "merge himl1,-1");
+    if (hmerge) ImageList_Destroy(hmerge);
+
+    hmerge = ImageList_Merge(himl1, 0, himl2, 0, 0, 0);
+    ok(hmerge != NULL,"merge himl1,0 failed\n");
+    check_bits(hwnd, hmerge, 0, 32, empty_bits, "merge himl1,0");
+    if (hmerge) ImageList_Destroy(hmerge);
+
+    /* Same happens if himl2 is empty */
+    ImageList_Destroy(himl2);
+    himl2 = ImageList_Create(32,32,0,0,3);
+    ok(himl2 != NULL,"failed to recreate himl2\n");
+    if (!himl2)
+        return;
+
+    hmerge = ImageList_Merge(himl1, -1, himl2, -1, 0, 0);
+    ok(hmerge != NULL, "merge himl2,-1 failed\n");
+    check_bits(hwnd, hmerge, 0, 32, empty_bits, "merge himl2,-1");
+    if (hmerge) ImageList_Destroy(hmerge);
+
+    hmerge = ImageList_Merge(himl1, -1, himl2, 0, 0, 0);
+    ok(hmerge != NULL, "merge himl2,0 failed\n");
+    check_bits(hwnd, hmerge, 0, 32, empty_bits, "merge himl2,0");
+    if (hmerge) ImageList_Destroy(hmerge);
+
+    /* Now try merging an image with itself */
+    ok(0==ImageList_AddIcon(himl2, hicon1),"re-add icon1 to himl2 failed\n");
+
+    hmerge = ImageList_Merge(himl2, 0, himl2, 0, 0, 0);
+    ok(hmerge != NULL, "merge himl2 with itself failed\n");
+    check_bits(hwnd, hmerge, 0, 32, empty_bits, "merge himl2 with itself");
+    if (hmerge) ImageList_Destroy(hmerge);
+
+    /* Try merging 2 different image lists */
+    ok(0==ImageList_AddIcon(himl1, hicon1),"add icon1 to himl1 failed\n");
+
+    hmerge = ImageList_Merge(himl1, 0, himl2, 0, 0, 0);
+    ok(hmerge != NULL, "merge himl1 with himl2 failed\n");
+    check_bits(hwnd, hmerge, 0, 32, empty_bits, "merge himl1 with himl2");
+    if (hmerge) ImageList_Destroy(hmerge);
+
+    hmerge = ImageList_Merge(himl1, 0, himl2, 0, 8, 16);
+    ok(hmerge != NULL, "merge himl1 with himl2 8,16 failed\n");
+    check_bits(hwnd, hmerge, 0, 32, empty_bits, "merge himl1 with himl2, 8,16");
+    if (hmerge) ImageList_Destroy(hmerge);
+
+    ImageList_Destroy(himl1);
+    ImageList_Destroy(himl2);
+    DeleteObject(hicon1);
+    DestroyWindow(hwnd);
+}
+
+START_TEST(imagelist)
+{
+    desktopDC=GetDC(NULL);
+    hinst = GetModuleHandleA(NULL);
+
+    InitCommonControls();
+
+    testHotspot();
+    DoTest1();
+    DoTest2();
+    DoTest3();
+    testMerge();
+}
diff --git a/rostests/winetests/comctl32/listview.c b/rostests/winetests/comctl32/listview.c
new file mode 100644 (file)
index 0000000..dd99df9
--- /dev/null
@@ -0,0 +1,235 @@
+/*
+ * ListView tests
+ *
+ * Copyright 2006 Mike McCormack for CodeWeavers
+ *
+ * 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 <stdio.h>
+#include <windows.h>
+#include <commctrl.h>
+
+#include "wine/test.h"
+
+static void test_images(void)
+{
+    HWND hwnd, hwndparent = 0;
+    DWORD r;
+    LVITEM item;
+    HIMAGELIST himl;
+    HBITMAP hbmp;
+    RECT r1, r2;
+    static CHAR hello[] = "hello";
+
+    himl = ImageList_Create(40, 40, 0, 4, 4);
+    ok(himl != NULL, "failed to create imagelist\n");
+
+    hbmp = CreateBitmap(40, 40, 1, 1, NULL);
+    ok(hbmp != NULL, "failed to create bitmap\n");
+
+    r = ImageList_Add(himl, hbmp, 0);
+    ok(r == 0, "should be zero\n");
+
+    hwnd = CreateWindowEx(0, "SysListView32", "foo", LVS_OWNERDRAWFIXED, 
+                10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
+    ok(hwnd != NULL, "failed to create listview window\n");
+
+    r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, 0x940);
+    ok(r == 0, "should return zero\n");
+
+    r = SendMessage(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)himl);
+    ok(r == 0, "should return zero\n");
+
+    r = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELONG(100,50));
+    /* returns dimensions */
+
+    r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
+    ok(r == 0, "should be zero items\n");
+
+    item.mask = LVIF_IMAGE | LVIF_TEXT;
+    item.iItem = 0;
+    item.iSubItem = 1;
+    item.iImage = 0;
+    r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
+    ok(r == -1, "should fail\n");
+
+    item.iSubItem = 0;
+    item.pszText = hello;
+    r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
+    ok(r == 0, "should not fail\n");
+
+    memset(&r1, 0, sizeof r1);
+    r1.left = LVIR_ICON;
+    r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM) &r1);
+
+    r = SendMessage(hwnd, LVM_DELETEALLITEMS, 0, 0);
+    ok(r == TRUE, "should not fail\n");
+
+    item.iSubItem = 0;
+    item.pszText = hello;
+    r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
+    ok(r == 0, "should not fail\n");
+
+    memset(&r2, 0, sizeof r2);
+    r2.left = LVIR_ICON;
+    r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM) &r2);
+
+    ok(!memcmp(&r1, &r2, sizeof r1), "rectangle should be the same\n");
+
+    DestroyWindow(hwnd);
+}
+
+static void test_checkboxes(void)
+{
+    HWND hwnd, hwndparent = 0;
+    LVITEMA item;
+    DWORD r;
+    static CHAR text[]  = "Text",
+                text2[] = "Text2",
+                text3[] = "Text3";
+
+    hwnd = CreateWindowEx(0, "SysListView32", "foo", LVS_REPORT, 
+                10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
+    ok(hwnd != NULL, "failed to create listview window\n");
+
+    /* first without LVS_EX_CHECKBOXES set and an item and check that state is preserved */
+    item.mask = LVIF_TEXT | LVIF_STATE;
+    item.stateMask = 0xffff;
+    item.state = 0xfccc;
+    item.iItem = 0;
+    item.iSubItem = 0;
+    item.pszText = text;
+    r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
+    ok(r == 0, "ret %ld\n", r);
+
+    item.iItem = 0;
+    item.mask = LVIF_STATE;
+    item.stateMask = 0xffff;
+    r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
+    ok(item.state == 0xfccc, "state %x\n", item.state);
+
+    /* Don't set LVIF_STATE */
+    item.mask = LVIF_TEXT;
+    item.stateMask = 0xffff;
+    item.state = 0xfccc;
+    item.iItem = 1;
+    item.iSubItem = 0;
+    item.pszText = text;
+    r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
+    ok(r == 1, "ret %ld\n", r);
+
+    item.iItem = 1;
+    item.mask = LVIF_STATE;
+    item.stateMask = 0xffff;
+    r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
+    ok(item.state == 0, "state %x\n", item.state);
+
+    r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
+    ok(r == 0, "should return zero\n");
+
+    /* Having turned on checkboxes, check that all existing items are set to 0x1000 (unchecked) */
+    item.iItem = 0;
+    item.mask = LVIF_STATE;
+    item.stateMask = 0xffff;
+    r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
+    ok(item.state == 0x1ccc, "state %x\n", item.state);
+
+    /* Now add an item without specifying a state and check that it's state goes to 0x1000 */
+    item.iItem = 2;
+    item.mask = LVIF_TEXT;
+    item.state = 0;
+    item.pszText = text2;
+    r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
+    ok(r == 2, "ret %ld\n", r);
+
+    item.iItem = 2;
+    item.mask = LVIF_STATE;
+    item.stateMask = 0xffff;
+    r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
+    ok(item.state == 0x1000, "state %x\n", item.state);
+
+    /* Add a further item this time specifying a state and still it's state goes to 0x1000 */
+    item.iItem = 3;
+    item.mask = LVIF_TEXT | LVIF_STATE;
+    item.stateMask = 0xffff;
+    item.state = 0x2aaa;
+    item.pszText = text3;
+    r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
+    ok(r == 3, "ret %ld\n", r);
+
+    item.iItem = 3;
+    item.mask = LVIF_STATE;
+    item.stateMask = 0xffff;
+    r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
+    ok(item.state == 0x1aaa, "state %x\n", item.state);
+
+    /* Set an item's state to checked */
+    item.iItem = 3;
+    item.mask = LVIF_STATE;
+    item.stateMask = 0xf000;
+    item.state = 0x2000;
+    r = SendMessage(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
+
+    item.iItem = 3;
+    item.mask = LVIF_STATE;
+    item.stateMask = 0xffff;
+    r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
+    ok(item.state == 0x2aaa, "state %x\n", item.state);
+
+    /* Set the style again and check that doesn't change an item's state */
+    r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
+    ok(r == LVS_EX_CHECKBOXES, "ret %lx\n", r);
+
+    item.iItem = 3;
+    item.mask = LVIF_STATE;
+    item.stateMask = 0xffff;
+    r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
+    ok(item.state == 0x2aaa, "state %x\n", item.state);
+
+    /* Unsetting the checkbox extended style doesn't change an item's state */
+    r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, 0);
+    ok(r == LVS_EX_CHECKBOXES, "ret %lx\n", r);
+
+    item.iItem = 3;
+    item.mask = LVIF_STATE;
+    item.stateMask = 0xffff;
+    r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
+    ok(item.state == 0x2aaa, "state %x\n", item.state);
+
+    /* Now setting the style again will change an item's state */
+    r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
+    ok(r == 0, "ret %lx\n", r);
+
+    item.iItem = 3;
+    item.mask = LVIF_STATE;
+    item.stateMask = 0xffff;
+    r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
+    ok(item.state == 0x1aaa, "state %x\n", item.state);
+
+    DestroyWindow(hwnd);
+}
+
+START_TEST(listview)
+{
+    INITCOMMONCONTROLSEX icc;
+
+    icc.dwICC = 0;
+    icc.dwSize = sizeof icc;
+    InitCommonControlsEx(&icc);
+
+    test_images();
+    test_checkboxes();
+}
diff --git a/rostests/winetests/comctl32/monthcal.c b/rostests/winetests/comctl32/monthcal.c
new file mode 100644 (file)
index 0000000..89c9ae4
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * comctl32 month calendar unit tests
+ *
+ * Copyright (C) 2006 Vitaliy Margolen
+ *
+ * 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 "windows.h"
+
+#include "commctrl.h"
+
+#include "wine/test.h"
+
+void test_monthcal(void)
+{
+    HWND hwnd;
+    SYSTEMTIME st[2], st1[2];
+    INITCOMMONCONTROLSEX ic = {sizeof(INITCOMMONCONTROLSEX), ICC_DATE_CLASSES};
+    int res, month_range;
+
+    InitCommonControlsEx(&ic);
+    hwnd = CreateWindowA(MONTHCAL_CLASSA, "MonthCal", WS_POPUP | WS_VISIBLE, CW_USEDEFAULT,
+                         0, 300, 300, 0, 0, NULL, NULL);
+    ok(hwnd != NULL, "Failed to create MonthCal\n");
+    GetSystemTime(&st[0]);
+    st[1] = st[0];
+
+    /* Invalid date/time */
+    st[0].wYear  = 2000;
+    /* Time should not matter */
+    st[1].wHour = st[1].wMinute = st[1].wSecond = 70;
+    ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Failed to set MAX limit\n");
+    ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MAX, "No limits should be set\n");
+    ok(st1[0].wYear != 2000, "Lover limit changed\n");
+
+    st[1].wMonth = 0;
+    ok(!SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st), "Should have failed to set limits\n");
+    ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MAX, "No limits should be set\n");
+    ok(st1[0].wYear != 2000, "Lover limit changed\n");
+    ok(!SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Should have failed to set MAX limit\n");
+    ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MAX, "No limits should be set\n");
+    ok(st1[0].wYear != 2000, "Lover limit changed\n");
+
+    GetSystemTime(&st[0]);
+    st[0].wDay = 20;
+    st[0].wMonth = 5;
+    st[1] = st[0];
+
+    month_range = SendMessage(hwnd, MCM_GETMONTHRANGE, GMR_VISIBLE, (LPARAM)st1);
+    st[1].wMonth--;
+    ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st), "Failed to set both min and max limits\n");
+    res = SendMessage(hwnd, MCM_GETMONTHRANGE, GMR_VISIBLE, (LPARAM)st1);
+    ok(res == month_range, "Invalid month range (%d)\n", res);
+    ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == (GDTR_MIN|GDTR_MAX), "Limits should be set\n");
+
+    st[1].wMonth += 2;
+    ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st), "Failed to set both min and max limits\n");
+    res = SendMessage(hwnd, MCM_GETMONTHRANGE, GMR_VISIBLE, (LPARAM)st1);
+    ok(res == month_range, "Invalid month range (%d)\n", res);
+
+    st[1].wYear --;
+    ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st), "Failed to set both min and max limits\n");
+    st[1].wYear += 1;
+    ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MIN | GDTR_MAX, (LPARAM)st), "Failed to set both min and max limits\n");
+
+    st[1].wMonth -= 3;
+    ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Failed to set max limit\n");
+    ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MAX, "Only MAX limit should be set\n");
+    st[1].wMonth += 4;
+    ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Failed to set max limit\n");
+    st[1].wYear -= 3;
+    ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Failed to set max limit\n");
+    st[1].wYear += 4;
+    ok(SendMessage(hwnd, MCM_SETRANGE, GDTR_MAX, (LPARAM)st), "Failed to set max limit\n");
+    ok(SendMessage(hwnd, MCM_GETRANGE, 0, (LPARAM)st1) == GDTR_MAX, "Only MAX limit should be set\n");
+}
+
+START_TEST(monthcal)
+{
+    test_monthcal();
+}
diff --git a/rostests/winetests/comctl32/mru.c b/rostests/winetests/comctl32/mru.c
new file mode 100644 (file)
index 0000000..5b51736
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ * comctl32 MRU unit tests
+ *
+ * Copyright (C) 2004 Jon Griffiths <jon_p_griffiths@yahoo.com>
+ *
+ * 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 "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "winnls.h"
+#include "winreg.h"
+#include "commctrl.h"
+#include "shlwapi.h"
+
+#include "wine/test.h"
+
+/* Keys for testing MRU functions */
+#define REG_TEST_BASEKEYA    "Software\\Wine"
+#define REG_TEST_BASESUBKEYA "Test"
+#define REG_TEST_KEYA    REG_TEST_BASEKEYA "\\" REG_TEST_BASESUBKEYA
+#define REG_TEST_SUBKEYA "MRUTest"
+#define REG_TEST_FULLKEY REG_TEST_KEYA "\\" REG_TEST_SUBKEYA
+
+/* Undocumented MRU structures & functions */
+typedef struct tagCREATEMRULISTA
+{
+    DWORD   cbSize;
+    DWORD   nMaxItems;
+    DWORD   dwFlags;
+    HKEY    hKey;
+    LPCSTR  lpszSubKey;
+    PROC    lpfnCompare;
+} CREATEMRULISTA, *LPCREATEMRULISTA;
+
+#define MRUF_STRING_LIST  0
+#define MRUF_BINARY_LIST  1
+#define MRUF_DELAYED_SAVE 2
+
+#define LIST_SIZE 3 /* Max entries for each mru */
+
+static CREATEMRULISTA mruA =
+{
+    sizeof(CREATEMRULISTA),
+    LIST_SIZE,
+    0,
+    NULL,
+    REG_TEST_SUBKEYA,
+    NULL
+};
+
+static HMODULE hComctl32;
+static HANDLE (WINAPI *pCreateMRUListA)(LPCREATEMRULISTA);
+static void   (WINAPI *pFreeMRUList)(HANDLE);
+static INT    (WINAPI *pAddMRUStringA)(HANDLE,LPCSTR);
+/*
+static INT    (WINAPI *pFindMRUStringA)(HANDLE,LPCSTR,LPINT);
+static INT    (WINAPI *pEnumMRUList)(HANDLE,INT,LPVOID,DWORD);
+*/
+
+static BOOL create_reg_entries(void)
+{
+    HKEY hKey = NULL;
+
+    ok(!RegCreateKeyA(HKEY_CURRENT_USER, REG_TEST_FULLKEY, &hKey),
+       "Couldn't create test key \"%s\"\n", REG_TEST_KEYA);
+    if (!hKey) return FALSE;
+    RegCloseKey(hKey);
+    return TRUE;
+}
+
+static void delete_reg_entries(void)
+{
+    HKEY hKey;
+
+    if (RegOpenKeyExA(HKEY_CURRENT_USER, REG_TEST_BASEKEYA, 0, KEY_ALL_ACCESS,
+                      &hKey))
+        return;
+    SHDeleteKeyA(hKey, REG_TEST_BASESUBKEYA);
+    RegCloseKey(hKey);
+}
+
+static void check_reg_entries(const char *mrulist, const char**items)
+{
+    char buff[128];
+    HKEY hKey = NULL;
+    DWORD type, size, ret;
+    unsigned int i;
+
+    ok(!RegOpenKeyA(HKEY_CURRENT_USER, REG_TEST_FULLKEY, &hKey),
+       "Couldn't open test key \"%s\"\n", REG_TEST_FULLKEY);
+    if (!hKey) return;
+
+    type = REG_SZ;
+    size = sizeof(buff);
+    buff[0] = '\0';
+    ret = RegQueryValueExA(hKey, "MRUList", NULL, &type, (LPBYTE)buff, &size);
+
+    ok(!ret && buff[0], "Checking MRU: got %ld from RegQueryValueExW\n", ret);
+    if(ret || !buff[0]) return;
+
+    ok(strcmp(buff, mrulist) == 0, "Checking MRU: Expected list %s, got %s\n",
+       mrulist, buff);
+    if(strcmp(buff, mrulist)) return;
+
+    for (i = 0; i < strlen(mrulist); i++)
+    {
+        char name[2];
+        name[0] = mrulist[i];
+        name[1] = '\0';
+        type = REG_SZ;
+        size = sizeof(buff);
+        buff[0] = '\0';
+        ret = RegQueryValueExA(hKey, name, NULL, &type, (LPBYTE)buff, &size);
+        ok(!ret && buff[0],
+           "Checking MRU item %d ('%c'): got %ld from RegQueryValueExW\n",
+           i, mrulist[i], ret);
+        if(ret || !buff[0]) return;
+        ok(!strcmp(buff, items[mrulist[i]-'a']),
+           "Checking MRU item %d ('%c'): expected \"%s\", got \"%s\"\n",
+           i, mrulist[i], buff, items[mrulist[i] - 'a']);
+    }
+}
+
+static INT CALLBACK cmp_mru_strA(LPCVOID data1, LPCVOID data2)
+{
+    return lstrcmpiA(data1, data2);
+}
+
+static HANDLE create_mruA(HKEY hKey, DWORD flags, PROC cmp)
+{
+    mruA.dwFlags = flags;
+    mruA.lpfnCompare = cmp;
+    mruA.hKey = hKey;
+
+    SetLastError(0);
+    return pCreateMRUListA(&mruA);
+}
+
+static void test_MRUListA(void)
+{
+    const char *checks[LIST_SIZE+1];
+    HANDLE hMRU;
+    HKEY hKey;
+    INT iRet;
+
+    pCreateMRUListA = (void*)GetProcAddress(hComctl32,(LPCSTR)151);
+    pFreeMRUList = (void*)GetProcAddress(hComctl32,(LPCSTR)152);
+    pAddMRUStringA = (void*)GetProcAddress(hComctl32,(LPCSTR)153);
+    if (!pCreateMRUListA || !pFreeMRUList || !pAddMRUStringA)
+        return;
+
+#if 0 /* Create (NULL) - crashes native */
+    hMRU = pCreateMRUListA(NULL);
+#endif
+
+    /* Create (size too small) */
+    mruA.cbSize = sizeof(mruA) - 2;
+    hMRU = create_mruA(NULL, MRUF_STRING_LIST, cmp_mru_strA);
+    ok (!hMRU && !GetLastError(),
+        "CreateMRUListA(too small) expected NULL,0 got %p,%ld\n",
+        hMRU, GetLastError());
+    mruA.cbSize = sizeof(mruA);
+
+    /* Create (size too big) */
+    mruA.cbSize = sizeof(mruA) + 2;
+    hMRU = create_mruA(NULL, MRUF_STRING_LIST, cmp_mru_strA);
+    ok (!hMRU && !GetLastError(),
+        "CreateMRUListA(too big) expected NULL,0 got %p,%ld\n",
+        hMRU, GetLastError());
+    mruA.cbSize = sizeof(mruA);
+
+    /* Create (NULL hKey) */
+    hMRU = create_mruA(NULL, MRUF_STRING_LIST, cmp_mru_strA);
+    ok (!hMRU && !GetLastError(),
+        "CreateMRUListA(NULL key) expected NULL,0 got %p,%ld\n",
+        hMRU, GetLastError());
+
+    /* Create (NULL name) */
+    mruA.lpszSubKey = NULL;
+    hMRU = create_mruA(NULL, MRUF_STRING_LIST, cmp_mru_strA);
+    ok (!hMRU && !GetLastError(),
+        "CreateMRUListA(NULL name) expected NULL,0 got %p,%ld\n",
+        hMRU, GetLastError());
+    mruA.lpszSubKey = REG_TEST_SUBKEYA;
+
+    /* Create a string MRU */
+    ok(!RegCreateKeyA(HKEY_CURRENT_USER, REG_TEST_KEYA, &hKey),
+       "Couldn't create test key \"%s\"\n", REG_TEST_KEYA);
+    if (!hKey)
+        return;
+    hMRU = create_mruA(hKey, MRUF_STRING_LIST, cmp_mru_strA);
+    ok(hMRU && !GetLastError(),
+       "CreateMRUListA(string) expected non-NULL,0 got %p,%ld\n",
+       hMRU, GetLastError());
+
+    if (hMRU)
+    {
+        checks[0] = "Test 1";
+        checks[1] = "Test 2";
+        checks[2] = "Test 3";
+        checks[3] = "Test 4";
+
+        /* Add (NULL list) */
+        SetLastError(0);
+        iRet = pAddMRUStringA(NULL, checks[0]);
+        ok(iRet == -1 && !GetLastError(),
+           "AddMRUStringA(NULL list) expected -1,0 got %d,%ld\n",
+           iRet, GetLastError());
+
+        /* Add (NULL string) */
+#if 0
+       /* Some native versions crash when passed NULL or fail to SetLastError()  */
+        SetLastError(0);
+        iRet = pAddMRUStringA(hMRU, NULL);
+        ok(iRet == 0 && GetLastError() == ERROR_INVALID_PARAMETER,
+           "AddMRUStringA(NULL str) expected 0,ERROR_INVALID_PARAMETER got %d,%ld\n",
+           iRet, GetLastError());
+#endif
+
+        /* Add 3 strings. Check the registry is correct after each add */
+        SetLastError(0);
+        iRet = pAddMRUStringA(hMRU, checks[0]);
+        ok(iRet == 0 && !GetLastError(),
+           "AddMRUStringA(1) expected 0,0 got %d,%ld\n",
+           iRet, GetLastError());
+        check_reg_entries("a", checks);
+
+        SetLastError(0);
+        iRet = pAddMRUStringA(hMRU, checks[1]);
+        ok(iRet == 1 && !GetLastError(),
+           "AddMRUStringA(2) expected 1,0 got %d,%ld\n",
+           iRet, GetLastError());
+        check_reg_entries("ba", checks);
+
+        SetLastError(0);
+        iRet = pAddMRUStringA(hMRU, checks[2]);
+        ok(iRet == 2 && !GetLastError(),
+           "AddMRUStringA(2) expected 2,0 got %d,%ld\n",
+           iRet, GetLastError());
+        check_reg_entries("cba", checks);
+
+        /* Add a duplicate of the 2nd string - it should move to the front,
+         * but keep the same index in the registry.
+         */
+        SetLastError(0);
+        iRet = pAddMRUStringA(hMRU, checks[1]);
+        ok(iRet == 1 && !GetLastError(),
+           "AddMRUStringA(re-add 1) expected 1,0 got %d,%ld\n",
+           iRet, GetLastError());
+        check_reg_entries("bca", checks);
+
+        /* Add a new string - replaces the oldest string + moves to the front */
+        SetLastError(0);
+        iRet = pAddMRUStringA(hMRU, checks[3]);
+        ok(iRet == 0 && !GetLastError(),
+           "AddMRUStringA(add new) expected 0,0 got %d,%ld\n",
+           iRet, GetLastError());
+        checks[0] = checks[3];
+        check_reg_entries("abc", checks);
+
+        /* Finished with this MRU */
+        pFreeMRUList(hMRU);
+    }
+
+    /* Free (NULL list) - Doesn't crash */
+    pFreeMRUList(NULL);
+}
+
+START_TEST(mru)
+{
+    hComctl32 = GetModuleHandleA("comctl32.dll");
+    if (!hComctl32)
+        return;
+
+    delete_reg_entries();
+    if (!create_reg_entries())
+        return;
+
+    test_MRUListA();
+
+    delete_reg_entries();
+}
diff --git a/rostests/winetests/comctl32/progress.c b/rostests/winetests/comctl32/progress.c
new file mode 100644 (file)
index 0000000..9d801c9
--- /dev/null
@@ -0,0 +1,205 @@
+/* Unit tests for the progress bar control.
+ *
+ * Copyright 2005 Michael Kaufmann
+ *
+ * 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 <assert.h>
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "commctrl.h" 
+
+#include "wine/test.h"
+
+
+HWND hProgressParentWnd, hProgressWnd;
+static const char progressTestClass[] = "ProgressBarTestClass";
+
+
+LRESULT CALLBACK ProgressTestWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    switch(msg) {
+    
+    case WM_DESTROY:
+        PostQuitMessage(0);
+        break;
+  
+    default:
+        return DefWindowProcA(hWnd, msg, wParam, lParam);
+    }
+    
+    return 0L;
+}
+
+static WNDPROC progress_wndproc;
+static BOOL erased;
+static RECT last_paint_rect;
+
+LRESULT CALLBACK ProgressSubclassProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    if (msg == WM_PAINT)
+    {
+        GetUpdateRect(hWnd, &last_paint_rect, FALSE);
+    }
+    else if (msg == WM_ERASEBKGND)
+    {
+        erased = TRUE;
+    }
+    return CallWindowProc(progress_wndproc, hWnd, msg, wParam, lParam);
+}
+
+
+static void update_window(HWND hWnd)
+{
+    UpdateWindow(hWnd);
+    ok(!GetUpdateRect(hWnd, NULL, FALSE), "GetUpdateRect must return zero after UpdateWindow\n");    
+}
+
+
+static void init(void)
+{
+    WNDCLASSA wc;
+    INITCOMMONCONTROLSEX icex;
+    RECT rect;
+    
+    icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
+    icex.dwICC   = ICC_PROGRESS_CLASS;
+    InitCommonControlsEx(&icex);
+  
+    wc.style = CS_HREDRAW | CS_VREDRAW;
+    wc.cbClsExtra = 0;
+    wc.cbWndExtra = 0;
+    wc.hInstance = GetModuleHandleA(NULL);
+    wc.hIcon = NULL;
+    wc.hCursor = LoadCursorA(NULL, MAKEINTRESOURCEA(IDC_ARROW));
+    wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
+    wc.lpszMenuName = NULL;
+    wc.lpszClassName = progressTestClass;
+    wc.lpfnWndProc = ProgressTestWndProc;
+    RegisterClassA(&wc);
+    
+    rect.left = 0;
+    rect.top = 0;
+    rect.right = 400;
+    rect.bottom = 20;
+    assert(AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE));
+    
+    hProgressParentWnd = CreateWindowExA(0, progressTestClass, "Progress Bar Test", WS_OVERLAPPEDWINDOW,
+      CW_USEDEFAULT, CW_USEDEFAULT, rect.right - rect.left, rect.bottom - rect.top, NULL, NULL, GetModuleHandleA(NULL), 0);
+    assert(hProgressParentWnd != NULL);
+
+    GetClientRect(hProgressParentWnd, &rect);
+    hProgressWnd = CreateWindowEx(0, PROGRESS_CLASS, "", WS_CHILD | WS_VISIBLE,
+      0, 0, rect.right, rect.bottom, hProgressParentWnd, NULL, GetModuleHandleA(NULL), 0);
+    assert(hProgressWnd != NULL);
+    progress_wndproc = (WNDPROC)SetWindowLongPtr(hProgressWnd, GWLP_WNDPROC, (LPARAM)ProgressSubclassProc);
+    
+    ShowWindow(hProgressParentWnd, SW_SHOWNORMAL);
+    ok(GetUpdateRect(hProgressParentWnd, NULL, FALSE), "GetUpdateRect: There should be a region that needs to be updated\n");
+    update_window(hProgressParentWnd);    
+}
+
+
+static void cleanup(void)
+{
+    MSG msg;
+    
+    PostMessageA(hProgressParentWnd, WM_CLOSE, 0, 0);
+    while (GetMessageA(&msg,0,0,0)) {
+        TranslateMessage(&msg);
+        DispatchMessageA(&msg);
+    }
+    
+    UnregisterClassA(progressTestClass, GetModuleHandleA(NULL));
+}
+
+
+/*
+ * Tests if a progress bar repaints itself immediately when it receives
+ * some specific messages.
+ */
+static void test_redraw(void)
+{
+    RECT client_rect;
+
+    SendMessageA(hProgressWnd, PBM_SETRANGE, 0, MAKELPARAM(0, 100));
+    SendMessageA(hProgressWnd, PBM_SETPOS, 10, 0);
+    SendMessageA(hProgressWnd, PBM_SETSTEP, 20, 0);
+    update_window(hProgressWnd);
+
+    /* PBM_SETPOS */
+    ok(SendMessageA(hProgressWnd, PBM_SETPOS, 50, 0) == 10, "PBM_SETPOS must return the previous position\n");
+    ok(!GetUpdateRect(hProgressWnd, NULL, FALSE), "PBM_SETPOS: The progress bar should be redrawn immediately\n");
+    
+    /* PBM_DELTAPOS */
+    ok(SendMessageA(hProgressWnd, PBM_DELTAPOS, 15, 0) == 50, "PBM_DELTAPOS must return the previous position\n");
+    ok(!GetUpdateRect(hProgressWnd, NULL, FALSE), "PBM_DELTAPOS: The progress bar should be redrawn immediately\n");
+    
+    /* PBM_SETPOS */
+    ok(SendMessageA(hProgressWnd, PBM_SETPOS, 80, 0) == 65, "PBM_SETPOS must return the previous position\n");
+    ok(!GetUpdateRect(hProgressWnd, NULL, FALSE), "PBM_SETPOS: The progress bar should be redrawn immediately\n");
+    
+    /* PBM_STEPIT */
+    ok(SendMessageA(hProgressWnd, PBM_STEPIT, 0, 0) == 80, "PBM_STEPIT must return the previous position\n");
+    ok(!GetUpdateRect(hProgressWnd, NULL, FALSE), "PBM_STEPIT: The progress bar should be redrawn immediately\n");
+    ok((UINT)SendMessageA(hProgressWnd, PBM_GETPOS, 0, 0) == 100, "PBM_GETPOS returned a wrong position\n");
+    
+    /* PBM_SETRANGE and PBM_SETRANGE32:
+    Usually the progress bar doesn't repaint itself immediately. If the
+    position is not in the new range, it does.
+    Don't test this, it may change in future Windows versions. */
+
+    SendMessage(hProgressWnd, PBM_SETPOS, 0, 0);
+    update_window(hProgressWnd);
+
+    /* increase to 10 - no background erase required */
+    erased = FALSE;
+    SetRectEmpty(&last_paint_rect);
+    SendMessage(hProgressWnd, PBM_SETPOS, 10, 0);
+    GetClientRect(hProgressWnd, &client_rect);
+    ok(EqualRect(&last_paint_rect, &client_rect),
+       "last_paint_rect was { %ld, %ld, %ld, %ld } instead of { %ld, %ld, %ld, %ld }\n",
+       last_paint_rect.left, last_paint_rect.top, last_paint_rect.right, last_paint_rect.bottom,
+       client_rect.left, client_rect.top, client_rect.right, client_rect.bottom);
+    update_window(hProgressWnd);
+    ok(!erased, "Progress bar shouldn't have erased the background\n");
+
+    /* decrease to 0 - background erase will be required */
+    erased = FALSE;
+    SetRectEmpty(&last_paint_rect);
+    SendMessage(hProgressWnd, PBM_SETPOS, 0, 0);
+    GetClientRect(hProgressWnd, &client_rect);
+    ok(EqualRect(&last_paint_rect, &client_rect),
+       "last_paint_rect was { %ld, %ld, %ld, %ld } instead of { %ld, %ld, %ld, %ld }\n",
+       last_paint_rect.left, last_paint_rect.top, last_paint_rect.right, last_paint_rect.bottom,
+       client_rect.left, client_rect.top, client_rect.right, client_rect.bottom);
+    update_window(hProgressWnd);
+    ok(erased, "Progress bar should have erased the background\n");
+}
+
+
+START_TEST(progress)
+{
+    init();
+    
+    test_redraw();
+    
+    cleanup();
+}
diff --git a/rostests/winetests/comctl32/propsheet.c b/rostests/winetests/comctl32/propsheet.c
new file mode 100644 (file)
index 0000000..79be337
--- /dev/null
@@ -0,0 +1,107 @@
+/* Unit test suite for property sheet control.
+ *
+ * Copyright 2006 Huw Davies
+ *
+ * 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
+ */
+
+#define NONAMELESSUNION
+#define NONAMELESSSTRUCT
+
+#include <windows.h>
+#include <commctrl.h>
+
+#include "wine/test.h"
+
+static int CALLBACK sheet_callback(HWND hwnd, UINT msg, LPARAM lparam)
+{
+    switch(msg)
+    {
+    case PSCB_INITIALIZED:
+      {
+        char caption[256];
+        GetWindowTextA(hwnd, caption, sizeof(caption));
+        ok(!strcmp(caption,"test caption"), "caption: %s\n", caption);
+        return 0;
+      }
+    }
+    return 0;
+}
+        
+static INT_PTR CALLBACK page_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam,
+                                      LPARAM lparam)
+{
+    switch(msg)
+    {
+    case WM_INITDIALOG:
+      {
+        HWND sheet = GetParent(hwnd);
+        char caption[256];
+        GetWindowTextA(sheet, caption, sizeof(caption));
+        ok(!strcmp(caption,"test caption"), "caption: %s\n", caption);
+        return TRUE;
+      }
+
+    case WM_NOTIFY:
+      {
+        NMHDR *nmhdr = (NMHDR *)lparam;
+        switch(nmhdr->code)
+        {
+        case PSN_APPLY:
+            return TRUE;
+        default:
+            return FALSE;
+        }
+      }
+    default:
+        return FALSE;
+    }
+}
+
+static void test_title(void)
+{
+    HPROPSHEETPAGE hpsp[1];
+    PROPSHEETPAGEA psp;
+    PROPSHEETHEADERA psh;
+    HWND hdlg;
+
+    memset(&psp, 0, sizeof(psp));
+    psp.dwSize = sizeof(psp);
+    psp.dwFlags = 0;
+    psp.hInstance = GetModuleHandleW(NULL);
+    psp.u.pszTemplate = "prop_page1";
+    psp.u2.pszIcon = NULL;
+    psp.pfnDlgProc = page_dlg_proc;
+    psp.lParam = 0;
+
+    hpsp[0] = CreatePropertySheetPageA(&psp);
+
+    memset(&psh, 0, sizeof(psh));
+    psh.dwSize = sizeof(psh);
+    psh.dwFlags = PSH_MODELESS | PSH_USECALLBACK;
+    psh.pszCaption = "test caption";
+    psh.nPages = 1;
+    psh.hwndParent = GetDesktopWindow();
+    psh.u3.phpage = hpsp;
+    psh.pfnCallback = sheet_callback;
+
+    hdlg = (HWND)PropertySheetA(&psh);
+    DestroyWindow(hdlg);
+}
+
+START_TEST(propsheet)
+{
+    test_title();
+}
diff --git a/rostests/winetests/comctl32/propsheet.rc b/rostests/winetests/comctl32/propsheet.rc
new file mode 100644 (file)
index 0000000..2296141
--- /dev/null
@@ -0,0 +1,29 @@
+/* Resources for the unit test suite for property sheet control.
+ *
+ * Copyright 2006 Huw Davies
+ *
+ * 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 "windef.h"
+#include "winuser.h"
+
+PROP_PAGE1 DIALOG LOADONCALL MOVEABLE DISCARDABLE 5, 43, 227, 215
+STYLE  WS_POPUP | WS_CAPTION | WS_CLIPSIBLINGS | WS_VISIBLE
+CAPTION "Page1"
+FONT 8, "MS Shell Dlg"
+{
+ LTEXT "Test", -1, 10, 6, 100, 8
+}
diff --git a/rostests/winetests/comctl32/subclass.c b/rostests/winetests/comctl32/subclass.c
new file mode 100644 (file)
index 0000000..9455fbd
--- /dev/null
@@ -0,0 +1,298 @@
+/* Unit tests for subclassed windows.
+ *
+ * Copyright 2004 Kevin Koltzau
+ *
+ * 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 <assert.h>
+#include <stdarg.h>
+
+#define _WIN32_WINNT 0x0501 /* For SetWindowSubclass/etc */
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "commctrl.h"
+
+#include "wine/test.h"
+
+static BOOL (WINAPI *pSetWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR, DWORD_PTR);
+static BOOL (WINAPI *pRemoveWindowSubclass)(HWND, SUBCLASSPROC, UINT_PTR);
+static LRESULT (WINAPI *pDefSubclassProc)(HWND, UINT, WPARAM, LPARAM);
+
+#define SEND_NEST   0x01
+#define DELETE_SELF 0x02
+#define DELETE_PREV 0x04
+
+struct message {
+    int procnum;           /* WndProc id message is expected from */
+    WPARAM wParam;         /* expected value of wParam */
+};
+
+static int sequence_cnt, sequence_size;
+static struct message* sequence;
+
+static const struct message Sub_BasicTest[] = {
+    { 2, 1 },
+    { 1, 1 },
+    { 2, 2 },
+    { 1, 2 },
+    { 0 }
+};
+
+static const struct message Sub_DeletedTest[] = {
+    { 2, 1 },
+    { 1, 1 },
+    { 0 }
+};
+
+static const struct message Sub_AfterDeletedTest[] = {
+    { 1, 1 },
+    { 0 }
+};
+
+static const struct message Sub_OldAfterNewTest[] = {
+    { 3, 1 },
+    { 2, 1 },
+    { 1, 1 },
+    { 3, 2 },
+    { 2, 2 },
+    { 1, 2 },
+    { 0 }
+};
+
+static const struct message Sub_MixTest[] = {
+    { 3, 1 },
+    { 4, 1 },
+    { 2, 1 },
+    { 1, 1 },
+    { 0 }
+};
+
+static const struct message Sub_MixAndNestTest[] = {
+    { 3, 1 },
+    { 4, 1 },
+    { 3, 2 },
+    { 4, 2 },
+    { 2, 2 },
+    { 1, 2 },
+    { 2, 1 },
+    { 1, 1 },
+    { 0 }
+};
+
+static const struct message Sub_MixNestDelTest[] = {
+    { 3, 1 },
+    { 4, 1 },
+    { 3, 2 },
+    { 2, 2 },
+    { 1, 2 },
+    { 2, 1 },
+    { 1, 1 },
+    { 0 }
+};
+
+static const struct message Sub_MixDelPrevTest[] = {
+    { 3, 1 },
+    { 5, 1 },
+    { 2, 1 },
+    { 1, 1 },
+    { 0 }
+};
+
+static void add_message(const struct message *msg)
+{
+    if (!sequence)
+    {
+        sequence_size = 10;
+        sequence = HeapAlloc( GetProcessHeap(), 0, sequence_size * sizeof (struct message) );
+    }
+    if (sequence_cnt == sequence_size)
+    {
+        sequence_size *= 2;
+        sequence = HeapReAlloc( GetProcessHeap(), 0, sequence, sequence_size * sizeof (struct message) );
+    }
+    assert(sequence);
+
+    sequence[sequence_cnt].wParam  = msg->wParam;
+    sequence[sequence_cnt].procnum = msg->procnum;
+
+    sequence_cnt++;
+}
+
+static void flush_sequence(void)
+{
+    HeapFree(GetProcessHeap(), 0, sequence);
+    sequence = 0;
+    sequence_cnt = sequence_size = 0;
+}
+
+static void ok_sequence(const struct message *expected, const char *context)
+{
+    static const struct message end_of_sequence = { 0, 0 };
+    const struct message *actual;
+
+    add_message(&end_of_sequence);
+
+    actual = sequence;
+
+    while(expected->procnum && actual->procnum)
+    {
+        ok(expected->procnum == actual->procnum,
+            "%s: the procnum %d was expected, but got procnum %d instead\n",
+            context, expected->procnum, actual->procnum);
+        ok(expected->wParam == actual->wParam,
+            "%s: in procnum %d expecting wParam 0x%x got 0x%x\n",
+            context, expected->procnum, expected->wParam, actual->wParam);
+        expected++;
+        actual++;
+    }
+    ok(!expected->procnum, "Received fewer messages than expected\n");
+    ok(!actual->procnum, "Received more messages than expected\n");
+    flush_sequence();
+}
+
+static LRESULT WINAPI WndProc1(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+    struct message msg;
+    
+    if(message == WM_USER) {
+        msg.wParam = wParam;
+        msg.procnum = 1;
+        add_message(&msg);
+    }
+    return DefWindowProc(hwnd, message, wParam, lParam);
+}
+
+
+static WNDPROC origProc3;
+static LRESULT WINAPI WndProc3(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+    struct message msg;
+    
+    if(message == WM_USER) {
+        msg.wParam = wParam;
+        msg.procnum = 3;
+        add_message(&msg);
+    }
+    return CallWindowProc(origProc3, hwnd, message, wParam, lParam);
+}
+
+static LRESULT WINAPI WndProcSub(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, UINT_PTR uldSubclass, DWORD_PTR dwRefData)
+{
+    struct message msg;
+    
+    if(message == WM_USER) {
+        msg.wParam = wParam;
+        msg.procnum = uldSubclass;
+        add_message(&msg);
+        
+        if(lParam) {
+            if(dwRefData & DELETE_SELF) {
+                pRemoveWindowSubclass(hwnd, WndProcSub, uldSubclass);
+                pRemoveWindowSubclass(hwnd, WndProcSub, uldSubclass);
+            }
+            if(dwRefData & DELETE_PREV)
+                pRemoveWindowSubclass(hwnd, WndProcSub, uldSubclass-1);
+            if(dwRefData & SEND_NEST)
+                SendMessage(hwnd, WM_USER, wParam+1, 0);
+        }
+    }
+    return pDefSubclassProc(hwnd, message, wParam, lParam);
+}
+
+static void test_subclass(void)
+{
+    HWND hwnd = CreateWindowExA(0, "TestSubclass", "Test subclass", WS_OVERLAPPEDWINDOW,
+                           100, 100, 200, 200, 0, 0, 0, NULL);
+    assert(hwnd);
+
+    pSetWindowSubclass(hwnd, WndProcSub, 2, 0);
+    SendMessage(hwnd, WM_USER, 1, 0);
+    SendMessage(hwnd, WM_USER, 2, 0);
+    ok_sequence(Sub_BasicTest, "Basic");
+
+    pSetWindowSubclass(hwnd, WndProcSub, 2, DELETE_SELF);
+    SendMessage(hwnd, WM_USER, 1, 1);
+    ok_sequence(Sub_DeletedTest, "Deleted");
+
+    SendMessage(hwnd, WM_USER, 1, 0);
+    ok_sequence(Sub_AfterDeletedTest, "After Deleted");
+
+    pSetWindowSubclass(hwnd, WndProcSub, 2, 0);
+    origProc3 = (WNDPROC)SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG)WndProc3);
+    SendMessage(hwnd, WM_USER, 1, 0);
+    SendMessage(hwnd, WM_USER, 2, 0);
+    ok_sequence(Sub_OldAfterNewTest, "Old after New");
+
+    pSetWindowSubclass(hwnd, WndProcSub, 4, 0);
+    SendMessage(hwnd, WM_USER, 1, 0);
+    ok_sequence(Sub_MixTest, "Mix");
+
+    /* Now the fun starts */
+    pSetWindowSubclass(hwnd, WndProcSub, 4, SEND_NEST);
+    SendMessage(hwnd, WM_USER, 1, 1);
+    ok_sequence(Sub_MixAndNestTest, "Mix and nest");
+
+    pSetWindowSubclass(hwnd, WndProcSub, 4, SEND_NEST | DELETE_SELF);
+    SendMessage(hwnd, WM_USER, 1, 1);
+    ok_sequence(Sub_MixNestDelTest, "Mix, nest, del");
+
+    pSetWindowSubclass(hwnd, WndProcSub, 4, 0);
+    pSetWindowSubclass(hwnd, WndProcSub, 5, DELETE_PREV);
+    SendMessage(hwnd, WM_USER, 1, 1);
+    ok_sequence(Sub_MixDelPrevTest, "Mix and del prev");
+
+    DestroyWindow(hwnd);
+}
+
+static BOOL RegisterWindowClasses(void)
+{
+    WNDCLASSA cls;
+
+    cls.style = 0;
+    cls.lpfnWndProc = WndProc1;
+    cls.cbClsExtra = 0;
+    cls.cbWndExtra = 0;
+    cls.hInstance = GetModuleHandleA(0);
+    cls.hIcon = 0;
+    cls.hCursor = NULL;
+    cls.hbrBackground = NULL;
+    cls.lpszMenuName = NULL;
+    cls.lpszClassName = "TestSubclass";
+    if(!RegisterClassA(&cls)) return FALSE;
+    
+    return TRUE;
+}
+
+START_TEST(subclass)
+{
+    HMODULE hdll;
+    
+    hdll = GetModuleHandleA("comctl32.dll");
+    assert(hdll);
+    pSetWindowSubclass = (void*)GetProcAddress(hdll, "SetWindowSubclass");
+    pRemoveWindowSubclass = (void*)GetProcAddress(hdll, "RemoveWindowSubclass");
+    pDefSubclassProc = (void*)GetProcAddress(hdll, "DefSubclassProc");
+    
+    if(!pSetWindowSubclass || !pRemoveWindowSubclass || !pDefSubclassProc)
+        return;
+
+    if(!RegisterWindowClasses()) assert(0);
+
+    test_subclass();
+}
diff --git a/rostests/winetests/comctl32/tab.c b/rostests/winetests/comctl32/tab.c
new file mode 100644 (file)
index 0000000..d5901c0
--- /dev/null
@@ -0,0 +1,249 @@
+/* Unit test suite for tab control.
+ *
+ * Copyright 2003 Vitaliy Margolen
+ *
+ * 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 <assert.h>
+#include <windows.h>
+#include <commctrl.h>
+
+#include "wine/test.h"
+
+#define DEFAULT_MIN_TAB_WIDTH 54
+#define TAB_DEFAULT_WIDTH 96
+#define TAB_PADDING_X 6
+#define EXTRA_ICON_PADDING 3
+
+#define TabWidthPadded(padd_x, num) (DEFAULT_MIN_TAB_WIDTH - (TAB_PADDING_X - (padd_x)) * num)
+
+#define TabCheckSetSize(hwnd, SetWidth, SetHeight, ExpWidth, ExpHeight, Msg)\
+    SendMessage (hwnd, TCM_SETITEMSIZE, 0,\
+       (LPARAM) MAKELPARAM((SetWidth >= 0) ? SetWidth:0, (SetHeight >= 0) ? SetHeight:0));\
+    if (winetest_interactive) RedrawWindow (hwnd, NULL, 0, RDW_UPDATENOW);\
+    CheckSize(hwnd, ExpWidth, ExpHeight, Msg);
+
+#define CheckSize(hwnd,width,height,msg)\
+    SendMessage (hwnd, TCM_GETITEMRECT, 0, (LPARAM) &rTab);\
+    if ((width  >= 0) && (height < 0))\
+       ok (width  == rTab.right  - rTab.left, "%s: Expected width [%d] got [%ld]\n",\
+        msg, (int)width,  rTab.right  - rTab.left);\
+    else if ((height >= 0) && (width  < 0))\
+       ok (height == rTab.bottom - rTab.top,  "%s: Expected height [%d] got [%ld]\n",\
+        msg, (int)height, rTab.bottom - rTab.top);\
+    else\
+       ok ((width  == rTab.right  - rTab.left) &&\
+           (height == rTab.bottom - rTab.top ),\
+           "%s: Expected [%d,%d] got [%ld,%ld]\n", msg, (int)width, (int)height,\
+            rTab.right - rTab.left, rTab.bottom - rTab.top);
+
+static HFONT hFont = 0;
+
+static HWND
+create_tabcontrol (DWORD style, DWORD mask)
+{
+    HWND handle;
+    TCITEM tcNewTab;
+    static char text1[] = "Tab 1",
+    text2[] = "Wide Tab 2",
+    text3[] = "T 3";
+
+    handle = CreateWindow (
+       WC_TABCONTROLA,
+       "TestTab",
+       WS_CLIPSIBLINGS | WS_CLIPCHILDREN | TCS_FOCUSNEVER | style,
+        10, 10, 300, 100,
+        NULL, NULL, NULL, 0);
+
+    assert (handle);
+
+    SetWindowLong(handle, GWL_STYLE, WS_CLIPSIBLINGS | WS_CLIPCHILDREN | TCS_FOCUSNEVER | style);
+    SendMessage (handle, WM_SETFONT, 0, (LPARAM) hFont);
+
+    tcNewTab.mask = mask;
+    tcNewTab.pszText = text1;
+    tcNewTab.iImage = 0;
+    SendMessage (handle, TCM_INSERTITEM, 0, (LPARAM) &tcNewTab);
+    tcNewTab.pszText = text2;
+    tcNewTab.iImage = 1;
+    SendMessage (handle, TCM_INSERTITEM, 1, (LPARAM) &tcNewTab);
+    tcNewTab.pszText = text3;
+    tcNewTab.iImage = 2;
+    SendMessage (handle, TCM_INSERTITEM, 2, (LPARAM) &tcNewTab);
+
+    if (winetest_interactive)
+    {
+        ShowWindow (handle, SW_SHOW);
+        RedrawWindow (handle, NULL, 0, RDW_UPDATENOW);
+        Sleep (1000);
+    }
+
+    return handle;
+}
+
+static void test_tab(INT nMinTabWidth)
+{
+    HWND hwTab;
+    RECT rTab;
+    HIMAGELIST himl = ImageList_Create(21, 21, ILC_COLOR, 3, 4);
+    SIZE size;
+    HDC hdc;
+    HFONT hOldFont;
+    INT i;
+
+    hwTab = create_tabcontrol(TCS_FIXEDWIDTH, TCIF_TEXT|TCIF_IMAGE);
+    SendMessage(hwTab, TCM_SETMINTABWIDTH, 0, nMinTabWidth);
+
+    hdc = GetDC(hwTab);
+    hOldFont = SelectObject(hdc, (HFONT)SendMessage(hwTab, WM_GETFONT, 0, 0));
+    GetTextExtentPoint32A(hdc, "Tab 1", strlen("Tab 1"), &size);
+    trace("Tab1 text size: size.cx=%ld size.cy=%ld\n", size.cx, size.cy);
+    SelectObject(hdc, hOldFont);
+    ReleaseDC(hwTab, hdc);
+
+    trace ("  TCS_FIXEDWIDTH tabs no icon...\n");
+    CheckSize(hwTab, TAB_DEFAULT_WIDTH, -1, "default width");
+    TabCheckSetSize(hwTab, 50, 20, 50, 20, "set size");
+    TabCheckSetSize(hwTab, 0, 1, 0, 1, "min size");
+
+    SendMessage(hwTab, TCM_SETIMAGELIST, 0, (LPARAM)himl);
+
+    trace ("  TCS_FIXEDWIDTH tabs with icon...\n");
+    TabCheckSetSize(hwTab, 50, 30, 50, 30, "set size > icon");
+    TabCheckSetSize(hwTab, 20, 20, 25, 20, "set size < icon");
+    TabCheckSetSize(hwTab, 0, 1, 25, 1, "min size");
+
+    DestroyWindow (hwTab);
+
+    hwTab = create_tabcontrol(TCS_FIXEDWIDTH | TCS_BUTTONS, TCIF_TEXT|TCIF_IMAGE);
+    SendMessage(hwTab, TCM_SETMINTABWIDTH, 0, nMinTabWidth);
+
+    trace ("  TCS_FIXEDWIDTH buttons no icon...\n");
+    CheckSize(hwTab, TAB_DEFAULT_WIDTH, -1, "default width");
+    TabCheckSetSize(hwTab, 20, 20, 20, 20, "set size 1");
+    TabCheckSetSize(hwTab, 10, 50, 10, 50, "set size 2");
+    TabCheckSetSize(hwTab, 0, 1, 0, 1, "min size");
+
+    SendMessage(hwTab, TCM_SETIMAGELIST, 0, (LPARAM)himl);
+
+    trace ("  TCS_FIXEDWIDTH buttons with icon...\n");
+    TabCheckSetSize(hwTab, 50, 30, 50, 30, "set size > icon");
+    TabCheckSetSize(hwTab, 20, 20, 25, 20, "set size < icon");
+    TabCheckSetSize(hwTab, 0, 1, 25, 1, "min size");
+    SendMessage(hwTab, TCM_SETPADDING, 0, MAKELPARAM(4,4));
+    TabCheckSetSize(hwTab, 0, 1, 25, 1, "set padding, min size");
+
+    DestroyWindow (hwTab);
+
+    hwTab = create_tabcontrol(TCS_FIXEDWIDTH | TCS_BOTTOM, TCIF_TEXT|TCIF_IMAGE);
+    SendMessage(hwTab, TCM_SETMINTABWIDTH, 0, nMinTabWidth);
+
+    trace ("  TCS_FIXEDWIDTH | TCS_BOTTOM tabs...\n");
+    CheckSize(hwTab, TAB_DEFAULT_WIDTH, -1, "no icon, default width");
+
+    TabCheckSetSize(hwTab, 20, 20, 20, 20, "no icon, set size 1");
+    TabCheckSetSize(hwTab, 10, 50, 10, 50, "no icon, set size 2");
+    TabCheckSetSize(hwTab, 0, 1, 0, 1, "no icon, min size");
+
+    SendMessage(hwTab, TCM_SETIMAGELIST, 0, (LPARAM)himl);
+
+    TabCheckSetSize(hwTab, 50, 30, 50, 30, "with icon, set size > icon");
+    TabCheckSetSize(hwTab, 20, 20, 25, 20, "with icon, set size < icon");
+    TabCheckSetSize(hwTab, 0, 1, 25, 1, "with icon, min size");
+    SendMessage(hwTab, TCM_SETPADDING, 0, MAKELPARAM(4,4));
+    TabCheckSetSize(hwTab, 0, 1, 25, 1, "set padding, min size");
+
+    DestroyWindow (hwTab);
+
+    hwTab = create_tabcontrol(0, TCIF_TEXT|TCIF_IMAGE);
+    SendMessage(hwTab, TCM_SETMINTABWIDTH, 0, nMinTabWidth);
+
+    trace ("  non fixed width, with text...\n");
+    CheckSize(hwTab, max(size.cx +TAB_PADDING_X*2, (nMinTabWidth < 0) ? DEFAULT_MIN_TAB_WIDTH : nMinTabWidth), -1,
+              "no icon, default width");
+    for (i=0; i<8; i++)
+    {
+        INT nTabWidth = (nMinTabWidth < 0) ? TabWidthPadded(i, 2) : nMinTabWidth;
+
+        SendMessage(hwTab, TCM_SETIMAGELIST, 0, 0);
+        SendMessage(hwTab, TCM_SETPADDING, 0, MAKELPARAM(i,i));
+
+        TabCheckSetSize(hwTab, 50, 20, max(size.cx + i*2, nTabWidth), 20, "no icon, set size");
+        TabCheckSetSize(hwTab, 0, 1, max(size.cx + i*2, nTabWidth), 1, "no icon, min size");
+
+        SendMessage(hwTab, TCM_SETIMAGELIST, 0, (LPARAM)himl);
+        nTabWidth = (nMinTabWidth < 0) ? TabWidthPadded(i, 3) : nMinTabWidth;
+
+        TabCheckSetSize(hwTab, 50, 30, max(size.cx + 21 + i*3, nTabWidth), 30, "with icon, set size > icon");
+        TabCheckSetSize(hwTab, 20, 20, max(size.cx + 21 + i*3, nTabWidth), 20, "with icon, set size < icon");
+        TabCheckSetSize(hwTab, 0, 1, max(size.cx + 21 + i*3, nTabWidth), 1, "with icon, min size");
+    }
+    DestroyWindow (hwTab);
+
+    hwTab = create_tabcontrol(0, TCIF_IMAGE);
+    SendMessage(hwTab, TCM_SETMINTABWIDTH, 0, nMinTabWidth);
+
+    trace ("  non fixed width, no text...\n");
+    CheckSize(hwTab, (nMinTabWidth < 0) ? DEFAULT_MIN_TAB_WIDTH : nMinTabWidth, -1, "no icon, default width");
+    for (i=0; i<8; i++)
+    {
+        INT nTabWidth = (nMinTabWidth < 0) ? TabWidthPadded(i, 2) : nMinTabWidth;
+
+        SendMessage(hwTab, TCM_SETIMAGELIST, 0, 0);
+        SendMessage(hwTab, TCM_SETPADDING, 0, MAKELPARAM(i,i));
+
+        TabCheckSetSize(hwTab, 50, 20, nTabWidth, 20, "no icon, set size");
+        TabCheckSetSize(hwTab, 0, 1, nTabWidth, 1, "no icon, min size");
+
+        SendMessage(hwTab, TCM_SETIMAGELIST, 0, (LPARAM)himl);
+        if (i > 1 && nMinTabWidth > 0 && nMinTabWidth < DEFAULT_MIN_TAB_WIDTH)
+            nTabWidth += EXTRA_ICON_PADDING *(i-1);
+
+        TabCheckSetSize(hwTab, 50, 30, nTabWidth, 30, "with icon, set size > icon");
+        TabCheckSetSize(hwTab, 20, 20, nTabWidth, 20, "with icon, set size < icon");
+        TabCheckSetSize(hwTab, 0, 1, nTabWidth, 1, "with icon, min size");
+    }
+
+    DestroyWindow (hwTab);
+
+    ImageList_Destroy(himl);
+    DeleteObject(hFont);
+}
+
+START_TEST(tab)
+{
+    LOGFONTA logfont;
+
+    lstrcpyA(logfont.lfFaceName, "Arial");
+    memset(&logfont, 0, sizeof(logfont));
+    logfont.lfHeight = -12;
+    logfont.lfWeight = FW_NORMAL;
+    logfont.lfCharSet = ANSI_CHARSET;
+    hFont = CreateFontIndirectA(&logfont);
+
+    InitCommonControls();
+
+    trace ("Testing with default MinWidth\n");
+    test_tab(-1);
+    trace ("Testing with MinWidth set to -3\n");
+    test_tab(-3);
+    trace ("Testing with MinWidth set to 24\n");
+    test_tab(24);
+    trace ("Testing with MinWidth set to 54\n");
+    test_tab(54);
+    trace ("Testing with MinWidth set to 94\n");
+    test_tab(94);
+}
diff --git a/rostests/winetests/comctl32/testlist.c b/rostests/winetests/comctl32/testlist.c
new file mode 100644 (file)
index 0000000..179eefd
--- /dev/null
@@ -0,0 +1,41 @@
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+#define STANDALONE
+#include "wine/test.h"
+
+extern void func_comboex(void);
+extern void func_dpa(void);
+extern void func_header(void);
+extern void func_imagelist(void);
+extern void func_listview(void);
+extern void func_monthcal(void);
+extern void func_mru(void);
+extern void func_progress(void);
+extern void func_propsheet(void);
+extern void func_subclass(void);
+extern void func_tab(void);
+extern void func_toolbar(void);
+extern void func_tooltips(void);
+extern void func_treeview(void);
+extern void func_updown(void);
+
+const struct test winetest_testlist[] =
+{
+    { "comboex", func_comboex },
+    { "dpa", func_dpa },
+    { "header", func_header },
+    { "imagelist", func_imagelist },
+    { "listview", func_listview },
+    { "monthcal", func_monthcal },
+    { "mru", func_mru },
+    { "progress", func_progress },
+    { "propsheet", func_propsheet },
+    { "subclass", func_subclass },
+    { "tab", func_tab },
+    { "toolbar", func_toolbar },
+    { "tooltips", func_tooltips },
+    { "treeview", func_treeview },
+    { "updown", func_updown },
+    { 0, 0 }
+};
diff --git a/rostests/winetests/comctl32/toolbar.c b/rostests/winetests/comctl32/toolbar.c
new file mode 100644 (file)
index 0000000..ec29a82
--- /dev/null
@@ -0,0 +1,137 @@
+/* Unit tests for treeview.
+ *
+ * Copyright 2005 Krzysztof Foltman
+ *
+ * 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 <assert.h>
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "winnls.h"
+#include "winreg.h"
+#include "commctrl.h" 
+
+#include "wine/test.h"
+static void MakeButton(TBBUTTON *p, int idCommand, int fsStyle, int nString) {
+  p->iBitmap = -2;
+  p->idCommand = idCommand;
+  p->fsState = TBSTATE_ENABLED;
+  p->fsStyle = fsStyle;
+  p->iString = nString;
+}
+
+static LRESULT CALLBACK MyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    switch(msg) {
+                  
+    case WM_CREATE:
+    {
+        TBBUTTON buttons[9];
+        int i;
+        HWND hToolbar;
+        for (i=0; i<9; i++)
+            MakeButton(buttons+i, 1000+i, TBSTYLE_CHECKGROUP, 0);
+        MakeButton(buttons+3, 1003, TBSTYLE_SEP|TBSTYLE_GROUP, 0);
+        MakeButton(buttons+6, 1006, TBSTYLE_SEP, 0);
+
+        hToolbar = CreateToolbarEx(hWnd,
+            WS_VISIBLE | WS_CLIPCHILDREN | CCS_TOP |
+            WS_CHILD | TBSTYLE_LIST,
+            100,
+            0, NULL, (UINT)0,
+            buttons, sizeof(buttons)/sizeof(buttons[0]),
+            0, 0, 20, 16, sizeof(TBBUTTON));
+        ok(hToolbar != NULL, "Toolbar creation\n");
+
+        SendMessage(hToolbar, TB_ADDSTRINGA, 0, (LPARAM)"test\000");
+
+        /* test for exclusion working inside a separator-separated :-) group */
+        SendMessage(hToolbar, TB_CHECKBUTTON, 1000, 1); /* press A1 */
+        ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1000, 0), "A1 pressed\n");
+        ok(!SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1001, 0), "A2 not pressed\n");
+
+        SendMessage(hToolbar, TB_CHECKBUTTON, 1004, 1); /* press A5, release A1 */
+        ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1004, 0), "A5 pressed\n");
+        ok(!SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1000, 0), "A1 not pressed anymore\n");
+
+        SendMessage(hToolbar, TB_CHECKBUTTON, 1005, 1); /* press A6, release A5 */
+        ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1005, 0), "A6 pressed\n");
+        ok(!SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1004, 0), "A5 not pressed anymore\n");
+
+        /* test for inter-group crosstalk, ie. two radio groups interfering with each other */
+        SendMessage(hToolbar, TB_CHECKBUTTON, 1007, 1); /* press B2 */
+        ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1005, 0), "A6 still pressed, no inter-group crosstalk\n");
+        ok(!SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1000, 0), "A1 still not pressed\n");
+        ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1007, 0), "B2 pressed\n");
+
+        SendMessage(hToolbar, TB_CHECKBUTTON, 1000, 1); /* press A1 and ensure B group didn't suffer */
+        ok(!SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1005, 0), "A6 not pressed anymore\n");
+        ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1000, 0), "A1 pressed\n");
+        ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1007, 0), "B2 still pressed\n");
+
+        SendMessage(hToolbar, TB_CHECKBUTTON, 1008, 1); /* press B3, and ensure A group didn't suffer */
+        ok(!SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1005, 0), "A6 pressed\n");
+        ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1000, 0), "A1 pressed\n");
+        ok(!SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1007, 0), "B2 not pressed\n");
+        ok(SendMessage(hToolbar, TB_ISBUTTONCHECKED, 1008, 0), "B3 pressed\n");
+        PostMessage(hWnd, WM_CLOSE, 0, 0);
+        return 0;
+    }
+    case WM_DESTROY:
+        PostQuitMessage(0);
+        break;
+  
+    default:
+        return DefWindowProcA(hWnd, msg, wParam, lParam);
+    }
+    return 0L;
+}
+
+START_TEST(toolbar)
+{
+    WNDCLASSA wc;
+    MSG msg;
+    RECT rc;
+    HWND hMainWnd;
+  
+    InitCommonControls();
+  
+    wc.style = CS_HREDRAW | CS_VREDRAW;
+    wc.cbClsExtra = 0;
+    wc.cbWndExtra = 0;
+    wc.hInstance = GetModuleHandleA(NULL);
+    wc.hIcon = NULL;
+    wc.hCursor = LoadCursorA(NULL, MAKEINTRESOURCEA(IDC_IBEAM));
+    wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
+    wc.lpszMenuName = NULL;
+    wc.lpszClassName = "MyTestWnd";
+    wc.lpfnWndProc = MyWndProc;
+    RegisterClassA(&wc);
+    
+    hMainWnd = CreateWindowExA(0, "MyTestWnd", "Blah", WS_OVERLAPPEDWINDOW, 
+      CW_USEDEFAULT, CW_USEDEFAULT, 680, 260, NULL, NULL, GetModuleHandleA(NULL), 0);
+    GetClientRect(hMainWnd, &rc);
+
+    while(GetMessageA(&msg,0,0,0)) {
+        TranslateMessage(&msg);
+        DispatchMessageA(&msg);
+    }
+}
diff --git a/rostests/winetests/comctl32/tooltips.c b/rostests/winetests/comctl32/tooltips.c
new file mode 100644 (file)
index 0000000..7f32471
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2005 Dmitry Timoshkov
+ *
+ * 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 <assert.h>
+#include <windows.h>
+#include <commctrl.h>
+
+#include "wine/test.h"
+
+static void test_create_tooltip(void)
+{
+    HWND parent, hwnd;
+    DWORD style, exp_style;
+
+    parent = CreateWindowEx(0, "static", NULL, WS_POPUP,
+                          0, 0, 0, 0,
+                          NULL, NULL, NULL, 0);
+    assert(parent);
+
+    hwnd = CreateWindowEx(0, TOOLTIPS_CLASS, NULL, 0x7fffffff | WS_POPUP,
+                          10, 10, 300, 100,
+                          parent, NULL, NULL, 0);
+    assert(hwnd);
+
+    style = GetWindowLong(hwnd, GWL_STYLE);
+    trace("style = %08lx\n", style);
+    exp_style = 0x7fffffff | WS_POPUP;
+    exp_style &= ~(WS_CHILD | WS_MAXIMIZE | WS_BORDER | WS_DLGFRAME);
+    ok(style == exp_style,"wrong style %08lx/%08lx\n", style, exp_style);
+
+    DestroyWindow(hwnd);
+
+    hwnd = CreateWindowEx(0, TOOLTIPS_CLASS, NULL, 0,
+                          10, 10, 300, 100,
+                          parent, NULL, NULL, 0);
+    assert(hwnd);
+
+    style = GetWindowLong(hwnd, GWL_STYLE);
+    trace("style = %08lx\n", style);
+    ok(style == (WS_POPUP | WS_CLIPSIBLINGS | WS_BORDER),
+       "wrong style %08lx\n", style);
+
+    DestroyWindow(hwnd);
+
+    DestroyWindow(parent);
+}
+
+START_TEST(tooltips)
+{
+    InitCommonControls();
+
+    test_create_tooltip();
+}
diff --git a/rostests/winetests/comctl32/treeview.c b/rostests/winetests/comctl32/treeview.c
new file mode 100644 (file)
index 0000000..b71be91
--- /dev/null
@@ -0,0 +1,221 @@
+/* Unit tests for treeview.
+ *
+ * Copyright 2005 Krzysztof Foltman
+ *
+ * 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 <assert.h>
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "winnls.h"
+#include "winreg.h"
+#include "commctrl.h" 
+
+#include "wine/test.h"
+static HWND hMainWnd;
+
+static HWND hTree;
+static HTREEITEM hRoot, hChild;
+
+static int pos = 0;
+static char sequence[256];
+
+static void Clear(void)
+{
+    pos = 0;
+    sequence[0] = '\0';
+}
+
+static void AddItem(char ch)
+{
+    sequence[pos++] = ch;
+    sequence[pos] = '\0';
+}
+
+static void IdentifyItem(HTREEITEM hItem)
+{
+    if (hItem == hRoot) {
+        AddItem('R');
+        return;
+    }
+    if (hItem == hChild) {
+        AddItem('C');
+        return;
+    }
+    if (hItem == NULL) {
+        AddItem('n');
+        return;
+    }
+    AddItem('?');
+}
+
+static void FillRoot(void)
+{
+    TVINSERTSTRUCTA ins;
+    static CHAR root[]  = "Root",
+                child[] = "Child";
+
+    Clear();
+    AddItem('A');
+    ins.hParent = TVI_ROOT;
+    ins.hInsertAfter = TVI_ROOT;
+    U(ins).item.mask = TVIF_TEXT;
+    U(ins).item.pszText = root;
+    hRoot = TreeView_InsertItem(hTree, &ins);
+    assert(hRoot);
+
+    AddItem('B');
+    ins.hParent = hRoot;
+    ins.hInsertAfter = TVI_FIRST;
+    U(ins).item.mask = TVIF_TEXT;
+    U(ins).item.pszText = child;
+    hChild = TreeView_InsertItem(hTree, &ins);
+    assert(hChild);
+    AddItem('.');
+
+    ok(!strcmp(sequence, "AB."), "Item creation\n");
+}
+
+static void DoTest1(void)
+{
+    BOOL r;
+    r = TreeView_SelectItem(hTree, NULL);
+    Clear();
+    AddItem('1');
+    r = TreeView_SelectItem(hTree, hRoot);
+    AddItem('2');
+    r = TreeView_SelectItem(hTree, hRoot);
+    AddItem('3');
+    r = TreeView_SelectItem(hTree, NULL);
+    AddItem('4');
+    r = TreeView_SelectItem(hTree, NULL);
+    AddItem('5');
+    r = TreeView_SelectItem(hTree, hRoot);
+    AddItem('.');
+    ok(!strcmp(sequence, "1(nR)nR23(Rn)Rn45(nR)nR."), "root-none select test\n");
+}
+
+static void DoTest2(void)
+{
+    BOOL r;
+    r = TreeView_SelectItem(hTree, NULL);
+    Clear();
+    AddItem('1');
+    r = TreeView_SelectItem(hTree, hRoot);
+    AddItem('2');
+    r = TreeView_SelectItem(hTree, hRoot);
+    AddItem('3');
+    r = TreeView_SelectItem(hTree, hChild);
+    AddItem('4');
+    r = TreeView_SelectItem(hTree, hChild);
+    AddItem('5');
+    r = TreeView_SelectItem(hTree, hRoot);
+    AddItem('.');
+    ok(!strcmp(sequence, "1(nR)nR23(RC)RC45(CR)CR."), "root-child select test\n");
+}
+
+LRESULT CALLBACK MyWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    switch(msg) {
+                  
+    case WM_CREATE:
+    {
+        hTree = CreateWindowExA(WS_EX_CLIENTEDGE, WC_TREEVIEWA, NULL, WS_CHILD|WS_VISIBLE|
+            TVS_LINESATROOT|TVS_HASLINES|TVS_HASBUTTONS, 
+            0, 0, 300, 50, hWnd, (HMENU)100, GetModuleHandleA(0), 0);
+    
+        SetFocus(hTree);
+        return 0;
+    }
+    case WM_NOTIFY:
+    {
+        NMHDR *pHdr = (NMHDR *)lParam;
+    
+        if (pHdr->idFrom == 100) {
+            NMTREEVIEWA *pTreeView = (LPNMTREEVIEWA) lParam;
+            switch(pHdr->code) {
+            case TVN_SELCHANGINGA:
+                AddItem('(');
+                IdentifyItem(pTreeView->itemOld.hItem);
+                IdentifyItem(pTreeView->itemNew.hItem);
+                return 0;
+            case TVN_SELCHANGEDA:
+                AddItem(')');
+                IdentifyItem(pTreeView->itemOld.hItem);
+                IdentifyItem(pTreeView->itemNew.hItem);
+                return 0;
+            }
+        }
+        return 0;
+    }
+  
+    case WM_SIZE:
+        MoveWindow(hTree, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
+        break;
+      
+    case WM_DESTROY:
+        PostQuitMessage(0);
+        break;
+  
+    default:
+        return DefWindowProcA(hWnd, msg, wParam, lParam);
+    }
+    return 0L;
+}
+
+START_TEST(treeview)
+{
+    WNDCLASSA wc;
+    MSG msg;
+    INITCOMMONCONTROLSEX icex;
+    RECT rc;
+  
+    icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
+    icex.dwICC   = ICC_TREEVIEW_CLASSES;
+    InitCommonControlsEx(&icex);
+  
+    wc.style = CS_HREDRAW | CS_VREDRAW;
+    wc.cbClsExtra = 0;
+    wc.cbWndExtra = 0;
+    wc.hInstance = GetModuleHandleA(NULL);
+    wc.hIcon = NULL;
+    wc.hCursor = LoadCursorA(NULL, MAKEINTRESOURCEA(IDC_IBEAM));
+    wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
+    wc.lpszMenuName = NULL;
+    wc.lpszClassName = "MyTestWnd";
+    wc.lpfnWndProc = MyWndProc;
+    RegisterClassA(&wc);
+    
+    
+    hMainWnd = CreateWindowExA(0, "MyTestWnd", "Blah", WS_OVERLAPPEDWINDOW, 
+      CW_USEDEFAULT, CW_USEDEFAULT, 680, 260, NULL, NULL, GetModuleHandleA(NULL), 0);
+    GetClientRect(hMainWnd, &rc);
+
+    FillRoot();
+    DoTest1();
+    DoTest2();
+
+    PostMessageA(hMainWnd, WM_CLOSE, 0, 0);
+    while(GetMessageA(&msg,0,0,0)) {
+        TranslateMessage(&msg);
+        DispatchMessageA(&msg);
+    }
+}
diff --git a/rostests/winetests/comctl32/updown.c b/rostests/winetests/comctl32/updown.c
new file mode 100644 (file)
index 0000000..7268c48
--- /dev/null
@@ -0,0 +1,98 @@
+/* Unit test suite for updown control.
+ *
+ * Copyright 2005 C. Scott Ananian
+ *
+ * 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 <assert.h>
+#include <windows.h>
+#include <commctrl.h>
+#include <stdio.h>
+
+#include "wine/test.h"
+
+static HDC desktopDC;
+static HINSTANCE hinst;
+
+static HWND create_edit_control (DWORD style, DWORD exstyle)
+{
+    HWND handle;
+
+    handle = CreateWindowEx(exstyle,
+                         "EDIT",
+                         NULL,
+                         ES_AUTOHSCROLL | ES_AUTOVSCROLL | style,
+                         10, 10, 300, 300,
+                         NULL, NULL, hinst, NULL);
+    assert (handle);
+    if (winetest_interactive)
+       ShowWindow (handle, SW_SHOW);
+    return handle;
+}
+
+static HWND create_updown_control (HWND hWndEdit)
+{
+    HWND hWndUpDown;
+
+    /* make the control */
+    hWndUpDown = CreateWindowEx
+       (0L, UPDOWN_CLASS, NULL,
+        /* window styles */
+        UDS_SETBUDDYINT | UDS_ALIGNRIGHT |
+        UDS_ARROWKEYS | UDS_NOTHOUSANDS,
+        /* placement */
+        0, 0, 8, 8, 
+        /* parent, etc */
+        NULL, NULL, hinst, NULL);
+    assert (hWndUpDown);
+    /* set the buddy. */
+    SendMessage (hWndUpDown, UDM_SETBUDDY, (WPARAM)hWndEdit, 0L );
+    /* set the range. */
+    SendMessage (hWndUpDown, UDM_SETRANGE, 0L, (LPARAM) MAKELONG(32000, 0));
+    /* maybe show it. */
+    if (winetest_interactive)
+       ShowWindow (hWndUpDown, SW_SHOW);
+    return hWndUpDown;
+}
+
+static void test_updown_control (void)
+{
+    HWND hWndUpDown, hWndEdit;
+    int num;
+
+    hWndEdit = create_edit_control (ES_AUTOHSCROLL | ES_NUMBER, 0);
+    hWndUpDown = create_updown_control (hWndEdit);
+    /* before we set a value, it should be '0' */
+    num = SendMessage(hWndUpDown, UDM_GETPOS, 0, 0L);
+    ok(num == 0, "Expected 0 got %d\n", num);
+    /* set a value, check it. */
+    SendMessage(hWndUpDown, UDM_SETPOS, 0L, MAKELONG( 1, 0));
+    num = SendMessage(hWndUpDown, UDM_GETPOS, 0, 0L);
+    ok(num == 1, "Expected 1 got %d\n", num);
+    /* okay, done (short set of tests!) */
+    DestroyWindow(hWndUpDown);
+    DestroyWindow(hWndEdit);
+}
+
+START_TEST(updown)
+{
+    desktopDC=GetDC(NULL);
+    hinst = GetModuleHandleA(NULL);
+
+    InitCommonControls();
+
+    test_updown_control();
+}
diff --git a/rostests/winetests/directory.rbuild b/rostests/winetests/directory.rbuild
new file mode 100644 (file)
index 0000000..b05b0f0
--- /dev/null
@@ -0,0 +1,56 @@
+<group>
+<directory name="advapi32">
+       <xi:include href="advapi32/advapi32.rbuild" />
+</directory>
+<directory name="cabinet">
+       <xi:include href="cabinet/cabinet.rbuild" />
+</directory>
+<directory name="comctl32">
+       <xi:include href="comctl32/comctl32.rbuild" />
+</directory>
+<directory name="gdi32">
+       <xi:include href="gdi32/gdi32.rbuild" />
+</directory>
+<directory name="icmp">
+        <xi:include href="icmp/icmp.rbuild" />
+</directory>
+<directory name="kernel32">
+       <xi:include href="kernel32/kernel32.rbuild" />
+</directory>
+<directory name="lz32">
+        <xi:include href="lz32/lz32.rbuild" />
+</directory>
+<directory name="msi">
+       <xi:include href="msi/msi.rbuild" />
+</directory>
+<directory name="msvcrt">
+       <xi:include href="msvcrt/msvcrt.rbuild" />
+</directory>
+<directory name="ntdll">
+       <xi:include href="ntdll/ntdll.rbuild" />
+</directory>
+<directory name="psapi">
+       <xi:include href="psapi/psapi.rbuild" />
+</directory>
+<directory name="powrprof">
+       <xi:include href="powrprof/powrprof.rbuild" />
+</directory>
+<directory name="setupapi">
+       <xi:include href="setupapi/setupapi.rbuild" />
+</directory>
+<directory name="shell32">
+       <xi:include href="shell32/shell32.rbuild" />
+</directory>
+<directory name="shlwapi">
+       <xi:include href="shlwapi/shlwapi.rbuild" />
+</directory>
+<directory name="user32">
+       <xi:include href="user32/user32.rbuild" />
+</directory>
+<directory name="usp10">
+       <xi:include href="usp10/usp10.rbuild" />
+</directory>
+<directory name="version">
+       <xi:include href="version/version.rbuild" />
+</directory>
+</group>
diff --git a/rostests/winetests/gdi32/bitmap.c b/rostests/winetests/gdi32/bitmap.c
new file mode 100755 (executable)
index 0000000..62a57eb
--- /dev/null
@@ -0,0 +1,1264 @@
+/*
+ * Unit test suite for bitmaps
+ *
+ * Copyright 2004 Huw Davies
+ * Copyright 2006 Dmitry Timoshkov
+ *
+ * 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 <assert.h>
+#include <string.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "mmsystem.h"
+
+#include "wine/test.h"
+
+static BOOL is_win9x;
+
+static INT BITMAP_GetWidthBytes( INT bmWidth, INT bpp )
+{
+    switch(bpp)
+    {
+    case 1:
+       return 2 * ((bmWidth+15) >> 4);
+
+    case 24:
+       bmWidth *= 3; /* fall through */
+    case 8:
+        return bmWidth + (bmWidth & 1);
+
+    case 32:
+        return bmWidth * 4;
+
+    case 16:
+    case 15:
+        return bmWidth * 2;
+
+    case 4:
+        return 2 * ((bmWidth+3) >> 2);
+
+    default:
+        trace("Unknown depth %d, please report.\n", bpp );
+        assert(0);
+    }
+    return -1;
+}
+
+static void test_bitmap_info(HBITMAP hbm, INT expected_depth, const BITMAPINFOHEADER *bmih)
+{
+    BITMAP bm;
+    INT ret, width_bytes;
+    char buf[512], buf_cmp[512];
+
+    ret = GetObject(hbm, sizeof(bm), &bm);
+    ok(ret == sizeof(bm), "GetObject returned %d\n", ret);
+
+    ok(bm.bmType == 0, "wrong bm.bmType %d\n", bm.bmType);
+    ok(bm.bmWidth == bmih->biWidth, "wrong bm.bmWidth %d\n", bm.bmWidth);
+    ok(bm.bmHeight == bmih->biHeight, "wrong bm.bmHeight %d\n", bm.bmHeight);
+    width_bytes = BITMAP_GetWidthBytes(bm.bmWidth, bm.bmBitsPixel);
+    ok(bm.bmWidthBytes == width_bytes, "wrong bm.bmWidthBytes %d != %d\n", bm.bmWidthBytes, width_bytes);
+    ok(bm.bmPlanes == bmih->biPlanes, "wrong bm.bmPlanes %d\n", bm.bmPlanes);
+    ok(bm.bmBitsPixel == expected_depth, "wrong bm.bmBitsPixel %d != %d\n", bm.bmBitsPixel, expected_depth);
+    ok(bm.bmBits == NULL, "wrong bm.bmBits %p\n", bm.bmBits);
+
+    assert(sizeof(buf) >= bm.bmWidthBytes * bm.bmHeight);
+    assert(sizeof(buf) == sizeof(buf_cmp));
+
+    ret = GetBitmapBits(hbm, 0, NULL);
+    ok(ret == bm.bmWidthBytes * bm.bmHeight, "%d != %d\n", ret, bm.bmWidthBytes * bm.bmHeight);
+
+    memset(buf_cmp, 0xAA, sizeof(buf_cmp));
+    memset(buf_cmp, 0, bm.bmWidthBytes * bm.bmHeight);
+
+    memset(buf, 0xAA, sizeof(buf));
+    ret = GetBitmapBits(hbm, sizeof(buf), buf);
+    ok(ret == bm.bmWidthBytes * bm.bmHeight, "%d != %d\n", ret, bm.bmWidthBytes * bm.bmHeight);
+    ok(!memcmp(buf, buf_cmp, sizeof(buf)), "buffers do not match\n");
+
+    /* test various buffer sizes for GetObject */
+    ret = GetObject(hbm, 0, NULL);
+    ok(ret == sizeof(bm), "wrong size %d\n", ret);
+
+    ret = GetObject(hbm, sizeof(bm) * 2, &bm);
+    ok(ret == sizeof(bm), "wrong size %d\n", ret);
+
+    ret = GetObject(hbm, sizeof(bm) / 2, &bm);
+    ok(ret == 0, "%d != 0\n", ret);
+
+    ret = GetObject(hbm, 0, &bm);
+    ok(ret == 0, "%d != 0\n", ret);
+
+    ret = GetObject(hbm, 1, &bm);
+    ok(ret == 0, "%d != 0\n", ret);
+}
+
+static void test_createdibitmap(void)
+{
+    HDC hdc, hdcmem;
+    BITMAPINFOHEADER bmih;
+    HBITMAP hbm, hbm_colour, hbm_old;
+    INT screen_depth;
+
+    hdc = GetDC(0);
+    screen_depth = GetDeviceCaps(hdc, BITSPIXEL);
+    memset(&bmih, 0, sizeof(bmih));
+    bmih.biSize = sizeof(bmih);
+    bmih.biWidth = 10;
+    bmih.biHeight = 10;
+    bmih.biPlanes = 1;
+    bmih.biBitCount = 32;
+    bmih.biCompression = BI_RGB;
+    /* First create an un-initialised bitmap.  The depth of the bitmap
+       should match that of the hdc and not that supplied in bmih.
+    */
+
+    /* First try 32 bits */
+    hbm = CreateDIBitmap(hdc, &bmih, 0, NULL, NULL, 0);
+    ok(hbm != NULL, "CreateDIBitmap failed\n");
+    test_bitmap_info(hbm, screen_depth, &bmih);
+    DeleteObject(hbm);
+    
+    /* Then 16 */
+    bmih.biBitCount = 16;
+    hbm = CreateDIBitmap(hdc, &bmih, 0, NULL, NULL, 0);
+    ok(hbm != NULL, "CreateDIBitmap failed\n");
+    test_bitmap_info(hbm, screen_depth, &bmih);
+    DeleteObject(hbm);
+
+    /* Then 1 */
+    bmih.biBitCount = 1;
+    hbm = CreateDIBitmap(hdc, &bmih, 0, NULL, NULL, 0);
+    ok(hbm != NULL, "CreateDIBitmap failed\n");
+    test_bitmap_info(hbm, screen_depth, &bmih);
+    DeleteObject(hbm);
+
+    /* Now with a monochrome dc we expect a monochrome bitmap */
+    hdcmem = CreateCompatibleDC(hdc);
+
+    /* First try 32 bits */
+    bmih.biBitCount = 32;
+    hbm = CreateDIBitmap(hdcmem, &bmih, 0, NULL, NULL, 0);
+    ok(hbm != NULL, "CreateDIBitmap failed\n");
+    test_bitmap_info(hbm, 1, &bmih);
+    DeleteObject(hbm);
+    
+    /* Then 16 */
+    bmih.biBitCount = 16;
+    hbm = CreateDIBitmap(hdcmem, &bmih, 0, NULL, NULL, 0);
+    ok(hbm != NULL, "CreateDIBitmap failed\n");
+    test_bitmap_info(hbm, 1, &bmih);
+    DeleteObject(hbm);
+    
+    /* Then 1 */
+    bmih.biBitCount = 1;
+    hbm = CreateDIBitmap(hdcmem, &bmih, 0, NULL, NULL, 0);
+    ok(hbm != NULL, "CreateDIBitmap failed\n");
+    test_bitmap_info(hbm, 1, &bmih);
+    DeleteObject(hbm);
+
+    /* Now select a polychrome bitmap into the dc and we expect
+       screen_depth bitmaps again */
+    hbm_colour = CreateCompatibleBitmap(hdc, 1, 1);
+    hbm_old = SelectObject(hdcmem, hbm_colour);
+
+    /* First try 32 bits */
+    bmih.biBitCount = 32;
+    hbm = CreateDIBitmap(hdcmem, &bmih, 0, NULL, NULL, 0);
+    ok(hbm != NULL, "CreateDIBitmap failed\n");
+    test_bitmap_info(hbm, screen_depth, &bmih);
+    DeleteObject(hbm);
+    
+    /* Then 16 */
+    bmih.biBitCount = 16;
+    hbm = CreateDIBitmap(hdcmem, &bmih, 0, NULL, NULL, 0);
+    ok(hbm != NULL, "CreateDIBitmap failed\n");
+    test_bitmap_info(hbm, screen_depth, &bmih);
+    DeleteObject(hbm);
+    
+    /* Then 1 */
+    bmih.biBitCount = 1;
+    hbm = CreateDIBitmap(hdcmem, &bmih, 0, NULL, NULL, 0);
+    ok(hbm != NULL, "CreateDIBitmap failed\n");
+    test_bitmap_info(hbm, screen_depth, &bmih);
+    DeleteObject(hbm);
+
+    SelectObject(hdcmem, hbm_old);
+    DeleteObject(hbm_colour);
+    DeleteDC(hdcmem);
+
+    /* If hdc == 0 then we get a 1 bpp bitmap */
+    if (!is_win9x) {
+        bmih.biBitCount = 32;
+        hbm = CreateDIBitmap(0, &bmih, 0, NULL, NULL, 0);
+        ok(hbm != NULL, "CreateDIBitmap failed\n");
+        test_bitmap_info(hbm, 1, &bmih);
+        DeleteObject(hbm);
+    }
+    
+    ReleaseDC(0, hdc);
+}
+
+static INT DIB_GetWidthBytes( int width, int bpp )
+{
+    int words;
+
+    switch (bpp)
+    {
+       case 1:  words = (width + 31) / 32; break;
+       case 4:  words = (width + 7) / 8; break;
+       case 8:  words = (width + 3) / 4; break;
+       case 15:
+       case 16: words = (width + 1) / 2; break;
+       case 24: words = (width * 3 + 3)/4; break;
+       case 32: words = width; break;
+
+        default:
+            words=0;
+            trace("Unknown depth %d, please report.\n", bpp );
+            assert(0);
+            break;
+    }
+    return 4 * words;
+}
+
+static void test_dib_info(HBITMAP hbm, const void *bits, const BITMAPINFOHEADER *bmih)
+{
+    BITMAP bm;
+    DIBSECTION ds;
+    INT ret, width_bytes;
+    BYTE *buf;
+
+    ret = GetObject(hbm, sizeof(bm), &bm);
+    ok(ret == sizeof(bm), "GetObject returned %d\n", ret);
+
+    ok(bm.bmType == 0, "wrong bm.bmType %d\n", bm.bmType);
+    ok(bm.bmWidth == bmih->biWidth, "wrong bm.bmWidth %d\n", bm.bmWidth);
+    ok(bm.bmHeight == bmih->biHeight, "wrong bm.bmHeight %d\n", bm.bmHeight);
+    width_bytes = DIB_GetWidthBytes(bm.bmWidth, bm.bmBitsPixel);
+    ok(bm.bmWidthBytes == width_bytes, "wrong bm.bmWidthBytes %d != %d\n", bm.bmWidthBytes, width_bytes);
+    ok(bm.bmPlanes == bmih->biPlanes, "wrong bm.bmPlanes %d\n", bm.bmPlanes);
+    ok(bm.bmBitsPixel == bmih->biBitCount, "bm.bmBitsPixel %d != %d\n", bm.bmBitsPixel, bmih->biBitCount);
+    ok(bm.bmBits == bits, "wrong bm.bmBits %p != %p\n", bm.bmBits, bits);
+
+    buf = HeapAlloc(GetProcessHeap(), 0, bm.bmWidthBytes * bm.bmHeight + 4096);
+
+    width_bytes = BITMAP_GetWidthBytes(bm.bmWidth, bm.bmBitsPixel);
+
+    /* GetBitmapBits returns not 32-bit aligned data */
+    ret = GetBitmapBits(hbm, 0, NULL);
+    ok(ret == width_bytes * bm.bmHeight, "%d != %d\n", ret, width_bytes * bm.bmHeight);
+
+    memset(buf, 0xAA, bm.bmWidthBytes * bm.bmHeight + 4096);
+    ret = GetBitmapBits(hbm, bm.bmWidthBytes * bm.bmHeight + 4096, buf);
+    ok(ret == width_bytes * bm.bmHeight, "%d != %d\n", ret, width_bytes * bm.bmHeight);
+
+    HeapFree(GetProcessHeap(), 0, buf);
+
+    /* test various buffer sizes for GetObject */
+    memset(&ds, 0xAA, sizeof(ds));
+    ret = GetObject(hbm, sizeof(bm) * 2, &bm);
+    ok(ret == sizeof(bm), "wrong size %d\n", ret);
+    ok(bm.bmWidth == bmih->biWidth, "wrong bm.bmWidth %d\n", bm.bmWidth);
+    ok(bm.bmHeight == bmih->biHeight, "wrong bm.bmHeight %d\n", bm.bmHeight);
+    ok(bm.bmBits == bits, "wrong bm.bmBits %p != %p\n", bm.bmBits, bits);
+
+    ret = GetObject(hbm, sizeof(bm) / 2, &bm);
+    ok(ret == 0, "%d != 0\n", ret);
+
+    ret = GetObject(hbm, 0, &bm);
+    ok(ret == 0, "%d != 0\n", ret);
+
+    ret = GetObject(hbm, 1, &bm);
+    ok(ret == 0, "%d != 0\n", ret);
+
+    /* test various buffer sizes for GetObject */
+    ret = GetObject(hbm, 0, NULL);
+    ok(ret == sizeof(bm), "wrong size %d\n", ret);
+
+    memset(&ds, 0xAA, sizeof(ds));
+    ret = GetObject(hbm, sizeof(ds) * 2, &ds);
+    ok(ret == sizeof(ds), "wrong size %d\n", ret);
+
+    ok(ds.dsBm.bmBits == bits, "wrong bm.bmBits %p != %p\n", ds.dsBm.bmBits, bits);
+    ok(ds.dsBmih.biSizeImage == ds.dsBm.bmWidthBytes * ds.dsBm.bmHeight, "%lu != %u\n",
+       ds.dsBmih.biSizeImage, ds.dsBm.bmWidthBytes * ds.dsBm.bmHeight);
+    ok(bmih->biSizeImage == 0, "%lu != 0\n", bmih->biSizeImage);
+    ds.dsBmih.biSizeImage = 0;
+
+    ok(ds.dsBmih.biSize == bmih->biSize, "%lu != %lu\n", ds.dsBmih.biSize, bmih->biSize);
+    ok(ds.dsBmih.biWidth == bmih->biWidth, "%lu != %lu\n", ds.dsBmih.biWidth, bmih->biWidth);
+    ok(ds.dsBmih.biHeight == bmih->biHeight, "%lu != %lu\n", ds.dsBmih.biHeight, bmih->biHeight);
+    ok(ds.dsBmih.biPlanes == bmih->biPlanes, "%u != %u\n", ds.dsBmih.biPlanes, bmih->biPlanes);
+    ok(ds.dsBmih.biBitCount == bmih->biBitCount, "%u != %u\n", ds.dsBmih.biBitCount, bmih->biBitCount);
+    ok(ds.dsBmih.biCompression == bmih->biCompression, "%lu != %lu\n", ds.dsBmih.biCompression, bmih->biCompression);
+    ok(ds.dsBmih.biSizeImage == bmih->biSizeImage, "%lu != %lu\n", ds.dsBmih.biSizeImage, bmih->biSizeImage);
+    ok(ds.dsBmih.biXPelsPerMeter == bmih->biXPelsPerMeter, "%lu != %lu\n", ds.dsBmih.biXPelsPerMeter, bmih->biXPelsPerMeter);
+    ok(ds.dsBmih.biYPelsPerMeter == bmih->biYPelsPerMeter, "%lu != %lu\n", ds.dsBmih.biYPelsPerMeter, bmih->biYPelsPerMeter);
+
+    memset(&ds, 0xAA, sizeof(ds));
+    ret = GetObject(hbm, sizeof(ds) - 4, &ds);
+    ok(ret == sizeof(ds.dsBm), "wrong size %d\n", ret);
+    ok(ds.dsBm.bmWidth == bmih->biWidth, "%lu != %lu\n", ds.dsBmih.biWidth, bmih->biWidth);
+    ok(ds.dsBm.bmHeight == bmih->biHeight, "%lu != %lu\n", ds.dsBmih.biHeight, bmih->biHeight);
+    ok(ds.dsBm.bmBits == bits, "%p != %p\n", ds.dsBm.bmBits, bits);
+
+    ret = GetObject(hbm, 0, &ds);
+    ok(ret == 0, "%d != 0\n", ret);
+
+    ret = GetObject(hbm, 1, &ds);
+    ok(ret == 0, "%d != 0\n", ret);
+}
+
+#define test_color_todo(got, exp, txt, todo) \
+    if (!todo && got != exp && screen_depth < 24) { \
+      todo_wine ok(0, #txt " failed at %d-bit screen depth: got 0x%06x expected 0x%06x - skipping DIB tests\n", \
+                   screen_depth, (UINT)got, (UINT)exp); \
+      return; \
+    } else if (todo) todo_wine { ok(got == exp, #txt " failed: got 0x%06x expected 0x%06x\n", (UINT)got, (UINT)exp); } \
+    else ok(got == exp, #txt " failed: got 0x%06x expected 0x%06x\n", (UINT)got, (UINT)exp) \
+
+#define test_color(hdc, color, exp, todo_setp, todo_getp) \
+{ \
+    COLORREF c; \
+    c = SetPixel(hdc, 0, 0, color); \
+    if (!is_win9x) { test_color_todo(c, exp, SetPixel, todo_setp); } \
+    c = GetPixel(hdc, 0, 0); \
+    test_color_todo(c, exp, GetPixel, todo_getp); \
+}
+
+static void test_dibsections(void)
+{
+    HDC hdc, hdcmem, hdcmem2;
+    HBITMAP hdib, oldbm, hdib2, oldbm2;
+    char bmibuf[sizeof(BITMAPINFO) + 256 * sizeof(RGBQUAD)];
+    char bcibuf[sizeof(BITMAPCOREINFO) + 256 * sizeof(RGBTRIPLE)];
+    BITMAPINFO *pbmi = (BITMAPINFO *)bmibuf;
+    BITMAPCOREINFO *pbci = (BITMAPCOREINFO *)bcibuf;
+    HBITMAP hcoredib;
+    char coreBits[256];
+    BYTE *bits;
+    RGBQUAD rgb[256];
+    int ret;
+    char logpalbuf[sizeof(LOGPALETTE) + 256 * sizeof(PALETTEENTRY)];
+    LOGPALETTE *plogpal = (LOGPALETTE*)logpalbuf;
+    WORD *index;
+    DWORD *bits32;
+    HPALETTE hpal, oldpal;
+    DIBSECTION dibsec;
+    COLORREF c0, c1;
+    int i;
+    int screen_depth;
+    MEMORY_BASIC_INFORMATION info;
+
+    hdc = GetDC(0);
+    screen_depth = GetDeviceCaps(hdc, BITSPIXEL) * GetDeviceCaps(hdc, PLANES);
+
+    memset(pbmi, 0, sizeof(bmibuf));
+    pbmi->bmiHeader.biSize = sizeof(pbmi->bmiHeader);
+    pbmi->bmiHeader.biHeight = 100;
+    pbmi->bmiHeader.biWidth = 512;
+    pbmi->bmiHeader.biBitCount = 24;
+    pbmi->bmiHeader.biPlanes = 1;
+    pbmi->bmiHeader.biCompression = BI_RGB;
+
+    SetLastError(0xdeadbeef);
+    hdib = CreateDIBSection(hdc, pbmi, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
+    ok(hdib != NULL, "CreateDIBSection error %ld\n", GetLastError());
+    ok(GetObject(hdib, sizeof(DIBSECTION), &dibsec) != 0, "GetObject failed for DIBSection\n");
+    ok(dibsec.dsBm.bmBits == bits, "dibsec.dsBits %p != bits %p\n", dibsec.dsBm.bmBits, bits);
+
+    /* test the DIB memory */
+    ok(VirtualQuery(bits, &info, sizeof(info)) == sizeof(info),
+        "VirtualQuery failed\n");
+    ok(info.BaseAddress == bits, "%p != %p\n", info.BaseAddress, bits);
+    ok(info.AllocationBase == bits, "%p != %p\n", info.AllocationBase, bits);
+    ok(info.AllocationProtect == PAGE_READWRITE, "%lx != PAGE_READWRITE\n", info.AllocationProtect);
+    ok(info.RegionSize == 0x26000, "0x%lx != 0x26000\n", info.RegionSize);
+    ok(info.State == MEM_COMMIT, "%lx != MEM_COMMIT\n", info.State);
+    ok(info.Protect == PAGE_READWRITE, "%lx != PAGE_READWRITE\n", info.Protect);
+    ok(info.Type == MEM_PRIVATE, "%lx != MEM_PRIVATE\n", info.Type);
+
+    test_dib_info(hdib, bits, &pbmi->bmiHeader);
+    DeleteObject(hdib);
+
+    pbmi->bmiHeader.biBitCount = 8;
+    pbmi->bmiHeader.biCompression = BI_RLE8;
+    SetLastError(0xdeadbeef);
+    hdib = CreateDIBSection(hdc, pbmi, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
+    ok(hdib == NULL, "CreateDIBSection should fail when asked to create a compressed DIB section\n");
+    ok(GetLastError() == 0xdeadbeef, "wrong error %ld\n", GetLastError());
+
+    pbmi->bmiHeader.biBitCount = 16;
+    pbmi->bmiHeader.biCompression = BI_BITFIELDS;
+    ((PDWORD)pbmi->bmiColors)[0] = 0xf800;
+    ((PDWORD)pbmi->bmiColors)[1] = 0x07e0;
+    ((PDWORD)pbmi->bmiColors)[2] = 0x001f;
+    SetLastError(0xdeadbeef);
+    hdib = CreateDIBSection(hdc, pbmi, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
+    ok(hdib != NULL, "CreateDIBSection error %ld\n", GetLastError());
+
+    /* test the DIB memory */
+    ok(VirtualQuery(bits, &info, sizeof(info)) == sizeof(info),
+        "VirtualQuery failed\n");
+    ok(info.BaseAddress == bits, "%p != %p\n", info.BaseAddress, bits);
+    ok(info.AllocationBase == bits, "%p != %p\n", info.AllocationBase, bits);
+    ok(info.AllocationProtect == PAGE_READWRITE, "%lx != PAGE_READWRITE\n", info.AllocationProtect);
+    ok(info.RegionSize == 0x19000, "0x%lx != 0x19000\n", info.RegionSize);
+    ok(info.State == MEM_COMMIT, "%lx != MEM_COMMIT\n", info.State);
+    ok(info.Protect == PAGE_READWRITE, "%lx != PAGE_READWRITE\n", info.Protect);
+    ok(info.Type == MEM_PRIVATE, "%lx != MEM_PRIVATE\n", info.Type);
+
+    test_dib_info(hdib, bits, &pbmi->bmiHeader);
+    DeleteObject(hdib);
+
+    memset(pbmi, 0, sizeof(bmibuf));
+    pbmi->bmiHeader.biSize = sizeof(pbmi->bmiHeader);
+    pbmi->bmiHeader.biHeight = 16;
+    pbmi->bmiHeader.biWidth = 16;
+    pbmi->bmiHeader.biBitCount = 1;
+    pbmi->bmiHeader.biPlanes = 1;
+    pbmi->bmiHeader.biCompression = BI_RGB;
+    pbmi->bmiColors[0].rgbRed = 0xff;
+    pbmi->bmiColors[0].rgbGreen = 0;
+    pbmi->bmiColors[0].rgbBlue = 0;
+    pbmi->bmiColors[1].rgbRed = 0;
+    pbmi->bmiColors[1].rgbGreen = 0;
+    pbmi->bmiColors[1].rgbBlue = 0xff;
+
+    hdib = CreateDIBSection(hdc, pbmi, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
+    ok(hdib != NULL, "CreateDIBSection failed\n");
+    ok(GetObject(hdib, sizeof(DIBSECTION), &dibsec) != 0, "GetObject failed for DIBSection\n");
+    ok(dibsec.dsBmih.biClrUsed == 2,
+        "created DIBSection: wrong biClrUsed field: %lu, should be: %u\n", dibsec.dsBmih.biClrUsed, 2);
+
+    /* Test if the old BITMAPCOREINFO structure is supported */    
+        
+    pbci->bmciHeader.bcSize = sizeof(BITMAPCOREHEADER);
+    pbci->bmciHeader.bcBitCount = 0;
+
+    if (!is_win9x) {
+        ret = GetDIBits(hdc, hdib, 0, 16, NULL, (BITMAPINFO*) pbci, DIB_RGB_COLORS);
+        ok(ret, "GetDIBits doesn't work with a BITMAPCOREHEADER\n");
+        ok((pbci->bmciHeader.bcWidth == 16) && (pbci->bmciHeader.bcHeight == 16)
+            && (pbci->bmciHeader.bcBitCount == 1) && (pbci->bmciHeader.bcPlanes == 1),
+        "GetDIBits did't fill in the BITMAPCOREHEADER structure properly\n");
+
+        ret = GetDIBits(hdc, hdib, 0, 16, &coreBits, (BITMAPINFO*) pbci, DIB_RGB_COLORS);
+        ok(ret, "GetDIBits doesn't work with a BITMAPCOREHEADER\n");
+        ok((pbci->bmciColors[0].rgbtRed == 0xff) && (pbci->bmciColors[0].rgbtGreen == 0) &&
+            (pbci->bmciColors[0].rgbtBlue == 0) && (pbci->bmciColors[1].rgbtRed == 0) &&
+            (pbci->bmciColors[1].rgbtGreen == 0) && (pbci->bmciColors[1].rgbtBlue == 0xff),
+            "The color table has not been translated to the old BITMAPCOREINFO format\n");
+
+        hcoredib = CreateDIBSection(hdc, (BITMAPINFO*) pbci, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
+        ok(hcoredib != NULL, "CreateDIBSection failed with a BITMAPCOREINFO\n");
+
+        ZeroMemory(pbci->bmciColors, 256 * sizeof(RGBTRIPLE));
+        ret = GetDIBits(hdc, hcoredib, 0, 16, &coreBits, (BITMAPINFO*) pbci, DIB_RGB_COLORS);
+        ok(ret, "GetDIBits doesn't work with a BITMAPCOREHEADER\n");
+        ok((pbci->bmciColors[0].rgbtRed == 0xff) && (pbci->bmciColors[0].rgbtGreen == 0) &&
+            (pbci->bmciColors[0].rgbtBlue == 0) && (pbci->bmciColors[1].rgbtRed == 0) &&
+            (pbci->bmciColors[1].rgbtGreen == 0) && (pbci->bmciColors[1].rgbtBlue == 0xff),
+            "The color table has not been translated to the old BITMAPCOREINFO format\n");
+
+        DeleteObject(hcoredib);
+    }
+
+    hdcmem = CreateCompatibleDC(hdc);
+    oldbm = SelectObject(hdcmem, hdib);
+
+    ret = GetDIBColorTable(hdcmem, 0, 2, rgb);
+    ok(ret == 2, "GetDIBColorTable returned %d\n", ret);
+    ok(!memcmp(rgb, pbmi->bmiColors, 2 * sizeof(RGBQUAD)),
+       "GetDIBColorTable returns table 0: r%02x g%02x b%02x res%02x 1: r%02x g%02x b%02x res%02x\n",
+       rgb[0].rgbRed, rgb[0].rgbGreen, rgb[0].rgbBlue, rgb[0].rgbReserved,
+       rgb[1].rgbRed, rgb[1].rgbGreen, rgb[1].rgbBlue, rgb[1].rgbReserved);
+
+    c0 = RGB(pbmi->bmiColors[0].rgbRed, pbmi->bmiColors[0].rgbGreen, pbmi->bmiColors[0].rgbBlue);
+    c1 = RGB(pbmi->bmiColors[1].rgbRed, pbmi->bmiColors[1].rgbGreen, pbmi->bmiColors[1].rgbBlue);
+
+    test_color(hdcmem, DIBINDEX(0), c0, 0, 1);
+    test_color(hdcmem, DIBINDEX(1), c1, 0, 1);
+    test_color(hdcmem, DIBINDEX(2), c0, 1, 1);
+    test_color(hdcmem, PALETTEINDEX(0), c0, 1, 1);
+    test_color(hdcmem, PALETTEINDEX(1), c0, 1, 1);
+    test_color(hdcmem, PALETTEINDEX(2), c0, 1, 1);
+    test_color(hdcmem, PALETTERGB(pbmi->bmiColors[0].rgbRed, pbmi->bmiColors[0].rgbGreen,
+        pbmi->bmiColors[0].rgbBlue), c0, 1, 1);
+    test_color(hdcmem, PALETTERGB(pbmi->bmiColors[1].rgbRed, pbmi->bmiColors[1].rgbGreen,
+        pbmi->bmiColors[1].rgbBlue), c1, 1, 1);
+    test_color(hdcmem, PALETTERGB(0, 0, 0), c0, 1, 1);
+    test_color(hdcmem, PALETTERGB(0xff, 0xff, 0xff), c0, 1, 1);
+    test_color(hdcmem, PALETTERGB(0, 0, 0xfe), c1, 1, 1);
+
+    SelectObject(hdcmem, oldbm);
+    DeleteObject(hdib);
+
+    pbmi->bmiColors[0].rgbRed = 0xff;
+    pbmi->bmiColors[0].rgbGreen = 0xff;
+    pbmi->bmiColors[0].rgbBlue = 0xff;
+    pbmi->bmiColors[1].rgbRed = 0;
+    pbmi->bmiColors[1].rgbGreen = 0;
+    pbmi->bmiColors[1].rgbBlue = 0;
+
+    hdib = CreateDIBSection(hdc, pbmi, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
+    ok(hdib != NULL, "CreateDIBSection failed\n");
+
+    test_dib_info(hdib, bits, &pbmi->bmiHeader);
+
+    oldbm = SelectObject(hdcmem, hdib);
+
+    ret = GetDIBColorTable(hdcmem, 0, 2, rgb);
+    ok(ret == 2, "GetDIBColorTable returned %d\n", ret);
+    ok(!memcmp(rgb, pbmi->bmiColors, 2 * sizeof(RGBQUAD)),
+       "GetDIBColorTable returns table 0: r%02x g%02x b%02x res%02x 1: r%02x g%02x b%02x res%02x\n",
+       rgb[0].rgbRed, rgb[0].rgbGreen, rgb[0].rgbBlue, rgb[0].rgbReserved,
+       rgb[1].rgbRed, rgb[1].rgbGreen, rgb[1].rgbBlue, rgb[1].rgbReserved);
+
+    SelectObject(hdcmem, oldbm);
+    test_dib_info(hdib, bits, &pbmi->bmiHeader);
+    DeleteObject(hdib);
+
+    pbmi->bmiHeader.biBitCount = 4;
+    for (i = 0; i < 16; i++) {
+        pbmi->bmiColors[i].rgbRed = i;
+        pbmi->bmiColors[i].rgbGreen = 16-i;
+        pbmi->bmiColors[i].rgbBlue = 0;
+    }
+    hdib = CreateDIBSection(hdcmem, pbmi, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
+    ok(hdib != NULL, "CreateDIBSection failed\n");
+    ok(GetObject(hdib, sizeof(DIBSECTION), &dibsec) != 0, "GetObject failed for DIB Section\n");
+    ok(dibsec.dsBmih.biClrUsed == 16,
+       "created DIBSection: wrong biClrUsed field: %lu, should be: %u\n", dibsec.dsBmih.biClrUsed, 16);
+    test_dib_info(hdib, bits, &pbmi->bmiHeader);
+    DeleteObject(hdib);
+
+    pbmi->bmiHeader.biBitCount = 8;
+
+    for (i = 0; i < 128; i++) {
+        pbmi->bmiColors[i].rgbRed = 255 - i * 2;
+        pbmi->bmiColors[i].rgbGreen = i * 2;
+        pbmi->bmiColors[i].rgbBlue = 0;
+        pbmi->bmiColors[255 - i].rgbRed = 0;
+        pbmi->bmiColors[255 - i].rgbGreen = i * 2;
+        pbmi->bmiColors[255 - i].rgbBlue = 255 - i * 2;
+    }
+    hdib = CreateDIBSection(hdcmem, pbmi, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
+    ok(hdib != NULL, "CreateDIBSection failed\n");
+    ok(GetObject(hdib, sizeof(DIBSECTION), &dibsec) != 0, "GetObject failed for DIB Section\n");
+    ok(dibsec.dsBmih.biClrUsed == 256,
+        "created DIBSection: wrong biClrUsed field: %lu, should be: %u\n", dibsec.dsBmih.biClrUsed, 256);
+
+    oldbm = SelectObject(hdcmem, hdib);
+
+    for (i = 0; i < 256; i++) {
+        test_color(hdcmem, DIBINDEX(i), 
+            RGB(pbmi->bmiColors[i].rgbRed, pbmi->bmiColors[i].rgbGreen, pbmi->bmiColors[i].rgbBlue), 0, 0);
+        test_color(hdcmem, PALETTERGB(pbmi->bmiColors[i].rgbRed, pbmi->bmiColors[i].rgbGreen, pbmi->bmiColors[i].rgbBlue), 
+            RGB(pbmi->bmiColors[i].rgbRed, pbmi->bmiColors[i].rgbGreen, pbmi->bmiColors[i].rgbBlue), 0, 0);
+    }
+
+    SelectObject(hdcmem, oldbm);
+    test_dib_info(hdib, bits, &pbmi->bmiHeader);
+    DeleteObject(hdib);
+
+    pbmi->bmiHeader.biBitCount = 1;
+
+    /* Now create a palette and a palette indexed dib section */
+    memset(plogpal, 0, sizeof(logpalbuf));
+    plogpal->palVersion = 0x300;
+    plogpal->palNumEntries = 2;
+    plogpal->palPalEntry[0].peRed = 0xff;
+    plogpal->palPalEntry[0].peBlue = 0xff;
+    plogpal->palPalEntry[1].peGreen = 0xff;
+
+    index = (WORD*)pbmi->bmiColors;
+    *index++ = 0;
+    *index = 1;
+    hpal = CreatePalette(plogpal);
+    ok(hpal != NULL, "CreatePalette failed\n");
+    oldpal = SelectPalette(hdc, hpal, TRUE);
+    hdib = CreateDIBSection(hdc, pbmi, DIB_PAL_COLORS, (void**)&bits, NULL, 0);
+    ok(hdib != NULL, "CreateDIBSection failed\n");
+    ok(GetObject(hdib, sizeof(DIBSECTION), &dibsec) != 0, "GetObject failed for DIB Section\n");
+    ok(dibsec.dsBmih.biClrUsed == 2,
+        "created DIBSection: wrong biClrUsed field: %lu, should be: %u\n", dibsec.dsBmih.biClrUsed, 2);
+
+    /* The colour table has already been grabbed from the dc, so we select back the
+       old palette */
+
+    SelectPalette(hdc, oldpal, TRUE);
+    oldbm = SelectObject(hdcmem, hdib);
+    oldpal = SelectPalette(hdcmem, hpal, TRUE);
+
+    ret = GetDIBColorTable(hdcmem, 0, 2, rgb);
+    ok(ret == 2, "GetDIBColorTable returned %d\n", ret);
+    ok(rgb[0].rgbRed == 0xff && rgb[0].rgbBlue == 0xff && rgb[0].rgbGreen == 0 &&
+       rgb[1].rgbRed == 0    && rgb[1].rgbBlue == 0    && rgb[1].rgbGreen == 0xff,
+       "GetDIBColorTable returns table 0: r%02x g%02x b%02x res%02x 1: r%02x g%02x b%02x res%02x\n",
+       rgb[0].rgbRed, rgb[0].rgbGreen, rgb[0].rgbBlue, rgb[0].rgbReserved,
+       rgb[1].rgbRed, rgb[1].rgbGreen, rgb[1].rgbBlue, rgb[1].rgbReserved);
+
+    c0 = RGB(plogpal->palPalEntry[0].peRed, plogpal->palPalEntry[0].peGreen, plogpal->palPalEntry[0].peBlue);
+    c1 = RGB(plogpal->palPalEntry[1].peRed, plogpal->palPalEntry[1].peGreen, plogpal->palPalEntry[1].peBlue);
+
+    test_color(hdcmem, DIBINDEX(0), c0, 0, 1);
+    test_color(hdcmem, DIBINDEX(1), c1, 0, 1);
+    test_color(hdcmem, DIBINDEX(2), c0, 1, 1);
+    test_color(hdcmem, PALETTEINDEX(0), c0, 0, 1);
+    test_color(hdcmem, PALETTEINDEX(1), c1, 0, 1);
+    test_color(hdcmem, PALETTEINDEX(2), c0, 1, 1);
+    test_color(hdcmem, PALETTERGB(plogpal->palPalEntry[0].peRed, plogpal->palPalEntry[0].peGreen,
+        plogpal->palPalEntry[0].peBlue), c0, 1, 1);
+    test_color(hdcmem, PALETTERGB(plogpal->palPalEntry[1].peRed, plogpal->palPalEntry[1].peGreen,
+        plogpal->palPalEntry[1].peBlue), c1, 1, 1);
+    test_color(hdcmem, PALETTERGB(0, 0, 0), c1, 1, 1);
+    test_color(hdcmem, PALETTERGB(0xff, 0xff, 0xff), c0, 1, 1);
+    test_color(hdcmem, PALETTERGB(0, 0, 0xfe), c0, 1, 1);
+    test_color(hdcmem, PALETTERGB(0, 1, 0), c1, 1, 1);
+    test_color(hdcmem, PALETTERGB(0x3f, 0, 0x3f), c1, 1, 1);
+    test_color(hdcmem, PALETTERGB(0x40, 0, 0x40), c0, 1, 1);
+
+    /* Bottom and 2nd row from top green, everything else magenta */
+    bits[0] = bits[1] = 0xff;
+    bits[13 * 4] = bits[13*4 + 1] = 0xff;
+
+    test_dib_info(hdib, bits, &pbmi->bmiHeader);
+
+    pbmi->bmiHeader.biBitCount = 32;
+
+    hdib2 = CreateDIBSection(NULL, pbmi, DIB_RGB_COLORS, (void **)&bits32, NULL, 0);
+    ok(hdib2 != NULL, "CreateDIBSection failed\n");
+    hdcmem2 = CreateCompatibleDC(hdc);
+    oldbm2 = SelectObject(hdcmem2, hdib2);
+
+    BitBlt(hdcmem2, 0, 0, 16,16, hdcmem, 0, 0, SRCCOPY);
+
+    ok(bits32[0] == 0xff00, "lower left pixel is %08lx\n", bits32[0]);
+    ok(bits32[17] == 0xff00ff, "bottom but one, left pixel is %08lx\n", bits32[17]);
+
+    SelectObject(hdcmem2, oldbm2);
+    test_dib_info(hdib2, bits32, &pbmi->bmiHeader);
+    DeleteObject(hdib2);
+
+    SelectObject(hdcmem, oldbm);
+    SelectObject(hdcmem, oldpal);
+    DeleteObject(hdib);
+    DeleteObject(hpal);
+
+
+    pbmi->bmiHeader.biBitCount = 8;
+
+    memset(plogpal, 0, sizeof(logpalbuf));
+    plogpal->palVersion = 0x300;
+    plogpal->palNumEntries = 256;
+
+    for (i = 0; i < 128; i++) {
+        plogpal->palPalEntry[i].peRed = 255 - i * 2;
+        plogpal->palPalEntry[i].peBlue = i * 2;
+        plogpal->palPalEntry[i].peGreen = 0;
+        plogpal->palPalEntry[255 - i].peRed = 0;
+        plogpal->palPalEntry[255 - i].peGreen = i * 2;
+        plogpal->palPalEntry[255 - i].peBlue = 255 - i * 2;
+    }
+
+    index = (WORD*)pbmi->bmiColors;
+    for (i = 0; i < 256; i++) {
+        *index++ = i;
+    }
+
+    hpal = CreatePalette(plogpal);
+    ok(hpal != NULL, "CreatePalette failed\n");
+    oldpal = SelectPalette(hdc, hpal, TRUE);
+    hdib = CreateDIBSection(hdc, pbmi, DIB_PAL_COLORS, (void**)&bits, NULL, 0);
+    ok(hdib != NULL, "CreateDIBSection failed\n");
+    ok(GetObject(hdib, sizeof(DIBSECTION), &dibsec) != 0, "GetObject failed for DIB Section\n");
+    ok(dibsec.dsBmih.biClrUsed == 256,
+        "created DIBSection: wrong biClrUsed field: %lu, should be: %u\n", dibsec.dsBmih.biClrUsed, 256);
+
+    test_dib_info(hdib, bits, &pbmi->bmiHeader);
+
+    SelectPalette(hdc, oldpal, TRUE);
+    oldbm = SelectObject(hdcmem, hdib);
+    oldpal = SelectPalette(hdcmem, hpal, TRUE);
+
+    ret = GetDIBColorTable(hdcmem, 0, 256, rgb);
+    ok(ret == 256, "GetDIBColorTable returned %d\n", ret);
+    for (i = 0; i < 256; i++) {
+        ok(rgb[i].rgbRed == plogpal->palPalEntry[i].peRed && 
+            rgb[i].rgbBlue == plogpal->palPalEntry[i].peBlue && 
+            rgb[i].rgbGreen == plogpal->palPalEntry[i].peGreen, 
+            "GetDIBColorTable returns table %d: r%02x g%02x b%02x res%02x\n",
+            i, rgb[i].rgbRed, rgb[i].rgbGreen, rgb[i].rgbBlue, rgb[i].rgbReserved);
+    }
+
+    for (i = 0; i < 256; i++) {
+        test_color(hdcmem, DIBINDEX(i), 
+            RGB(plogpal->palPalEntry[i].peRed, plogpal->palPalEntry[i].peGreen, plogpal->palPalEntry[i].peBlue), 0, 0);
+        test_color(hdcmem, PALETTEINDEX(i), 
+            RGB(plogpal->palPalEntry[i].peRed, plogpal->palPalEntry[i].peGreen, plogpal->palPalEntry[i].peBlue), 0, 0);
+        test_color(hdcmem, PALETTERGB(plogpal->palPalEntry[i].peRed, plogpal->palPalEntry[i].peGreen, plogpal->palPalEntry[i].peBlue), 
+            RGB(plogpal->palPalEntry[i].peRed, plogpal->palPalEntry[i].peGreen, plogpal->palPalEntry[i].peBlue), 0, 0);
+    }
+
+    SelectPalette(hdcmem, oldpal, TRUE);
+    SelectObject(hdcmem, oldbm);
+    DeleteObject(hdib);
+    DeleteObject(hpal);
+
+
+    DeleteDC(hdcmem);
+    ReleaseDC(0, hdc);
+}    
+
+void test_mono_dibsection(void)
+{
+    HDC hdc, memdc;
+    HBITMAP old_bm, mono_ds;
+    char bmibuf[sizeof(BITMAPINFO) + 256 * sizeof(RGBQUAD)];
+    BITMAPINFO *pbmi = (BITMAPINFO *)bmibuf;
+    BYTE bits[10 * 4];
+    BYTE *ds_bits;
+    int num;
+
+    hdc = GetDC(0);
+
+    memdc = CreateCompatibleDC(hdc);
+
+    memset(pbmi, 0, sizeof(bmibuf));
+    pbmi->bmiHeader.biSize = sizeof(pbmi->bmiHeader);
+    pbmi->bmiHeader.biHeight = 10;
+    pbmi->bmiHeader.biWidth = 10;
+    pbmi->bmiHeader.biBitCount = 1;
+    pbmi->bmiHeader.biPlanes = 1;
+    pbmi->bmiHeader.biCompression = BI_RGB;
+    pbmi->bmiColors[0].rgbRed = 0xff;
+    pbmi->bmiColors[0].rgbGreen = 0xff;
+    pbmi->bmiColors[0].rgbBlue = 0xff;
+    pbmi->bmiColors[1].rgbRed = 0x0;
+    pbmi->bmiColors[1].rgbGreen = 0x0;
+    pbmi->bmiColors[1].rgbBlue = 0x0;
+
+    /*
+     * First dib section is 'inverted' ie color[0] is white, color[1] is black
+     */
+
+    mono_ds = CreateDIBSection(hdc, pbmi, DIB_RGB_COLORS, (void**)&ds_bits, NULL, 0);
+    ok(mono_ds != NULL, "CreateDIBSection rets NULL\n");
+    old_bm = SelectObject(memdc, mono_ds);
+
+    /* black border, white interior */
+    Rectangle(memdc, 0, 0, 10, 10);
+    ok(ds_bits[0] == 0xff, "out_bits %02x\n", ds_bits[0]);
+    ok(ds_bits[4] == 0x80, "out_bits %02x\n", ds_bits[4]);
+
+    /* SetDIBitsToDevice with an inverted bmi -> inverted dib section */
+
+    memset(bits, 0, sizeof(bits));
+    bits[0] = 0xaa;
+
+    SetDIBitsToDevice(memdc, 0, 0, 10, 10, 0, 0, 0, 10, bits, pbmi, DIB_RGB_COLORS);
+    ok(ds_bits[0] == 0xaa, "out_bits %02x\n", ds_bits[0]);
+
+    /* SetDIBitsToDevice with a normal bmi -> inverted dib section */
+
+    pbmi->bmiColors[0].rgbRed = 0x0;
+    pbmi->bmiColors[0].rgbGreen = 0x0;
+    pbmi->bmiColors[0].rgbBlue = 0x0;
+    pbmi->bmiColors[1].rgbRed = 0xff;
+    pbmi->bmiColors[1].rgbGreen = 0xff;
+    pbmi->bmiColors[1].rgbBlue = 0xff;
+
+    SetDIBitsToDevice(memdc, 0, 0, 10, 10, 0, 0, 0, 10, bits, pbmi, DIB_RGB_COLORS);
+    ok(ds_bits[0] == 0x55, "out_bits %02x\n", ds_bits[0]);
+
+    SelectObject(memdc, old_bm);
+    DeleteObject(mono_ds);
+
+    /*
+     * Next dib section is 'normal' ie color[0] is black, color[1] is white
+     */
+
+    pbmi->bmiColors[0].rgbRed = 0x0;
+    pbmi->bmiColors[0].rgbGreen = 0x0;
+    pbmi->bmiColors[0].rgbBlue = 0x0;
+    pbmi->bmiColors[1].rgbRed = 0xff;
+    pbmi->bmiColors[1].rgbGreen = 0xff;
+    pbmi->bmiColors[1].rgbBlue = 0xff;
+
+    mono_ds = CreateDIBSection(hdc, pbmi, DIB_RGB_COLORS, (void**)&ds_bits, NULL, 0);
+    ok(mono_ds != NULL, "CreateDIBSection rets NULL\n");
+    old_bm = SelectObject(memdc, mono_ds);
+
+    /* black border, white interior */
+    Rectangle(memdc, 0, 0, 10, 10);
+    ok(ds_bits[0] == 0x00, "out_bits %02x\n", ds_bits[0]);
+    ok(ds_bits[4] == 0x7f, "out_bits %02x\n", ds_bits[4]);
+
+    /* SetDIBitsToDevice with a normal bmi -> normal dib section */
+
+    SetDIBitsToDevice(memdc, 0, 0, 10, 10, 0, 0, 0, 10, bits, pbmi, DIB_RGB_COLORS);
+    ok(ds_bits[0] == 0xaa, "out_bits %02x\n", ds_bits[0]);
+
+    /* SetDIBitsToDevice with a inverted bmi -> normal dib section */
+
+    pbmi->bmiColors[0].rgbRed = 0xff;
+    pbmi->bmiColors[0].rgbGreen = 0xff;
+    pbmi->bmiColors[0].rgbBlue = 0xff;
+    pbmi->bmiColors[1].rgbRed = 0x0;
+    pbmi->bmiColors[1].rgbGreen = 0x0;
+    pbmi->bmiColors[1].rgbBlue = 0x0;
+
+    SetDIBitsToDevice(memdc, 0, 0, 10, 10, 0, 0, 0, 10, bits, pbmi, DIB_RGB_COLORS);
+    ok(ds_bits[0] == 0x55, "out_bits %02x\n", ds_bits[0]);
+
+    /*
+     * Take that 'normal' dibsection and change its colour table to an 'inverted' one
+     */
+
+    pbmi->bmiColors[0].rgbRed = 0xff;
+    pbmi->bmiColors[0].rgbGreen = 0xff;
+    pbmi->bmiColors[0].rgbBlue = 0xff;
+    pbmi->bmiColors[1].rgbRed = 0x0;
+    pbmi->bmiColors[1].rgbGreen = 0x0;
+    pbmi->bmiColors[1].rgbBlue = 0x0;
+    num = SetDIBColorTable(memdc, 0, 2, pbmi->bmiColors);
+    ok(num == 2, "num = %d\n", num);
+
+    /* black border, white interior */
+    Rectangle(memdc, 0, 0, 10, 10);
+todo_wine {
+    ok(ds_bits[0] == 0xff, "out_bits %02x\n", ds_bits[0]);
+    ok(ds_bits[4] == 0x80, "out_bits %02x\n", ds_bits[4]);
+ }
+    /* SetDIBitsToDevice with an inverted bmi -> inverted dib section */
+
+    memset(bits, 0, sizeof(bits));
+    bits[0] = 0xaa;
+
+    SetDIBitsToDevice(memdc, 0, 0, 10, 10, 0, 0, 0, 10, bits, pbmi, DIB_RGB_COLORS);
+    ok(ds_bits[0] == 0xaa, "out_bits %02x\n", ds_bits[0]);
+
+    /* SetDIBitsToDevice with a normal bmi -> inverted dib section */
+
+    pbmi->bmiColors[0].rgbRed = 0x0;
+    pbmi->bmiColors[0].rgbGreen = 0x0;
+    pbmi->bmiColors[0].rgbBlue = 0x0;
+    pbmi->bmiColors[1].rgbRed = 0xff;
+    pbmi->bmiColors[1].rgbGreen = 0xff;
+    pbmi->bmiColors[1].rgbBlue = 0xff;
+
+    SetDIBitsToDevice(memdc, 0, 0, 10, 10, 0, 0, 0, 10, bits, pbmi, DIB_RGB_COLORS);
+    ok(ds_bits[0] == 0x55, "out_bits %02x\n", ds_bits[0]);
+
+    SelectObject(memdc, old_bm);
+    DeleteObject(mono_ds);
+
+    /*
+     * Now a dib section with a strange colour map just for fun.  This behaves just like an inverted one.
+     */
+    pbmi->bmiColors[0].rgbRed = 0xff;
+    pbmi->bmiColors[0].rgbGreen = 0x0;
+    pbmi->bmiColors[0].rgbBlue = 0x0;
+    pbmi->bmiColors[1].rgbRed = 0xfe;
+    pbmi->bmiColors[1].rgbGreen = 0x0;
+    pbmi->bmiColors[1].rgbBlue = 0x0;
+
+    mono_ds = CreateDIBSection(hdc, pbmi, DIB_RGB_COLORS, (void**)&ds_bits, NULL, 0);
+    ok(mono_ds != NULL, "CreateDIBSection rets NULL\n");
+    old_bm = SelectObject(memdc, mono_ds);
+
+    /* black border, white interior */
+    Rectangle(memdc, 0, 0, 10, 10);
+    ok(ds_bits[0] == 0xff, "out_bits %02x\n", ds_bits[0]);
+    ok(ds_bits[4] == 0x80, "out_bits %02x\n", ds_bits[4]);
+
+    /* SetDIBitsToDevice with a normal bmi -> inverted dib section */
+
+    pbmi->bmiColors[0].rgbRed = 0x0;
+    pbmi->bmiColors[0].rgbGreen = 0x0;
+    pbmi->bmiColors[0].rgbBlue = 0x0;
+    pbmi->bmiColors[1].rgbRed = 0xff;
+    pbmi->bmiColors[1].rgbGreen = 0xff;
+    pbmi->bmiColors[1].rgbBlue = 0xff;
+
+    SetDIBitsToDevice(memdc, 0, 0, 10, 10, 0, 0, 0, 10, bits, pbmi, DIB_RGB_COLORS);
+    ok(ds_bits[0] == 0x55, "out_bits %02x\n", ds_bits[0]);
+
+    /* SetDIBitsToDevice with a inverted bmi -> inverted dib section */
+
+    pbmi->bmiColors[0].rgbRed = 0xff;
+    pbmi->bmiColors[0].rgbGreen = 0xff;
+    pbmi->bmiColors[0].rgbBlue = 0xff;
+    pbmi->bmiColors[1].rgbRed = 0x0;
+    pbmi->bmiColors[1].rgbGreen = 0x0;
+    pbmi->bmiColors[1].rgbBlue = 0x0;
+
+    SetDIBitsToDevice(memdc, 0, 0, 10, 10, 0, 0, 0, 10, bits, pbmi, DIB_RGB_COLORS);
+    ok(ds_bits[0] == 0xaa, "out_bits %02x\n", ds_bits[0]);
+
+    SelectObject(memdc, old_bm);
+    DeleteObject(mono_ds);
+
+    DeleteDC(memdc);
+    ReleaseDC(0, hdc);
+}
+
+static void test_bitmap(void)
+{
+    char buf[256], buf_cmp[256];
+    HBITMAP hbmp, hbmp_old;
+    HDC hdc;
+    BITMAP bm;
+    INT ret;
+
+    hdc = CreateCompatibleDC(0);
+    assert(hdc != 0);
+
+    hbmp = CreateBitmap(15, 15, 1, 1, NULL);
+    assert(hbmp != NULL);
+
+    ret = GetObject(hbmp, sizeof(bm), &bm);
+    ok(ret == sizeof(bm), "wrong size %d\n", ret);
+
+    ok(bm.bmType == 0, "wrong bm.bmType %d\n", bm.bmType);
+    ok(bm.bmWidth == 15, "wrong bm.bmWidth %d\n", bm.bmWidth);
+    ok(bm.bmHeight == 15, "wrong bm.bmHeight %d\n", bm.bmHeight);
+    ok(bm.bmWidthBytes == 2, "wrong bm.bmWidthBytes %d\n", bm.bmWidthBytes);
+    ok(bm.bmPlanes == 1, "wrong bm.bmPlanes %d\n", bm.bmPlanes);
+    ok(bm.bmBitsPixel == 1, "wrong bm.bmBitsPixel %d\n", bm.bmBitsPixel);
+    ok(bm.bmBits == NULL, "wrong bm.bmBits %p\n", bm.bmBits);
+
+    assert(sizeof(buf) >= bm.bmWidthBytes * bm.bmHeight);
+    assert(sizeof(buf) == sizeof(buf_cmp));
+
+    ret = GetBitmapBits(hbmp, 0, NULL);
+    ok(ret == bm.bmWidthBytes * bm.bmHeight, "%d != %d\n", ret, bm.bmWidthBytes * bm.bmHeight);
+
+    memset(buf_cmp, 0xAA, sizeof(buf_cmp));
+    memset(buf_cmp, 0, bm.bmWidthBytes * bm.bmHeight);
+
+    memset(buf, 0xAA, sizeof(buf));
+    ret = GetBitmapBits(hbmp, sizeof(buf), buf);
+    ok(ret == bm.bmWidthBytes * bm.bmHeight, "%d != %d\n", ret, bm.bmWidthBytes * bm.bmHeight);
+    ok(!memcmp(buf, buf_cmp, sizeof(buf)), "buffers do not match\n");
+
+    hbmp_old = SelectObject(hdc, hbmp);
+
+    ret = GetObject(hbmp, sizeof(bm), &bm);
+    ok(ret == sizeof(bm), "wrong size %d\n", ret);
+
+    ok(bm.bmType == 0, "wrong bm.bmType %d\n", bm.bmType);
+    ok(bm.bmWidth == 15, "wrong bm.bmWidth %d\n", bm.bmWidth);
+    ok(bm.bmHeight == 15, "wrong bm.bmHeight %d\n", bm.bmHeight);
+    ok(bm.bmWidthBytes == 2, "wrong bm.bmWidthBytes %d\n", bm.bmWidthBytes);
+    ok(bm.bmPlanes == 1, "wrong bm.bmPlanes %d\n", bm.bmPlanes);
+    ok(bm.bmBitsPixel == 1, "wrong bm.bmBitsPixel %d\n", bm.bmBitsPixel);
+    ok(bm.bmBits == NULL, "wrong bm.bmBits %p\n", bm.bmBits);
+
+    memset(buf, 0xAA, sizeof(buf));
+    ret = GetBitmapBits(hbmp, sizeof(buf), buf);
+    ok(ret == bm.bmWidthBytes * bm.bmHeight, "%d != %d\n", ret, bm.bmWidthBytes * bm.bmHeight);
+    ok(!memcmp(buf, buf_cmp, sizeof(buf)), "buffers do not match\n");
+
+    hbmp_old = SelectObject(hdc, hbmp_old);
+    ok(hbmp_old == hbmp, "wrong old bitmap %p\n", hbmp_old);
+
+    /* test various buffer sizes for GetObject */
+    ret = GetObject(hbmp, sizeof(bm) * 2, &bm);
+    ok(ret == sizeof(bm), "wrong size %d\n", ret);
+
+    ret = GetObject(hbmp, sizeof(bm) / 2, &bm);
+    ok(ret == 0, "%d != 0\n", ret);
+
+    ret = GetObject(hbmp, 0, &bm);
+    ok(ret == 0, "%d != 0\n", ret);
+
+    ret = GetObject(hbmp, 1, &bm);
+    ok(ret == 0, "%d != 0\n", ret);
+
+    DeleteObject(hbmp);
+    DeleteDC(hdc);
+}
+
+static void test_bmBits(void)
+{
+    BYTE bits[4];
+    HBITMAP hbmp;
+    BITMAP bmp;
+
+    memset(bits, 0, sizeof(bits));
+    hbmp = CreateBitmap(2, 2, 1, 4, bits);
+    ok(hbmp != NULL, "CreateBitmap failed\n");
+
+    memset(&bmp, 0xFF, sizeof(bmp));
+    ok(GetObject(hbmp, sizeof(bmp), &bmp) == sizeof(bmp),
+       "GetObject failed or returned a wrong structure size\n");
+    ok(!bmp.bmBits, "bmBits must be NULL for device-dependent bitmaps\n");
+
+    DeleteObject(hbmp);
+}
+
+static void test_GetDIBits_selected_DIB(UINT bpp)
+{
+    HBITMAP dib;
+    BITMAPINFO * info;
+    BITMAPINFO * info2;
+    void * bits;
+    void * bits2;
+    UINT dib_size;
+    HDC dib_dc, dc;
+    HBITMAP old_bmp;
+    BOOL equalContents;
+    UINT i;
+    int res;
+
+    /* Create a DIB section with a color table */
+
+    info  = (BITMAPINFO *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + (1 << bpp) * sizeof(RGBQUAD));
+    info2 = (BITMAPINFO *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + (1 << bpp) * sizeof(RGBQUAD));
+    assert(info);
+    assert(info2);
+
+    info->bmiHeader.biSize = sizeof(info->bmiHeader);
+
+    /* Choose width and height such that the row length (in bytes)
+       is a multiple of 4 (makes things easier) */
+    info->bmiHeader.biWidth = 32;
+    info->bmiHeader.biHeight = 32;
+    info->bmiHeader.biPlanes = 1;
+    info->bmiHeader.biBitCount = bpp;
+    info->bmiHeader.biCompression = BI_RGB;
+
+    for (i=0; i < (1 << bpp); i++)
+    {
+        BYTE c = i * (1 << (8 - bpp));
+        info->bmiColors[i].rgbRed = c;
+        info->bmiColors[i].rgbGreen = c;
+        info->bmiColors[i].rgbBlue = c;
+        info->bmiColors[i].rgbReserved = 0;
+    }
+
+    dib = CreateDIBSection(NULL, info, DIB_RGB_COLORS, &bits, NULL, 0);
+    assert(dib);
+    dib_size = bpp * (info->bmiHeader.biWidth * info->bmiHeader.biHeight) / 8;
+
+    /* Set the bits of the DIB section */
+    for (i=0; i < dib_size; i++)
+    {
+        ((BYTE *)bits)[i] = i % 256;
+    }
+
+    /* Select the DIB into a DC */
+    dib_dc = CreateCompatibleDC(NULL);
+    old_bmp = (HBITMAP) SelectObject(dib_dc, dib);
+    dc = CreateCompatibleDC(NULL);
+    bits2 = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dib_size);
+    assert(bits2);
+
+    /* Copy the DIB attributes but not the color table */
+    memcpy(info2, info, sizeof(BITMAPINFOHEADER));
+
+    res = GetDIBits(dc, dib, 0, info->bmiHeader.biHeight, bits2, info2, DIB_RGB_COLORS);
+    ok(res, "GetDIBits failed\n");
+
+    /* Compare the color table and the bits */
+    equalContents = TRUE;
+    for (i=0; i < (1 << bpp); i++)
+    {
+        if ((info->bmiColors[i].rgbRed != info2->bmiColors[i].rgbRed)
+            || (info->bmiColors[i].rgbGreen != info2->bmiColors[i].rgbGreen)
+            || (info->bmiColors[i].rgbBlue != info2->bmiColors[i].rgbBlue)
+            || (info->bmiColors[i].rgbReserved != info2->bmiColors[i].rgbReserved))
+        {
+            equalContents = FALSE;
+            break;
+        }
+    }
+    todo_wine
+    {
+        ok(equalContents, "GetDIBits with DIB selected in DC: Invalid DIB color table\n");
+    }
+
+    equalContents = TRUE;
+    for (i=0; i < dib_size / sizeof(DWORD); i++)
+    {
+        if (((DWORD *)bits)[i] != ((DWORD *)bits2)[i])
+        {
+            equalContents = FALSE;
+            break;
+        }
+    }
+    todo_wine
+    {
+        ok(equalContents, "GetDIBits with DIB selected in DC: Invalid DIB bits\n");
+    }
+
+    HeapFree(GetProcessHeap(), 0, bits2);
+    DeleteDC(dc);
+
+    SelectObject(dib_dc, old_bmp);
+    DeleteDC(dib_dc);
+    DeleteObject(dib);
+
+    HeapFree(GetProcessHeap(), 0, info2);
+    HeapFree(GetProcessHeap(), 0, info);
+}
+
+static void test_GetDIBits_selected_DDB(BOOL monochrome)
+{
+    HBITMAP ddb;
+    BITMAPINFO * info;
+    BITMAPINFO * info2;
+    void * bits;
+    void * bits2;
+    HDC ddb_dc, dc;
+    HBITMAP old_bmp;
+    BOOL equalContents;
+    UINT width, height;
+    UINT bpp;
+    UINT i, j;
+    int res;
+
+    width = height = 16;
+
+    /* Create a DDB (device-dependent bitmap) */
+    if (monochrome)
+    {
+        bpp = 1;
+        ddb = CreateBitmap(width, height, 1, 1, NULL);
+    }
+    else
+    {
+        HDC screen_dc = GetDC(NULL);
+        bpp = GetDeviceCaps(screen_dc, BITSPIXEL) * GetDeviceCaps(screen_dc, PLANES);
+        ddb = CreateCompatibleBitmap(screen_dc, width, height);
+        ReleaseDC(NULL, screen_dc);
+    }
+
+    /* Set the pixels */
+    ddb_dc = CreateCompatibleDC(NULL);
+    old_bmp = (HBITMAP) SelectObject(ddb_dc, ddb);
+    for (i = 0; i < width; i++)
+    {
+        for (j=0; j < height; j++)
+        {
+            BYTE c = (i * width + j) % 256;
+            SetPixelV(ddb_dc, i, j, RGB(c, c, c));
+        }
+    }
+    SelectObject(ddb_dc, old_bmp);
+
+    info  = (BITMAPINFO *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
+    info2 = (BITMAPINFO *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
+    assert(info);
+    assert(info2);
+
+    info->bmiHeader.biSize = sizeof(info->bmiHeader);
+    info->bmiHeader.biWidth = width;
+    info->bmiHeader.biHeight = height;
+    info->bmiHeader.biPlanes = 1;
+    info->bmiHeader.biBitCount = bpp;
+    info->bmiHeader.biCompression = BI_RGB;
+
+    dc = CreateCompatibleDC(NULL);
+
+    /* Fill in biSizeImage */
+    GetDIBits(dc, ddb, 0, height, NULL, info, DIB_RGB_COLORS);
+    ok(info->bmiHeader.biSizeImage != 0, "GetDIBits failed to get the DIB attributes\n");
+
+    bits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, info->bmiHeader.biSizeImage);
+    bits2 = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, info->bmiHeader.biSizeImage);
+    assert(bits);
+    assert(bits2);
+
+    /* Get the bits */
+    res = GetDIBits(dc, ddb, 0, height, bits, info, DIB_RGB_COLORS);
+    ok(res, "GetDIBits failed\n");
+
+    /* Copy the DIB attributes but not the color table */
+    memcpy(info2, info, sizeof(BITMAPINFOHEADER));
+
+    /* Select the DDB into another DC */
+    old_bmp = (HBITMAP) SelectObject(ddb_dc, ddb);
+
+    /* Get the bits */
+    res = GetDIBits(dc, ddb, 0, height, bits2, info2, DIB_RGB_COLORS);
+    ok(res, "GetDIBits failed\n");
+
+    /* Compare the color table and the bits */
+    if (bpp <= 8)
+    {
+        equalContents = TRUE;
+        for (i=0; i < (1 << bpp); i++)
+        {
+            if ((info->bmiColors[i].rgbRed != info2->bmiColors[i].rgbRed)
+                || (info->bmiColors[i].rgbGreen != info2->bmiColors[i].rgbGreen)
+                || (info->bmiColors[i].rgbBlue != info2->bmiColors[i].rgbBlue)
+                || (info->bmiColors[i].rgbReserved != info2->bmiColors[i].rgbReserved))
+            {
+                equalContents = FALSE;
+                break;
+            }
+        }
+        ok(equalContents, "GetDIBits with DDB selected in DC: Got a different color table\n");
+    }
+
+    equalContents = TRUE;
+    for (i=0; i < info->bmiHeader.biSizeImage / sizeof(DWORD); i++)
+    {
+        if (((DWORD *)bits)[i] != ((DWORD *)bits2)[i])
+        {
+            equalContents = FALSE;
+        }
+    }
+    ok(equalContents, "GetDIBits with DDB selected in DC: Got different DIB bits\n");
+
+    HeapFree(GetProcessHeap(), 0, bits2);
+    HeapFree(GetProcessHeap(), 0, bits);
+    DeleteDC(dc);
+
+    SelectObject(ddb_dc, old_bmp);
+    DeleteDC(ddb_dc);
+    DeleteObject(ddb);
+
+    HeapFree(GetProcessHeap(), 0, info2);
+    HeapFree(GetProcessHeap(), 0, info);
+}
+
+START_TEST(bitmap)
+{
+    is_win9x = GetWindowLongPtrW(GetDesktopWindow(), GWLP_WNDPROC) == 0;
+
+    test_createdibitmap();
+    test_dibsections();
+    test_mono_dibsection();
+    test_bitmap();
+    test_bmBits();
+    test_GetDIBits_selected_DIB(1);
+    test_GetDIBits_selected_DIB(4);
+    test_GetDIBits_selected_DIB(8);
+    test_GetDIBits_selected_DDB(TRUE);
+    test_GetDIBits_selected_DDB(FALSE);
+}
diff --git a/rostests/winetests/gdi32/brush.c b/rostests/winetests/gdi32/brush.c
new file mode 100755 (executable)
index 0000000..c2aee7c
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Unit test suite for brushes
+ *
+ * Copyright 2004 Kevin Koltzau
+ *
+ * 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 "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+
+#include "wine/test.h"
+
+typedef struct _STOCK_BRUSH {
+    COLORREF color;
+    int stockobj;
+    const char *name;
+} STOCK_BRUSH;
+
+static void test_solidbrush(void)
+{
+    static const STOCK_BRUSH stock[] = {
+        {RGB(255,255,255), WHITE_BRUSH, "white"},
+        {RGB(192,192,192), LTGRAY_BRUSH, "ltgray"},
+        {RGB(128,128,128), GRAY_BRUSH, "gray"},
+        {RGB(0,0,0), BLACK_BRUSH, "black"},
+        {RGB(0,0,255), -1, "blue"}
+    };
+    HBRUSH solidBrush;
+    HBRUSH stockBrush;
+    LOGBRUSH br;
+    size_t i;
+    INT ret;
+
+    for(i=0; i<sizeof(stock)/sizeof(stock[0]); i++) {
+        solidBrush = CreateSolidBrush(stock[i].color);
+        
+        if(stock[i].stockobj != -1) {
+            stockBrush = (HBRUSH)GetStockObject(stock[i].stockobj);
+            ok(stockBrush!=solidBrush, "Stock %s brush equals solid %s brush\n", stock[i].name, stock[i].name);
+        }
+        else
+            stockBrush = NULL;
+        memset(&br, 0, sizeof(br));
+        ret = GetObject(solidBrush, sizeof(br), &br);
+        ok( ret !=0, "GetObject on solid %s brush failed, error=%ld\n", stock[i].name, GetLastError());
+        ok(br.lbStyle==BS_SOLID, "%s brush has wrong style, got %d expected %d\n", stock[i].name, br.lbStyle, BS_SOLID);
+        ok(br.lbColor==stock[i].color, "%s brush has wrong color, got 0x%08lx expected 0x%08lx\n", stock[i].name, br.lbColor, stock[i].color);
+        
+        if(stockBrush) {
+            /* Sanity check, make sure the colors being compared do in fact have a stock brush */
+            ret = GetObject(stockBrush, sizeof(br), &br);
+            ok( ret !=0, "GetObject on stock %s brush failed, error=%ld\n", stock[i].name, GetLastError());
+            ok(br.lbColor==stock[i].color, "stock %s brush unexpected color, got 0x%08lx expected 0x%08lx\n", stock[i].name, br.lbColor, stock[i].color);
+        }
+
+        DeleteObject(solidBrush);
+        ok(GetObject(solidBrush, sizeof(br), &br)==0, "GetObject succeeded on a deleted %s brush\n", stock[i].name);
+    }
+}
+START_TEST(brush)
+{
+    test_solidbrush();
+}
diff --git a/rostests/winetests/gdi32/clipping.c b/rostests/winetests/gdi32/clipping.c
new file mode 100644 (file)
index 0000000..079fbcc
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * Unit test suite for clipping
+ *
+ * Copyright 2005 Huw Davies
+ *
+ * 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 "wine/test.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+
+static void test_GetRandomRgn(void)
+{
+    HWND hwnd = CreateWindowExA(0,"BUTTON","test",WS_VISIBLE|WS_POPUP,0,0,100,100,GetDesktopWindow(),0,0,0);
+    HDC hdc;
+    HRGN hrgn = CreateRectRgn(0, 0, 0, 0);
+    int ret;
+    RECT rc, rc2;
+    RECT ret_rc, window_rc;
+
+    ok( hwnd != 0, "CreateWindow failed\n" );
+
+    SetRect(&window_rc, 400, 300, 500, 400);
+    MoveWindow(hwnd, window_rc.left, window_rc.top, window_rc.right - window_rc.left, window_rc.bottom - window_rc.top, FALSE);
+    hdc = GetDC(hwnd);
+
+    ret = GetRandomRgn(hdc, hrgn, 1);
+    ok(ret == 0, "GetRandomRgn rets %d\n", ret);
+    ret = GetRandomRgn(hdc, hrgn, 2);
+    ok(ret == 0, "GetRandomRgn rets %d\n", ret);
+    ret = GetRandomRgn(hdc, hrgn, 3);
+    ok(ret == 0, "GetRandomRgn rets %d\n", ret);
+
+    /* Set a clip region */
+    SetRect(&rc, 20, 20, 80, 80);
+    IntersectClipRect(hdc, rc.left, rc.top, rc.right, rc.bottom);
+
+    ret = GetRandomRgn(hdc, hrgn, 1);
+    ok(ret != 0, "GetRandomRgn rets %d\n", ret);
+    GetRgnBox(hrgn, &ret_rc);
+    ok(EqualRect(&rc, &ret_rc), "GetRandomRgn %ld,%ld - %ld,%ld\n",
+       ret_rc.left, ret_rc.top, ret_rc.right, ret_rc.bottom);
+    ret = GetRandomRgn(hdc, hrgn, 2);
+    ok(ret == 0, "GetRandomRgn rets %d\n", ret);
+
+    ret = GetRandomRgn(hdc, hrgn, 3);
+    ok(ret != 0, "GetRandomRgn rets %d\n", ret);
+    GetRgnBox(hrgn, &ret_rc);
+    ok(EqualRect(&rc, &ret_rc), "GetRandomRgn %ld,%ld - %ld,%ld\n",
+       ret_rc.left, ret_rc.top, ret_rc.right, ret_rc.bottom);
+
+    /* Move the clip to the meta and clear the clip */
+    SetMetaRgn(hdc);
+
+    ret = GetRandomRgn(hdc, hrgn, 1);
+    ok(ret == 0, "GetRandomRgn rets %d\n", ret);
+    ret = GetRandomRgn(hdc, hrgn, 2);
+    ok(ret != 0, "GetRandomRgn rets %d\n", ret);
+    GetRgnBox(hrgn, &ret_rc);
+    ok(EqualRect(&rc, &ret_rc), "GetRandomRgn %ld,%ld - %ld,%ld\n",
+       ret_rc.left, ret_rc.top, ret_rc.right, ret_rc.bottom);
+
+    ret = GetRandomRgn(hdc, hrgn, 3);
+    ok(ret != 0, "GetRandomRgn rets %d\n", ret);
+    GetRgnBox(hrgn, &ret_rc);
+    ok(EqualRect(&rc, &ret_rc), "GetRandomRgn %ld,%ld - %ld,%ld\n",
+       ret_rc.left, ret_rc.top, ret_rc.right, ret_rc.bottom);
+
+    /* Set a new clip (still got the meta) */
+    SetRect(&rc2, 10, 30, 70, 90);
+    IntersectClipRect(hdc, rc2.left, rc2.top, rc2.right, rc2.bottom);
+
+    ret = GetRandomRgn(hdc, hrgn, 1);
+    ok(ret != 0, "GetRandomRgn rets %d\n", ret);
+    GetRgnBox(hrgn, &ret_rc);
+    ok(EqualRect(&rc2, &ret_rc), "GetRandomRgn %ld,%ld - %ld,%ld\n",
+       ret_rc.left, ret_rc.top, ret_rc.right, ret_rc.bottom);
+
+    ret = GetRandomRgn(hdc, hrgn, 2);
+    ok(ret != 0, "GetRandomRgn rets %d\n", ret);
+    GetRgnBox(hrgn, &ret_rc);
+    ok(EqualRect(&rc, &ret_rc), "GetRandomRgn %ld,%ld - %ld,%ld\n",
+       ret_rc.left, ret_rc.top, ret_rc.right, ret_rc.bottom);
+    IntersectRect(&rc2, &rc, &rc2);
+
+    ret = GetRandomRgn(hdc, hrgn, 3);
+    ok(ret != 0, "GetRandomRgn rets %d\n", ret);
+    GetRgnBox(hrgn, &ret_rc);
+    ok(EqualRect(&rc2, &ret_rc), "GetRandomRgn %ld,%ld - %ld,%ld\n",
+       ret_rc.left, ret_rc.top, ret_rc.right, ret_rc.bottom);
+
+
+    ret = GetRandomRgn(hdc, hrgn, SYSRGN);
+    ok(ret != 0, "GetRandomRgn rets %d\n", ret);
+    GetRgnBox(hrgn, &ret_rc);
+    if(GetVersion() & 0x80000000)
+        OffsetRect(&window_rc, -window_rc.left, -window_rc.top);
+    ok(EqualRect(&window_rc, &ret_rc), "GetRandomRgn %ld,%ld - %ld,%ld\n",
+       ret_rc.left, ret_rc.top, ret_rc.right, ret_rc.bottom);
+
+    DeleteObject(hrgn);
+    ReleaseDC(hwnd, hdc);
+    DestroyWindow(hwnd);
+}
+
+START_TEST(clipping)
+{
+    test_GetRandomRgn();
+}
diff --git a/rostests/winetests/gdi32/dc.c b/rostests/winetests/gdi32/dc.c
new file mode 100644 (file)
index 0000000..5b50632
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * Unit tests for dc functions
+ *
+ * Copyright (c) 2005 Huw Davies
+ * Copyright (c) 2005 Dmitry Timoshkov
+ *
+ * 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 <assert.h>
+#include <stdio.h>
+
+#include "wine/test.h"
+#include "winbase.h"
+#include "wingdi.h"