I've tested this on XP, but I would like to get somebody to test on 9x and
maybe even vista please and thank you. These tests are the prelude to
cursoricon patches including Griswold's animated cursors & themed cursors and
my fixes for LOTRO (mostly handling invalid calls properly).
Thanks,
Daniel
From acbbfdee105878c1f5f78293a1082e5bce908682 Mon Sep 17 00:00:00 2001
From: Daniel Santos <[email protected]>
Date: Mon, 8 Jun 2009 15:51:40 -0500
Subject: user32/tests: Add more intensive tests for SetCursor.
---
dlls/user32/tests/cursoricon.c | 166 +++++++++++++++++++++++++++++++++++-----
1 files changed, 145 insertions(+), 21 deletions(-)
diff --git a/dlls/user32/tests/cursoricon.c b/dlls/user32/tests/cursoricon.c
index 9475534..ea968fa 100644
--- a/dlls/user32/tests/cursoricon.c
+++ b/dlls/user32/tests/cursoricon.c
@@ -64,6 +64,14 @@ static HANDLE child_process;
#define PROC_INIT (WM_USER+1)
+#define __STRIZE2(x) #x
+#define __STRIZE(x) __STRIZE2(x)
+#define __FILE_SPOT __FILE__ ":" __STRIZE(__LINE__)
+
+inline static int is_win9x() {
+ return GetVersion() & 0x80000000;
+}
+
static LRESULT CALLBACK callback_child(HWND hwnd, UINT msg, WPARAM wParam,
LPARAM lParam)
{
BOOL ret;
@@ -76,10 +84,11 @@ static LRESULT CALLBACK callback_child(HWND hwnd, UINT msg,
WPARAM wParam, LPARA
SetLastError(0xdeadbeef);
ret = DestroyCursor((HCURSOR) lParam);
error = GetLastError();
- todo_wine ok(!ret || broken(ret) /* win9x */, "DestroyCursor on
the active cursor succeeded.\n");
+ todo_wine ok(!ret || broken(is_win9x() && ret), /* win9x */
+ "DestroyCursor on the active cursor succeeded.\n");
ok(error == ERROR_DESTROY_OBJECT_OF_OTHER_THREAD ||
- error == 0xdeadbeef, /* vista */
- "Last error: %u\n", error);
+ error == 0xdeadbeef, /* vista */
+ "Last error: %u\n", error);
return TRUE;
case WM_DESTROY:
PostQuitMessage(0);
@@ -768,9 +777,94 @@ static void test_LoadImageFile(const unsigned char *
image_data,
DeleteFileA(filename);
}
+/*************************************************************************
+ * test_SetCursor
+ *
+ * Encapsulates tests to SetCursor() function.
+ *
+ * PARAMS
+ * target [I] A handle to use when calling SetCursor
+ * shouldFail [I] Rather of not it should fail
+ * filespot [I] The file:line location this function was called from.
+ * retValTodo [I] True if return value is broken in wine (wine's return value
+ * is broken in some, but not all cases)
+ *
+ * RETURNS
+ * The return value of the SetCursor() call.
+ */
+static HCURSOR test_SetCursor(HANDLE hNewCursor, BOOL shouldFail,
+ const char *filespot, BOOL retValTodo)
+{
+ HCURSOR cursor1, cursor2, cursor3;
+ DWORD error;
+
+ /* GetCursor should have no errors */
+ SetLastError(0xdeadbeef);
+ cursor1 = GetCursor();
+ error = GetLastError();
+ ok(error == 0xdeadbeef, "(Called from %s) GetCursor() changed last error: "
+ "%u.\n",
+ filespot, error);
+
+ /* Call SetCursor on supplied handle */
+ SetLastError(0xdeadbeef);
+ cursor2 = SetCursor(hNewCursor);
+ error = GetLastError();
+ cursor3 = GetCursor();
+
+ if (shouldFail) {
+ todo_wine ok(error == ERROR_INVALID_CURSOR_HANDLE,
+ "(Called from %s) Last error is %u (0x%08x), expected "
+ "ERROR_INVALID_CURSOR_HANDLE (%u).\n",
+ filespot, error, error, ERROR_INVALID_CURSOR_HANDLE);
+
+ if(retValTodo) {
+ todo_wine ok(!cursor2,
+ "(Called from %s) SetCursor() returned non-zero (%p).\n",
+ filespot, cursor2);
+ } else {
+ ok(!cursor2,
+ "(Called from %s) SetCursor() returned non-zero (%p).\n",
+ filespot, cursor2);
+ }
+
+ todo_wine ok(cursor1 == cursor3,
+ "(Called from %s) SetCursor() changed cursor.\n",
+ filespot);
+ } else {
+ todo_wine ok(error == 0xdeadbeef,
+ "(Called from %s) Last error is %u (0x%08x), expected "
+ "0xdeadbeef.\n",
+ filespot, error, error);
+
+ /* WinXP: For some reason, SetCursor() is returning NULL when
hNewCursor
+ * is NULL. Is it this way on other versions? MSDN says it should
+ * return the old cursor.
+ */
+ if(hNewCursor) {
+ ok(cursor1 == cursor2,
+ "(Called from %s) SetCursor() did not return the previous "
+ "cursor. Expected %p, got %p.\n",
+ filespot, cursor1, cursor2);
+ } else {
+ todo_wine ok(!cursor2,
+ "(Called from %s) SetCursor() returned %p, expected
NULL\n",
+ filespot, cursor2);
+ }
+
+ ok(cursor3 == hNewCursor,
+ "(Called from %s) GetCursor() did not return the value we "
+ "previously passed to SetCursor(). Expected %p, got %p.\n",
+ filespot, hNewCursor, cursor3);
+ }
+
+ return cursor2;
+}
+
static void test_LoadImage(void)
{
HANDLE handle;
+ HCURSOR cursor;
BOOL ret;
DWORD error, bytes_written;
CURSORICONFILEDIR *icon_data;
@@ -845,6 +939,12 @@ static void test_LoadImage(void)
ok(icon_info.hbmMask != NULL, "No hbmMask!\n");
}
+ /* Test SetCursor with this icon */
+ cursor = test_SetCursor(handle, FALSE, __FILE_SPOT, TRUE);
+
+ /* Now change it back to the previous cursor */
+ test_SetCursor(cursor, FALSE, __FILE_SPOT, FALSE);
+
/* Clean up. */
SetLastError(0xdeadbeef);
ret = DestroyCursor(handle);
@@ -855,6 +955,10 @@ static void test_LoadImage(void)
HeapFree(GetProcessHeap(), 0, icon_data);
DeleteFileA("icon.ico");
+ /* Test passing invalid handles to SetCursor. */
+ test_SetCursor(handle, TRUE, __FILE_SPOT, FALSE);
+ test_SetCursor(GetCurrentThread(), TRUE, __FILE_SPOT, TRUE);
+
test_LoadImageFile(bmpimage, sizeof(bmpimage), "bmp", 1);
test_LoadImageFile(gifimage, sizeof(gifimage), "gif", 0);
test_LoadImageFile(gif4pixel, sizeof(gif4pixel), "gif", 0);
@@ -981,29 +1085,53 @@ static void test_DestroyCursor(void)
if(!cursor) {
return;
}
- SetCursor(cursor);
+ test_SetCursor(cursor, FALSE, __FILE_SPOT, FALSE);
+
+ /* When you attempt to destroy the current cursor, windows obliges you.
+ * On win9x, it returns TRUE (indicating success) and on NT it returns
+ * FALSE, but neither sets the last error.
+ */
SetLastError(0xdeadbeef);
ret = DestroyCursor(cursor);
- ok(!ret || broken(ret) /* succeeds on win9x */, "DestroyCursor on the
active cursor succeeded\n");
error = GetLastError();
- ok(error == 0xdeadbeef, "Last error: %u\n", error);
+ ok(error == 0xdeadbeef, "Last error: 0x%x.\n", error);
+ ok(!ret || broken(is_win9x() && ret) /* succeeds on win9x */,
+ "DestroyCursor on the active cursor returned TRUE.\n");
+
+ /* QUESTION: This if statment effectively skips these tests on win9x, do we
+ * want to do that? */
if (!ret)
{
cursor2 = GetCursor();
ok(cursor2 == cursor, "Active was set to %p when trying to destroy
it\n", cursor2);
- SetCursor(NULL);
- /* Trying to destroy the cursor properly fails now with
- * ERROR_INVALID_CURSOR_HANDLE. This happens because we called
- * DestroyCursor() 2+ times after calling SetCursor(). The calls to
- * GetCursor() and SetCursor(NULL) in between make no difference. */
+ /* Make sure showing/hiding the invalid cursor still works. */
+ SetLastError(0xdeadbeef);
+ ok(ShowCursor(TRUE) == 1, "Cursor count != 1\n");
+ ok(GetLastError() == 0xdeadbeef, "Last error: 0x%x.\n",
GetLastError());
+
+ SetLastError(0xdeadbeef);
+ ok(ShowCursor(FALSE) == 0, "Cursor count != 0\n");
+ ok(GetLastError() == 0xdeadbeef, "Last error: 0x%x.\n",
GetLastError());
+ test_SetCursor(NULL, FALSE, __FILE_SPOT, FALSE);
+
+ /* Trying to destroy the cursor again fails now with
+ * ERROR_INVALID_CURSOR_HANDLE. This happens because we've previously
+ * called DestroyCursor() on this handle. The calls to GetCursor()
+ * and SetCursor(NULL) in between make no difference. It would appear
+ * that windows doesn't mind having an invalid cursor handle as its
+ * current cursor much the way a comatose person doesn't mind a
+ * stranger in their hospital room.
+ */
+ SetLastError(0xdeadbeef);
ret = DestroyCursor(cursor);
todo_wine {
ok(!ret, "DestroyCursor succeeded.\n");
error = GetLastError();
- ok(error == ERROR_INVALID_CURSOR_HANDLE || error == 0xdeadbeef, /*
vista */
- "Last error: 0x%08x\n", error);
+ ok(error == ERROR_INVALID_CURSOR_HANDLE
+ || broken(error == 0xdeadbeef), /* vista */
+ "Last error: 0x%08x\n", error);
}
}
@@ -1015,17 +1143,13 @@ static void test_DestroyCursor(void)
SetLastError(0xdeadbeef);
ret = DestroyCursor(cursor);
- ok(ret || broken(!ret) /* fails on win9x */, "DestroyCursor on the active
cursor failed.\n");
error = GetLastError();
- ok(error == 0xdeadbeef, "Last error: 0x%08x\n", error);
+ ok(error == 0xdeadbeef, "Last error: 0x%x.\n", error);
+ ok(ret || broken(is_win9x() && !ret) /* fails on win9x */,
+ "DestroyCursor on OEM cursor failed.\n");
/* Try setting the cursor to a destroyed OEM cursor. */
- SetLastError(0xdeadbeef);
- SetCursor(cursor);
- error = GetLastError();
- todo_wine {
- ok(error == 0xdeadbeef, "Last error: 0x%08x\n", error);
- }
+ test_SetCursor(cursor, FALSE, __FILE_SPOT, FALSE);
/* Check if LoadCursor() returns the same handle with the same icon. */
cursor2 = LoadCursor(NULL, IDC_ARROW);
--
1.6.2.3