<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
--- /dev/null
+<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
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+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
--- /dev/null
+<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>
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+<module name="rtshared" type="staticlibrary">
+ <include base="rtshared">.</include>
+ <define name="__USE_W32API" />
+ <file>regtests.c</file>
+</module>
--- /dev/null
+<?xml version="1.0"?>
+<!DOCTYPE project SYSTEM "tools/rbuild/project.dtd">
+<group>
+<directory name="queuetest">
+ <xi:include href="queuetest/queuetest.rbuild" />
+</directory>
+</group>
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+<module name="queuetest" type="win32cui" installbase="system32" installname="queuetest.exe" allowwarnings="true">
+ <define name="__USE_W32API" />
+ <library>kernel32</library>
+ <file>queuetest.c</file>
+</module>
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+<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>
<?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>
--- /dev/null
+<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>
--- /dev/null
+/*
+ * 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, ¬Null, 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, ¬Null, 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, ¬Null, 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, ¬Null, 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();
+}
--- /dev/null
+/*
+ * 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 );
+}
--- /dev/null
+/*
+ * 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();
+}
--- /dev/null
+/*
+ * 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();
+}
--- /dev/null
+/*
+ * 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();
+}
--- /dev/null
+/*
+ * 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 );
+}
--- /dev/null
+/*
+ * 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();
+}
--- /dev/null
+/* 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 }
+};
--- /dev/null
+<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>
--- /dev/null
+/*
+ * 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();
+}
--- /dev/null
+#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 }
+};
--- /dev/null
+/* 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();
+}
--- /dev/null
+<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>
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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();
+}
--- /dev/null
+/*
+ * 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();
+}
--- /dev/null
+/*
+ * 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();
+}
--- /dev/null
+/*
+ * 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();
+}
--- /dev/null
+/* 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();
+}
--- /dev/null
+/* 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();
+}
--- /dev/null
+/* 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
+}
--- /dev/null
+/* 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();
+}
--- /dev/null
+/* 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);
+}
--- /dev/null
+#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 }
+};
--- /dev/null
+/* 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);
+ }
+}
--- /dev/null
+/*
+ * 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();
+}
--- /dev/null
+/* 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);
+ }
+}
--- /dev/null
+/* 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();
+}
--- /dev/null
+<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>
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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();
+}
--- /dev/null
+/*
+ * 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();
+}
--- /dev/null
+/*
+ * 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"