[COMCTL32_WINETEST] Sync with Wine Staging 4.0. CORE-15682

This commit is contained in:
Amine Khaldi 2019-01-25 13:16:18 +01:00
parent 07f4be3faf
commit 5f7243b577
26 changed files with 3902 additions and 269 deletions

View file

@ -20,7 +20,9 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifdef __REACTOS__
#undef USE_WINE_TODOS
#endif
#include <windows.h>
#include <commctrl.h>
@ -29,11 +31,18 @@
#include "v6util.h"
#include "msg.h"
#ifdef __REACTOS__
#define BS_PUSHBOX 0x0000000AL
#endif
#define IS_WNDPROC_HANDLE(x) (((ULONG_PTR)(x) >> 16) == (~0u >> 16))
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);
static HIMAGELIST (WINAPI *pImageList_Create)(int, int, UINT, int, int);
static int (WINAPI *pImageList_Add)(HIMAGELIST, HBITMAP, HBITMAP);
static BOOL (WINAPI *pImageList_Destroy)(HIMAGELIST);
/****************** button message test *************************/
#define ID_BUTTON 0x000e
@ -78,6 +87,12 @@ static void init_functions(void)
MAKEFUNC_ORD(RemoveWindowSubclass, 412);
MAKEFUNC_ORD(DefSubclassProc, 413);
#undef MAKEFUNC_ORD
#define X(f) p##f = (void *)GetProcAddress(hmod, #f);
X(ImageList_Create);
X(ImageList_Add);
X(ImageList_Destroy);
#undef X
}
/* try to make sure pending X events have been processed before continuing */
@ -550,15 +565,15 @@ static void test_button_messages(void)
hfont2 = CreateFontIndirectA(&logfont);
ok(hfont2 != NULL, "Failed to create Tahoma font\n");
for (i = 0; i < sizeof(button)/sizeof(button[0]); i++)
for (i = 0; i < ARRAY_SIZE(button); i++)
{
HFONT prevfont, hfont;
MSG msg;
DWORD style, state;
HDC hdc;
trace("%d: button test sequence\n", i);
hwnd = create_button(button[i].style, parent);
ok(hwnd != NULL, "Failed to create a button.\n");
style = GetWindowLongA(hwnd, GWL_STYLE);
style &= ~(WS_CHILD | BS_NOTIFY);
@ -807,6 +822,395 @@ static void test_button_class(void)
DestroyWindow(hwnd);
}
static void test_note(void)
{
HWND hwnd;
BOOL ret;
WCHAR test_w[] = {'t', 'e', 's', 't', 0};
WCHAR tes_w[] = {'t', 'e', 's', 0};
WCHAR deadbeef_w[] = {'d', 'e', 'a', 'd', 'b', 'e', 'e', 'f', 0};
WCHAR buffer_w[10];
DWORD size;
DWORD error;
INT type;
hwnd = create_button(BS_COMMANDLINK, NULL);
ok(hwnd != NULL, "Expect hwnd not null\n");
SetLastError(0xdeadbeef);
size = ARRAY_SIZE(buffer_w);
ret = SendMessageA(hwnd, BCM_GETNOTE, (WPARAM)&size, (LPARAM)buffer_w);
error = GetLastError();
if (!ret && error == 0xdeadbeef)
{
win_skip("BCM_GETNOTE message is unavailable. Skipping note tests\n"); /* xp or 2003 */
DestroyWindow(hwnd);
return;
}
DestroyWindow(hwnd);
for (type = BS_PUSHBUTTON; type <= BS_DEFCOMMANDLINK; type++)
{
if (type == BS_DEFCOMMANDLINK || type == BS_COMMANDLINK)
{
hwnd = create_button(type, NULL);
ok(hwnd != NULL, "Expect hwnd not null\n");
/* Get note when note hasn't been not set yet */
SetLastError(0xdeadbeef);
lstrcpyW(buffer_w, deadbeef_w);
size = ARRAY_SIZE(buffer_w);
ret = SendMessageA(hwnd, BCM_GETNOTE, (WPARAM)&size, (LPARAM)buffer_w);
error = GetLastError();
ok(!ret, "Expect BCM_GETNOTE return false\n");
ok(!lstrcmpW(buffer_w, deadbeef_w), "Expect note: %s, got: %s\n",
wine_dbgstr_w(deadbeef_w), wine_dbgstr_w(buffer_w));
ok(size == ARRAY_SIZE(buffer_w), "Got: %d\n", size);
ok(error == ERROR_INVALID_PARAMETER, "Expect last error: 0x%08x, got: 0x%08x\n",
ERROR_INVALID_PARAMETER, error);
/* Get note length when note is not set */
ret = SendMessageA(hwnd, BCM_GETNOTELENGTH, 0, 0);
ok(ret == 0, "Expect note length: %d, got: %d\n", 0, ret);
/* Successful set note, get note and get note length */
SetLastError(0xdeadbeef);
ret = SendMessageA(hwnd, BCM_SETNOTE, 0, (LPARAM)test_w);
ok(ret, "Expect BCM_SETNOTE return true\n");
error = GetLastError();
ok(error == NO_ERROR, "Expect last error: 0x%08x, got: 0x%08x\n", NO_ERROR, error);
SetLastError(0xdeadbeef);
lstrcpyW(buffer_w, deadbeef_w);
size = ARRAY_SIZE(buffer_w);
ret = SendMessageA(hwnd, BCM_GETNOTE, (WPARAM)&size, (LPARAM)buffer_w);
ok(ret, "Expect BCM_GETNOTE return true\n");
ok(!lstrcmpW(buffer_w, test_w), "Expect note: %s, got: %s\n", wine_dbgstr_w(test_w),
wine_dbgstr_w(buffer_w));
ok(size == ARRAY_SIZE(buffer_w), "Got: %d\n", size);
error = GetLastError();
ok(error == NO_ERROR, "Expect last error: 0x%08x, got: 0x%08x\n", NO_ERROR, error);
ret = SendMessageA(hwnd, BCM_GETNOTELENGTH, 0, 0);
ok(ret == ARRAY_SIZE(test_w) - 1, "Got: %d\n", ret);
/* Insufficient buffer, return partial string */
SetLastError(0xdeadbeef);
lstrcpyW(buffer_w, deadbeef_w);
size = ARRAY_SIZE(test_w) - 1;
ret = SendMessageA(hwnd, BCM_GETNOTE, (WPARAM)&size, (LPARAM)buffer_w);
ok(!ret, "Expect BCM_GETNOTE return false\n");
ok(!lstrcmpW(buffer_w, tes_w), "Expect note: %s, got: %s\n", wine_dbgstr_w(tes_w),
wine_dbgstr_w(buffer_w));
ok(size == ARRAY_SIZE(test_w), "Got: %d\n", size);
error = GetLastError();
ok(error == ERROR_INSUFFICIENT_BUFFER, "Expect last error: 0x%08x, got: 0x%08x\n",
ERROR_INSUFFICIENT_BUFFER, error);
/* Set note with NULL buffer */
SetLastError(0xdeadbeef);
ret = SendMessageA(hwnd, BCM_SETNOTE, 0, 0);
ok(ret, "Expect BCM_SETNOTE return false\n");
error = GetLastError();
ok(error == NO_ERROR, "Expect last error: 0x%08x, got: 0x%08x\n", NO_ERROR, error);
/* Check that set note with NULL buffer make note empty */
SetLastError(0xdeadbeef);
lstrcpyW(buffer_w, deadbeef_w);
size = ARRAY_SIZE(buffer_w);
ret = SendMessageA(hwnd, BCM_GETNOTE, (WPARAM)&size, (LPARAM)buffer_w);
ok(ret, "Expect BCM_GETNOTE return true\n");
ok(lstrlenW(buffer_w) == 0, "Expect note length 0\n");
ok(size == ARRAY_SIZE(buffer_w), "Got: %d\n", size);
error = GetLastError();
ok(error == NO_ERROR, "Expect last error: 0x%08x, got: 0x%08x\n", NO_ERROR, error);
ret = SendMessageA(hwnd, BCM_GETNOTELENGTH, 0, 0);
ok(ret == 0, "Expect note length: %d, got: %d\n", 0, ret);
/* Get note with NULL buffer */
SetLastError(0xdeadbeef);
size = ARRAY_SIZE(buffer_w);
ret = SendMessageA(hwnd, BCM_GETNOTE, (WPARAM)&size, 0);
ok(!ret, "Expect BCM_SETNOTE return false\n");
ok(size == ARRAY_SIZE(buffer_w), "Got: %d\n", size);
error = GetLastError();
ok(error == ERROR_INVALID_PARAMETER, "Expect last error: 0x%08x, got: 0x%08x\n",
ERROR_INVALID_PARAMETER, error);
/* Get note with NULL size */
SetLastError(0xdeadbeef);
lstrcpyW(buffer_w, deadbeef_w);
ret = SendMessageA(hwnd, BCM_GETNOTE, 0, (LPARAM)buffer_w);
ok(!ret, "Expect BCM_SETNOTE return false\n");
ok(!lstrcmpW(buffer_w, deadbeef_w), "Expect note: %s, got: %s\n",
wine_dbgstr_w(deadbeef_w), wine_dbgstr_w(buffer_w));
error = GetLastError();
ok(error == ERROR_INVALID_PARAMETER, "Expect last error: 0x%08x, got: 0x%08x\n",
ERROR_INVALID_PARAMETER, error);
/* Get note with zero size */
SetLastError(0xdeadbeef);
size = 0;
lstrcpyW(buffer_w, deadbeef_w);
ret = SendMessageA(hwnd, BCM_GETNOTE, (WPARAM)&size, (LPARAM)buffer_w);
ok(!ret, "Expect BCM_GETNOTE return false\n");
ok(!lstrcmpW(buffer_w, deadbeef_w), "Expect note: %s, got: %s\n",
wine_dbgstr_w(deadbeef_w), wine_dbgstr_w(buffer_w));
ok(size == 1, "Got: %d\n", size);
error = GetLastError();
ok(error == ERROR_INSUFFICIENT_BUFFER, "Expect last error: 0x%08x, got: 0x%08x\n",
ERROR_INSUFFICIENT_BUFFER, error);
DestroyWindow(hwnd);
}
else
{
hwnd = create_button(type, NULL);
ok(hwnd != NULL, "Expect hwnd not null\n");
SetLastError(0xdeadbeef);
size = ARRAY_SIZE(buffer_w);
ret = SendMessageA(hwnd, BCM_GETNOTE, (WPARAM)&size, (LPARAM)buffer_w);
ok(!ret, "Expect BCM_GETNOTE return false\n");
error = GetLastError();
ok(error == ERROR_NOT_SUPPORTED, "Expect last error: 0x%08x, got: 0x%08x\n",
ERROR_NOT_SUPPORTED, error);
DestroyWindow(hwnd);
}
}
}
static void test_bm_get_set_image(void)
{
HWND hwnd;
HDC hdc;
HBITMAP hbmp1x1;
HBITMAP hbmp2x2;
HBITMAP hmask2x2;
ICONINFO icon_info2x2;
HICON hicon2x2;
HBITMAP hbmp;
HICON hicon;
ICONINFO icon_info;
BITMAP bm;
static const DWORD default_style = BS_PUSHBUTTON | WS_TABSTOP | WS_POPUP | WS_VISIBLE;
hdc = GetDC(0);
hbmp1x1 = CreateCompatibleBitmap(hdc, 1, 1);
hbmp2x2 = CreateCompatibleBitmap(hdc, 2, 2);
ZeroMemory(&bm, sizeof(bm));
ok(GetObjectW(hbmp1x1, sizeof(bm), &bm), "Expect GetObjectW() success\n");
ok(bm.bmWidth == 1 && bm.bmHeight == 1, "Expect bitmap size: %d,%d, got: %d,%d\n", 1, 1,
bm.bmWidth, bm.bmHeight);
ZeroMemory(&bm, sizeof(bm));
ok(GetObjectW(hbmp2x2, sizeof(bm), &bm), "Expect GetObjectW() success\n");
ok(bm.bmWidth == 2 && bm.bmHeight == 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2,
bm.bmWidth, bm.bmHeight);
hmask2x2 = CreateCompatibleBitmap(hdc, 2, 2);
ZeroMemory(&icon_info2x2, sizeof(icon_info2x2));
icon_info2x2.fIcon = TRUE;
icon_info2x2.hbmMask = hmask2x2;
icon_info2x2.hbmColor = hbmp2x2;
hicon2x2 = CreateIconIndirect(&icon_info2x2);
ok(hicon2x2 !=NULL, "Expect CreateIconIndirect() success\n");
ZeroMemory(&icon_info, sizeof(icon_info));
ok(GetIconInfo(hicon2x2, &icon_info), "Expect GetIconInfo() success\n");
ZeroMemory(&bm, sizeof(bm));
ok(GetObjectW(icon_info.hbmColor, sizeof(bm), &bm), "Expect GetObjectW() success\n");
ok(bm.bmWidth == 2 && bm.bmHeight == 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2,
bm.bmWidth, bm.bmHeight);
DeleteObject(icon_info.hbmColor);
DeleteObject(icon_info.hbmMask);
hwnd = CreateWindowA(WC_BUTTONA, "test", default_style | BS_BITMAP, 0, 0, 100, 100, 0, 0,
0, 0);
ok(hwnd != NULL, "Expect hwnd to be not NULL\n");
/* Get image when image is not set */
hbmp = (HBITMAP)SendMessageA(hwnd, BM_GETIMAGE, IMAGE_BITMAP, 0);
ok(hbmp == 0, "Expect hbmp == 0\n");
/* Set image */
hbmp = (HBITMAP)SendMessageA(hwnd, BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hbmp1x1);
ok(hbmp == 0, "Expect hbmp == 0\n");
hbmp = (HBITMAP)SendMessageA(hwnd, BM_GETIMAGE, IMAGE_BITMAP, 0);
ok(hbmp != 0, "Expect hbmp != 0\n");
/* Set null resets image */
hbmp = (HBITMAP)SendMessageA(hwnd, BM_SETIMAGE, IMAGE_BITMAP, 0);
ok(hbmp != 0, "Expect hbmp != 0\n");
hbmp = (HBITMAP)SendMessageA(hwnd, BM_GETIMAGE, IMAGE_BITMAP, 0);
ok(hbmp == 0, "Expect hbmp == 0\n");
DestroyWindow(hwnd);
/* Set bitmap with BS_BITMAP */
hwnd = CreateWindowA(WC_BUTTONA, "test", default_style | BS_BITMAP, 0, 0, 100, 100, 0, 0,
0, 0);
ok(hwnd != NULL, "Expect hwnd to be not NULL\n");
hbmp = (HBITMAP)SendMessageA(hwnd, BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hbmp1x1);
ok(hbmp == 0, "Expect hbmp == 0\n");
hbmp = (HBITMAP)SendMessageA(hwnd, BM_GETIMAGE, IMAGE_BITMAP, 0);
ok(hbmp != 0, "Expect hbmp != 0\n");
ZeroMemory(&bm, sizeof(bm));
ok(GetObjectW(hbmp, sizeof(bm), &bm), "Expect GetObjectW() success\n");
ok(bm.bmWidth == 1 && bm.bmHeight == 1, "Expect bitmap size: %d,%d, got: %d,%d\n", 1, 1,
bm.bmWidth, bm.bmHeight);
DestroyWindow(hwnd);
/* Set bitmap without BS_BITMAP */
hwnd = CreateWindowA(WC_BUTTONA, "test", default_style, 0, 0, 100, 100, 0, 0, 0, 0);
ok(hwnd != NULL, "Expect hwnd to be not NULL\n");
hbmp = (HBITMAP)SendMessageA(hwnd, BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hbmp1x1);
ok(hbmp == 0, "Expect hbmp == 0\n");
hbmp = (HBITMAP)SendMessageA(hwnd, BM_GETIMAGE, IMAGE_BITMAP, 0);
if (hbmp == 0)
{
/* on xp or 2003*/
win_skip("Show both image and text is not supported. Skip following tests.\n");
DestroyWindow(hwnd);
goto done;
}
ok(hbmp != 0, "Expect hbmp != 0\n");
ZeroMemory(&bm, sizeof(bm));
ok(GetObjectW(hbmp, sizeof(bm), &bm), "Expect GetObjectW() success\n");
ok(bm.bmWidth == 1 && bm.bmHeight == 1, "Expect bitmap size: %d,%d, got: %d,%d\n", 1, 1,
bm.bmWidth, bm.bmHeight);
DestroyWindow(hwnd);
/* Set icon with BS_ICON */
hwnd = CreateWindowA(WC_BUTTONA, "test", default_style | BS_ICON, 0, 0, 100, 100, 0, 0, 0,
0);
ok(hwnd != NULL, "Expect hwnd to be not NULL\n");
hicon = (HICON)SendMessageA(hwnd, BM_SETIMAGE, IMAGE_ICON, (LPARAM)hicon2x2);
ok(hicon == 0, "Expect hicon == 0\n");
hicon = (HICON)SendMessageA(hwnd, BM_GETIMAGE, IMAGE_ICON, 0);
ok(hicon != 0, "Expect hicon != 0\n");
ZeroMemory(&icon_info, sizeof(icon_info));
ok(GetIconInfo(hicon, &icon_info), "Expect GetIconInfo() success\n");
ZeroMemory(&bm, sizeof(bm));
ok(GetObjectW(icon_info.hbmColor, sizeof(bm), &bm), "Expect GetObjectW() success\n");
ok(bm.bmWidth == 2 && bm.bmHeight == 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2,
bm.bmWidth, bm.bmHeight);
DeleteObject(icon_info.hbmColor);
DeleteObject(icon_info.hbmMask);
DestroyWindow(hwnd);
/* Set icon without BS_ICON */
hwnd = CreateWindowA(WC_BUTTONA, "test", default_style, 0, 0, 100, 100, 0, 0, 0, 0);
ok(hwnd != NULL, "Expect hwnd to be not NULL\n");
hicon = (HICON)SendMessageA(hwnd, BM_SETIMAGE, IMAGE_ICON, (LPARAM)hicon2x2);
ok(hicon == 0, "Expect hicon == 0\n");
hicon = (HICON)SendMessageA(hwnd, BM_GETIMAGE, IMAGE_ICON, 0);
ok(hicon != 0, "Expect hicon != 0\n");
ZeroMemory(&icon_info, sizeof(icon_info));
ok(GetIconInfo(hicon, &icon_info), "Expect GetIconInfo() success\n");
ZeroMemory(&bm, sizeof(bm));
ok(GetObjectW(icon_info.hbmColor, sizeof(bm), &bm), "Expect GetObjectW() success\n");
ok(bm.bmWidth == 2 && bm.bmHeight == 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2,
bm.bmWidth, bm.bmHeight);
DeleteObject(icon_info.hbmColor);
DeleteObject(icon_info.hbmMask);
DestroyWindow(hwnd);
/* Set icon with BS_BITMAP */
hwnd = CreateWindowA(WC_BUTTONA, "test", default_style | BS_BITMAP, 0, 0, 100, 100, 0, 0,
0, 0);
ok(hwnd != NULL, "Expect hwnd to be not NULL\n");
hicon = (HICON)SendMessageA(hwnd, BM_SETIMAGE, IMAGE_ICON, (LPARAM)hicon2x2);
ok(hicon == 0, "Expect hicon == 0\n");
hicon = (HICON)SendMessageA(hwnd, BM_GETIMAGE, IMAGE_ICON, 0);
ok(hicon != 0, "Expect hicon != 0\n");
ZeroMemory(&icon_info, sizeof(icon_info));
ok(GetIconInfo(hicon, &icon_info), "Expect GetIconInfo() success\n");
ZeroMemory(&bm, sizeof(bm));
ok(GetObjectW(icon_info.hbmColor, sizeof(bm), &bm), "Expect GetObjectW() success\n");
ok(bm.bmWidth == 2 && bm.bmHeight == 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2,
bm.bmWidth, bm.bmHeight);
DeleteObject(icon_info.hbmColor);
DeleteObject(icon_info.hbmMask);
DestroyWindow(hwnd);
/* Set bitmap with BS_ICON */
hwnd = CreateWindowA(WC_BUTTONA, "test", default_style | BS_ICON, 0, 0, 100, 100, 0, 0, 0,
0);
ok(hwnd != NULL, "Expect hwnd to be not NULL\n");
hbmp = (HBITMAP)SendMessageA(hwnd, BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hbmp1x1);
ok(hbmp == 0, "Expect hbmp == 0\n");
hbmp = (HBITMAP)SendMessageA(hwnd, BM_GETIMAGE, IMAGE_BITMAP, 0);
ok(hbmp != 0, "Expect hbmp != 0\n");
ZeroMemory(&bm, sizeof(bm));
ok(GetObjectW(hbmp, sizeof(bm), &bm), "Expect GetObjectW() success\n");
ok(bm.bmWidth == 1 && bm.bmHeight == 1, "Expect bitmap size: %d,%d, got: %d,%d\n", 1, 1,
bm.bmWidth, bm.bmHeight);
DestroyWindow(hwnd);
/* Set bitmap with BS_BITMAP and IMAGE_ICON*/
hwnd = CreateWindowA(WC_BUTTONA, "test", default_style | BS_BITMAP, 0, 0, 100, 100, 0, 0,
0, 0);
ok(hwnd != NULL, "Expect hwnd to be not NULL\n");
hbmp = (HBITMAP)SendMessageA(hwnd, BM_SETIMAGE, IMAGE_ICON, (LPARAM)hbmp1x1);
ok(hbmp == 0, "Expect hbmp == 0\n");
hbmp = (HBITMAP)SendMessageA(hwnd, BM_GETIMAGE, IMAGE_ICON, 0);
ok(hbmp != 0, "Expect hbmp != 0\n");
ZeroMemory(&bm, sizeof(bm));
ok(GetObjectW(hbmp, sizeof(bm), &bm), "Expect GetObjectW() success\n");
ok(bm.bmWidth == 1 && bm.bmHeight == 1, "Expect bitmap size: %d,%d, got: %d,%d\n", 1, 1,
bm.bmWidth, bm.bmHeight);
DestroyWindow(hwnd);
/* Set icon with BS_ICON and IMAGE_BITMAP */
hwnd = CreateWindowA(WC_BUTTONA, "test", default_style | BS_ICON, 0, 0, 100, 100, 0, 0, 0,
0);
ok(hwnd != NULL, "Expect hwnd to be not NULL\n");
hicon = (HICON)SendMessageA(hwnd, BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hicon2x2);
ok(hicon == 0, "Expect hicon == 0\n");
hicon = (HICON)SendMessageA(hwnd, BM_GETIMAGE, IMAGE_BITMAP, 0);
ok(hicon != 0, "Expect hicon != 0\n");
ZeroMemory(&icon_info, sizeof(icon_info));
ok(GetIconInfo(hicon, &icon_info), "Expect GetIconInfo() success\n");
ZeroMemory(&bm, sizeof(bm));
ok(GetObjectW(icon_info.hbmColor, sizeof(BITMAP), &bm), "Expect GetObjectW() success\n");
ok(bm.bmWidth == 2 && bm.bmHeight == 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2,
bm.bmWidth, bm.bmHeight);
DeleteObject(icon_info.hbmColor);
DeleteObject(icon_info.hbmMask);
DestroyWindow(hwnd);
/* Set bitmap with BS_ICON and IMAGE_ICON */
hwnd = CreateWindowA(WC_BUTTONA, "test", default_style | BS_ICON, 0, 0, 100, 100, 0, 0, 0, 0);
ok(hwnd != NULL, "Expect hwnd to be not NULL\n");
hbmp = (HBITMAP)SendMessageA(hwnd, BM_SETIMAGE, IMAGE_ICON, (LPARAM)hbmp1x1);
ok(hbmp == 0, "Expect hbmp == 0\n");
hbmp = (HBITMAP)SendMessageA(hwnd, BM_GETIMAGE, IMAGE_ICON, 0);
ok(hbmp != 0, "Expect hbmp != 0\n");
ZeroMemory(&bm, sizeof(bm));
ok(GetObjectW(hbmp, sizeof(bm), &bm), "Expect GetObjectW() success\n");
ok(bm.bmWidth == 1 && bm.bmHeight == 1, "Expect bitmap size: %d,%d, got: %d,%d\n", 1, 1,
bm.bmWidth, bm.bmHeight);
DestroyWindow(hwnd);
/* Set icon with BS_BITMAP and IMAGE_BITMAP */
hwnd = CreateWindowA(WC_BUTTONA, "test", default_style | BS_BITMAP, 0, 0, 100, 100, 0, 0, 0, 0);
ok(hwnd != NULL, "Expect hwnd to be not NULL\n");
hicon = (HICON)SendMessageA(hwnd, BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hicon2x2);
ok(hicon == 0, "Expect hicon == 0\n");
hicon = (HICON)SendMessageA(hwnd, BM_GETIMAGE, IMAGE_BITMAP, 0);
ok(hicon != 0, "Expect hicon != 0\n");
ZeroMemory(&icon_info, sizeof(icon_info));
ok(GetIconInfo(hicon, &icon_info), "Expect GetIconInfo() success\n");
ZeroMemory(&bm, sizeof(bm));
ok(GetObjectW(icon_info.hbmColor, sizeof(BITMAP), &bm), "Expect GetObjectW() success\n");
ok(bm.bmWidth == 2 && bm.bmHeight == 2, "Expect bitmap size: %d,%d, got: %d,%d\n", 2, 2,
bm.bmWidth, bm.bmHeight);
DeleteObject(icon_info.hbmColor);
DeleteObject(icon_info.hbmMask);
DestroyWindow(hwnd);
done:
DestroyIcon(hicon2x2);
DeleteObject(hmask2x2);
DeleteObject(hbmp2x2);
DeleteObject(hbmp1x1);
ReleaseDC(0, hdc);
}
static void register_parent_class(void)
{
WNDCLASSA cls;
@ -824,6 +1228,504 @@ static void register_parent_class(void)
RegisterClassA(&cls);
}
static void test_button_data(void)
{
static const DWORD styles[] =
{
BS_PUSHBUTTON,
BS_DEFPUSHBUTTON,
BS_CHECKBOX,
BS_AUTOCHECKBOX,
BS_RADIOBUTTON,
BS_3STATE,
BS_AUTO3STATE,
BS_GROUPBOX,
BS_USERBUTTON,
BS_AUTORADIOBUTTON,
BS_OWNERDRAW,
BS_SPLITBUTTON,
BS_DEFSPLITBUTTON,
BS_COMMANDLINK,
BS_DEFCOMMANDLINK,
};
struct button_desc
{
HWND self;
HWND parent;
LONG style;
};
unsigned int i;
HWND parent;
parent = CreateWindowExA(0, "TestParentClass", "Test parent", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
100, 100, 200, 200, 0, 0, 0, NULL);
ok(parent != 0, "Failed to create parent window\n");
for (i = 0; i < ARRAY_SIZE(styles); i++)
{
struct button_desc *desc;
HWND hwnd;
hwnd = create_button(styles[i], parent);
ok(hwnd != NULL, "Failed to create a button.\n");
desc = (void *)GetWindowLongPtrA(hwnd, 0);
ok(desc != NULL, "Expected window data.\n");
if (desc)
{
ok(desc->self == hwnd, "Unexpected 'self' field.\n");
ok(desc->parent == parent, "Unexpected 'parent' field.\n");
ok(desc->style == (WS_CHILD | BS_NOTIFY | styles[i]), "Unexpected 'style' field.\n");
}
DestroyWindow(hwnd);
}
DestroyWindow(parent);
}
static void test_get_set_imagelist(void)
{
HWND hwnd;
HIMAGELIST himl;
BUTTON_IMAGELIST biml = {0};
HDC hdc;
HBITMAP hbmp;
INT width = 16;
INT height = 16;
INT index;
DWORD type;
BOOL ret;
hdc = GetDC(0);
hbmp = CreateCompatibleBitmap(hdc, width, height);
ok(hbmp != NULL, "Expect hbmp not null\n");
himl = pImageList_Create(width, height, ILC_COLOR, 1, 0);
ok(himl != NULL, "Expect himl not null\n");
index = pImageList_Add(himl, hbmp, NULL);
ok(index == 0, "Expect index == 0\n");
DeleteObject(hbmp);
ReleaseDC(0, hdc);
for (type = BS_PUSHBUTTON; type <= BS_DEFCOMMANDLINK; type++)
{
hwnd = create_button(type, NULL);
ok(hwnd != NULL, "Expect hwnd not null\n");
/* Get imagelist when imagelist is unset yet */
ret = SendMessageA(hwnd, BCM_GETIMAGELIST, 0, (LPARAM)&biml);
ok(ret, "Expect BCM_GETIMAGELIST return true\n");
ok(biml.himl == 0 && IsRectEmpty(&biml.margin) && biml.uAlign == 0,
"Expect BUTTON_IMAGELIST is empty\n");
/* Set imagelist with himl null */
biml.himl = 0;
biml.uAlign = BUTTON_IMAGELIST_ALIGN_CENTER;
ret = SendMessageA(hwnd, BCM_SETIMAGELIST, 0, (LPARAM)&biml);
ok(ret || broken(!ret), /* xp or 2003 */
"Expect BCM_SETIMAGELIST return true\n");
/* Set imagelist with uAlign invalid */
biml.himl = himl;
biml.uAlign = -1;
ret = SendMessageA(hwnd, BCM_SETIMAGELIST, 0, (LPARAM)&biml);
ok(ret, "Expect BCM_SETIMAGELIST return true\n");
/* Successful get and set imagelist */
biml.himl = himl;
biml.uAlign = BUTTON_IMAGELIST_ALIGN_CENTER;
ret = SendMessageA(hwnd, BCM_SETIMAGELIST, 0, (LPARAM)&biml);
ok(ret, "Expect BCM_SETIMAGELIST return true\n");
ret = SendMessageA(hwnd, BCM_GETIMAGELIST, 0, (LPARAM)&biml);
ok(ret, "Expect BCM_GETIMAGELIST return true\n");
ok(biml.himl == himl, "Expect himl to be same\n");
ok(biml.uAlign == BUTTON_IMAGELIST_ALIGN_CENTER, "Expect uAlign to be %x\n",
BUTTON_IMAGELIST_ALIGN_CENTER);
/* BCM_SETIMAGELIST null pointer handling */
ret = SendMessageA(hwnd, BCM_SETIMAGELIST, 0, 0);
ok(!ret, "Expect BCM_SETIMAGELIST return false\n");
ret = SendMessageA(hwnd, BCM_GETIMAGELIST, 0, (LPARAM)&biml);
ok(ret, "Expect BCM_GETIMAGELIST return true\n");
ok(biml.himl == himl, "Expect himl to be same\n");
/* BCM_GETIMAGELIST null pointer handling */
biml.himl = himl;
biml.uAlign = BUTTON_IMAGELIST_ALIGN_CENTER;
ret = SendMessageA(hwnd, BCM_SETIMAGELIST, 0, (LPARAM)&biml);
ok(ret, "Expect BCM_SETIMAGELIST return true\n");
ret = SendMessageA(hwnd, BCM_GETIMAGELIST, 0, 0);
ok(!ret, "Expect BCM_GETIMAGELIST return false\n");
DestroyWindow(hwnd);
}
pImageList_Destroy(himl);
}
static void test_get_set_textmargin(void)
{
HWND hwnd;
RECT margin_in;
RECT margin_out;
BOOL ret;
DWORD type;
SetRect(&margin_in, 2, 1, 3, 4);
for (type = BS_PUSHBUTTON; type <= BS_DEFCOMMANDLINK; type++)
{
hwnd = create_button(type, NULL);
ok(hwnd != NULL, "Expect hwnd not null\n");
/* Get text margin when it is unset */
ret = SendMessageA(hwnd, BCM_GETTEXTMARGIN, 0, (LPARAM)&margin_out);
ok(ret, "Expect ret to be true\n");
ok(IsRectEmpty(&margin_out), "Expect margin empty\n");
/* Successful get and set text margin */
ret = SendMessageA(hwnd, BCM_SETTEXTMARGIN, 0, (LPARAM)&margin_in);
ok(ret, "Expect ret to be true\n");
SetRectEmpty(&margin_out);
ret = SendMessageA(hwnd, BCM_GETTEXTMARGIN, 0, (LPARAM)&margin_out);
ok(ret, "Expect ret to be true\n");
ok(EqualRect(&margin_in, &margin_out), "Expect margins to be equal\n");
/* BCM_SETTEXTMARGIN null pointer handling */
ret = SendMessageA(hwnd, BCM_SETTEXTMARGIN, 0, 0);
ok(!ret, "Expect ret to be false\n");
SetRectEmpty(&margin_out);
ret = SendMessageA(hwnd, BCM_GETTEXTMARGIN, 0, (LPARAM)&margin_out);
ok(ret, "Expect ret to be true\n");
ok(EqualRect(&margin_in, &margin_out), "Expect margins to be equal\n");
/* BCM_GETTEXTMARGIN null pointer handling */
ret = SendMessageA(hwnd, BCM_SETTEXTMARGIN, 0, (LPARAM)&margin_in);
ok(ret, "Expect ret to be true\n");
ret = SendMessageA(hwnd, BCM_GETTEXTMARGIN, 0, 0);
ok(!ret, "Expect ret to be true\n");
DestroyWindow(hwnd);
}
}
static void test_state(void)
{
HWND hwnd;
DWORD type;
LONG state;
/* Initial button state */
for (type = BS_PUSHBUTTON; type <= BS_DEFCOMMANDLINK; type++)
{
hwnd = create_button(type, NULL);
state = SendMessageA(hwnd, BM_GETSTATE, 0, 0);
ok(state == BST_UNCHECKED, "Expect state 0x%08x, got 0x%08x\n", BST_UNCHECKED, state);
DestroyWindow(hwnd);
}
}
static void test_bcm_get_ideal_size(void)
{
static const char *button_text2 = "WWWW\nWWWW";
static const char *button_text = "WWWW";
static const DWORD imagelist_aligns[] = {BUTTON_IMAGELIST_ALIGN_LEFT, BUTTON_IMAGELIST_ALIGN_RIGHT,
BUTTON_IMAGELIST_ALIGN_TOP, BUTTON_IMAGELIST_ALIGN_BOTTOM,
BUTTON_IMAGELIST_ALIGN_CENTER};
static const DWORD aligns[] = {0, BS_TOP, BS_LEFT, BS_RIGHT, BS_BOTTOM,
BS_CENTER, BS_VCENTER, BS_RIGHTBUTTON, WS_EX_RIGHT};
DWORD default_style = WS_TABSTOP | WS_POPUP | WS_VISIBLE;
const LONG client_width = 400, client_height = 200;
LONG image_width, height, line_count, text_width;
HFONT hfont, prev_font;
DWORD style, type;
BOOL ret;
HWND hwnd;
HDC hdc;
LOGFONTA lf;
TEXTMETRICA tm;
SIZE size;
HBITMAP hmask, hbmp;
ICONINFO icon_info;
HICON hicon;
HIMAGELIST himl;
BUTTON_IMAGELIST biml = {0};
RECT rect;
INT i, j;
/* Check for NULL pointer handling */
hwnd = CreateWindowA(WC_BUTTONA, button_text, BS_PUSHBUTTON | default_style, 0, 0, client_width, client_height,
NULL, NULL, 0, NULL);
ret = SendMessageA(hwnd, BCM_GETIDEALSIZE, 0, 0);
ok(!ret, "Expect BCM_GETIDEALSIZE message to return false.\n");
/* Set font so that the test is consistent on Wine and Windows */
ZeroMemory(&lf, sizeof(lf));
lf.lfWeight = FW_NORMAL;
lf.lfHeight = 20;
lstrcpyA(lf.lfFaceName, "Tahoma");
hfont = CreateFontIndirectA(&lf);
ok(hfont != NULL, "Failed to create test font.\n");
/* Get tmHeight */
hdc = GetDC(hwnd);
prev_font = SelectObject(hdc, hfont);
GetTextMetricsA(hdc, &tm);
SelectObject(hdc, prev_font);
DrawTextA(hdc, button_text, -1, &rect, DT_CALCRECT);
text_width = rect.right - rect.left;
ReleaseDC(hwnd, hdc);
DestroyWindow(hwnd);
/* XP and 2003 doesn't support command links, getting ideal size with button having only text returns client size on these platforms. */
hwnd = CreateWindowA(WC_BUTTONA, button_text, BS_DEFCOMMANDLINK | default_style, 0, 0, client_width, client_height, NULL,
NULL, 0, NULL);
ok(hwnd != NULL, "Expect hwnd not NULL\n");
SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, (LPARAM)TRUE);
ZeroMemory(&size, sizeof(size));
ret = SendMessageA(hwnd, BCM_GETIDEALSIZE, 0, (LPARAM)&size);
ok(ret, "Expect BCM_GETIDEALSIZE message to return true\n");
if (size.cx == client_width && size.cy == client_height)
{
/* on XP and 2003, buttons with image are not supported */
win_skip("Skipping further tests on XP and 2003\n");
return;
}
/* Tests for image placements */
/* Prepare bitmap */
image_width = 48;
height = 48;
hdc = GetDC(0);
hmask = CreateCompatibleBitmap(hdc, image_width, height);
hbmp = CreateCompatibleBitmap(hdc, image_width, height);
/* Only bitmap for push button, ideal size should be enough for image and text */
hwnd = CreateWindowA(WC_BUTTONA, button_text, BS_DEFPUSHBUTTON | BS_BITMAP | default_style, 0, 0, client_width,
client_height, NULL, NULL, 0, NULL);
ok(hwnd != NULL, "Expect hwnd not NULL\n");
SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hbmp);
SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, (LPARAM)TRUE);
ZeroMemory(&size, sizeof(size));
ret = SendMessageA(hwnd, BCM_GETIDEALSIZE, 0, (LPARAM)&size);
ok(ret, "Expect BCM_GETIDEALSIZE message to return true\n");
/* Ideal size contains text rect even show bitmap only */
ok((size.cx >= image_width + text_width && size.cy >= max(height, tm.tmHeight)),
"Expect ideal cx %d >= %d and ideal cy %d >= %d\n", size.cx, image_width + text_width,
size.cy, max(height, tm.tmHeight));
DestroyWindow(hwnd);
/* Image alignments when button has bitmap and text*/
for (i = 0; i < ARRAY_SIZE(aligns); i++)
for (j = 0; j < ARRAY_SIZE(aligns); j++)
{
style = BS_DEFPUSHBUTTON | default_style | aligns[i] | aligns[j];
hwnd = CreateWindowA(WC_BUTTONA, button_text, style, 0, 0, client_width, client_height, NULL, NULL, 0, NULL);
ok(hwnd != NULL, "Expect hwnd not NULL\n");
SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hbmp);
SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, (LPARAM)TRUE);
ZeroMemory(&size, sizeof(size));
ret = SendMessageA(hwnd, BCM_GETIDEALSIZE, 0, (LPARAM)&size);
ok(ret, "Expect BCM_GETIDEALSIZE message to return true\n");
if (!(style & (BS_CENTER | BS_VCENTER)) || ((style & BS_CENTER) && (style & BS_CENTER) != BS_CENTER)
|| !(style & BS_VCENTER) || (style & BS_VCENTER) == BS_VCENTER)
ok((size.cx >= image_width + text_width && size.cy >= max(height, tm.tmHeight)),
"Style: 0x%08x expect ideal cx %d >= %d and ideal cy %d >= %d\n", style, size.cx,
image_width + text_width, size.cy, max(height, tm.tmHeight));
else
ok((size.cx >= max(text_width, height) && size.cy >= height + tm.tmHeight),
"Style: 0x%08x expect ideal cx %d >= %d and ideal cy %d >= %d\n", style, size.cx,
max(text_width, height), size.cy, height + tm.tmHeight);
DestroyWindow(hwnd);
}
/* Image list alignments */
himl = pImageList_Create(image_width, height, ILC_COLOR, 1, 1);
pImageList_Add(himl, hbmp, 0);
biml.himl = himl;
for (i = 0; i < ARRAY_SIZE(imagelist_aligns); i++)
{
biml.uAlign = imagelist_aligns[i];
hwnd = CreateWindowA(WC_BUTTONA, button_text, BS_DEFPUSHBUTTON | default_style, 0, 0, client_width,
client_height, NULL, NULL, 0, NULL);
ok(hwnd != NULL, "Expect hwnd not NULL\n");
SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, (LPARAM)TRUE);
SendMessageA(hwnd, BCM_SETIMAGELIST, 0, (LPARAM)&biml);
ZeroMemory(&size, sizeof(size));
ret = SendMessageA(hwnd, BCM_GETIDEALSIZE, 0, (LPARAM)&size);
ok(ret, "Expect BCM_GETIDEALSIZE message to return true\n");
if (biml.uAlign == BUTTON_IMAGELIST_ALIGN_TOP || biml.uAlign == BUTTON_IMAGELIST_ALIGN_BOTTOM)
ok((size.cx >= max(text_width, height) && size.cy >= height + tm.tmHeight),
"Align:%d expect ideal cx %d >= %d and ideal cy %d >= %d\n", biml.uAlign, size.cx,
max(text_width, height), size.cy, height + tm.tmHeight);
else if (biml.uAlign == BUTTON_IMAGELIST_ALIGN_LEFT || biml.uAlign == BUTTON_IMAGELIST_ALIGN_RIGHT)
ok((size.cx >= image_width + text_width && size.cy >= max(height, tm.tmHeight)),
"Align:%d expect ideal cx %d >= %d and ideal cy %d >= %d\n", biml.uAlign, size.cx,
image_width + text_width, size.cy, max(height, tm.tmHeight));
else
ok(size.cx >= image_width && size.cy >= height, "Align:%d expect ideal cx %d >= %d and ideal cy %d >= %d\n",
biml.uAlign, size.cx, image_width, size.cy, height);
DestroyWindow(hwnd);
}
/* Icon as image */
/* Create icon from bitmap */
ZeroMemory(&icon_info, sizeof(icon_info));
icon_info.fIcon = TRUE;
icon_info.hbmMask = hmask;
icon_info.hbmColor = hbmp;
hicon = CreateIconIndirect(&icon_info);
/* Only icon, ideal size should be enough for image and text */
hwnd = CreateWindowA(WC_BUTTONA, button_text, BS_DEFPUSHBUTTON | BS_ICON | default_style, 0, 0, client_width,
client_height, NULL, NULL, 0, NULL);
ok(hwnd != NULL, "Expect hwnd not NULL\n");
SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)hicon);
SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, (LPARAM)TRUE);
ZeroMemory(&size, sizeof(size));
ret = SendMessageA(hwnd, BCM_GETIDEALSIZE, 0, (LPARAM)&size);
ok(ret, "Expect BCM_GETIDEALSIZE message to return true\n");
/* Ideal size contains text rect even show icons only */
ok((size.cx >= image_width + text_width && size.cy >= max(height, tm.tmHeight)),
"Expect ideal cx %d >= %d and ideal cy %d >= %d\n", size.cx, image_width + text_width, size.cy,
max(height, tm.tmHeight));
DestroyWindow(hwnd);
/* Show icon and text */
hwnd = CreateWindowA(WC_BUTTONA, button_text, BS_DEFPUSHBUTTON | default_style, 0, 0, client_width,
client_height, NULL, NULL, 0, NULL);
ok(hwnd != NULL, "Expect hwnd not NULL\n");
SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)hicon);
SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, (LPARAM)TRUE);
ZeroMemory(&size, sizeof(size));
ret = SendMessageA(hwnd, BCM_GETIDEALSIZE, 0, (LPARAM)&size);
ok(ret, "Expect BCM_GETIDEALSIZE message to return true\n");
ok((size.cx >= image_width + text_width && size.cy >= max(height, tm.tmHeight)),
"Expect ideal cx %d >= %d and ideal cy %d >= %d\n", size.cx, image_width + text_width, size.cy,
max(height, tm.tmHeight));
DestroyWindow(hwnd);
/* Checkbox */
/* Both bitmap and text for checkbox, ideal size is only enough for text because it doesn't support image(but not image list)*/
hwnd = CreateWindowA(WC_BUTTONA, button_text, BS_AUTOCHECKBOX | default_style, 0, 0, client_width, client_height,
NULL, NULL, 0, NULL);
ok(hwnd != NULL, "Expect hwnd not NULL\n");
SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hbmp);
SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, (LPARAM)TRUE);
ZeroMemory(&size, sizeof(size));
ret = SendMessageA(hwnd, BCM_GETIDEALSIZE, 0, (LPARAM)&size);
ok(ret, "Expect BCM_GETIDEALSIZE message to return true\n");
ok((size.cx <= image_width + text_width && size.cx >= text_width && size.cy <= max(height, tm.tmHeight)
&& size.cy >= tm.tmHeight),
"Expect ideal cx %d within range (%d, %d ) and ideal cy %d within range (%d, %d )\n", size.cx,
text_width, image_width + text_width, size.cy, tm.tmHeight, max(height, tm.tmHeight));
DestroyWindow(hwnd);
/* Both image list and text for checkbox, ideal size should have enough for image list and text */
biml.uAlign = BUTTON_IMAGELIST_ALIGN_LEFT;
hwnd = CreateWindowA(WC_BUTTONA, button_text, BS_AUTOCHECKBOX | BS_BITMAP | default_style, 0, 0, client_width,
client_height, NULL, NULL, 0, NULL);
ok(hwnd != NULL, "Expect hwnd not NULL\n");
SendMessageA(hwnd, BCM_SETIMAGELIST, 0, (LPARAM)&biml);
SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, (LPARAM)TRUE);
ZeroMemory(&size, sizeof(size));
ret = SendMessageA(hwnd, BCM_GETIDEALSIZE, 0, (LPARAM)&size);
ok(ret, "Expect BCM_GETIDEALSIZE message to return true\n");
ok((size.cx >= image_width + text_width && size.cy >= max(height, tm.tmHeight)),
"Expect ideal cx %d >= %d and ideal cy %d >= %d\n", size.cx, image_width + text_width, size.cy,
max(height, tm.tmHeight));
DestroyWindow(hwnd);
/* Only bitmap for checkbox, ideal size should have enough for image and text */
hwnd = CreateWindowA(WC_BUTTONA, button_text, BS_AUTOCHECKBOX | BS_BITMAP | default_style, 0, 0, client_width,
client_height, NULL, NULL, 0, NULL);
ok(hwnd != NULL, "Expect hwnd not NULL\n");
SendMessageA(hwnd, BM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hbmp);
SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, (LPARAM)TRUE);
ZeroMemory(&size, sizeof(size));
ret = SendMessageA(hwnd, BCM_GETIDEALSIZE, 0, (LPARAM)&size);
ok(ret, "Expect BCM_GETIDEALSIZE message to return true\n");
ok((size.cx >= image_width + text_width && size.cy >= max(height, tm.tmHeight)),
"Expect ideal cx %d >= %d and ideal cy %d >= %d\n", size.cx, image_width + text_width, size.cy,
max(height, tm.tmHeight));
DestroyWindow(hwnd);
/* Test button with only text */
/* No text */
for (type = BS_PUSHBUTTON; type <= BS_DEFCOMMANDLINK; type++)
{
style = type | default_style;
hwnd = CreateWindowA(WC_BUTTONA, "", style, 0, 0, client_width, client_height, NULL, NULL, 0, NULL);
ok(hwnd != NULL, "Expect hwnd not NULL\n");
SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, (LPARAM)TRUE);
ZeroMemory(&size, sizeof(size));
ret = SendMessageA(hwnd, BCM_GETIDEALSIZE, 0, (LPARAM)&size);
ok(ret, "Expect BCM_GETIDEALSIZE message to return true\n");
if (type == BS_COMMANDLINK || type == BS_DEFCOMMANDLINK)
{
todo_wine ok((size.cx == 0 && size.cy > 0), "Style 0x%08x expect ideal cx %d >= %d and ideal cy %d >= %d\n",
style, size.cx, 0, size.cy, 0);
}
else
{
ok(size.cx == client_width && size.cy == client_height,
"Style 0x%08x expect size.cx == %d and size.cy == %d, got size.cx: %d size.cy: %d\n", style,
client_width, client_height, size.cx, size.cy);
}
DestroyWindow(hwnd);
}
/* Single line and multiple lines text */
for (line_count = 1; line_count <= 2; line_count++)
{
for (type = BS_PUSHBUTTON; type <= BS_DEFCOMMANDLINK; type++)
{
style = line_count > 1 ? type | BS_MULTILINE : type;
style |= default_style;
hwnd = CreateWindowA(WC_BUTTONA, (line_count == 2 ? button_text2 : button_text), style, 0, 0, client_width,
client_height, NULL, NULL, 0, NULL);
ok(hwnd != NULL, "Expect hwnd not NULL\n");
SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, (LPARAM)TRUE);
ZeroMemory(&size, sizeof(size));
ret = SendMessageA(hwnd, BCM_GETIDEALSIZE, 0, (LPARAM)&size);
ok(ret, "Expect BCM_GETIDEALSIZE message to return true\n");
if (type == BS_3STATE || type == BS_AUTO3STATE || type == BS_GROUPBOX || type == BS_PUSHBOX
|| type == BS_OWNERDRAW)
{
ok(size.cx == client_width && size.cy == client_height,
"Style 0x%08x expect ideal size (%d,%d), got (%d,%d)\n", style, client_width, client_height, size.cx,
size.cy);
}
else if (type == BS_COMMANDLINK || type == BS_DEFCOMMANDLINK)
{
todo_wine ok((size.cx == 0 && size.cy > 0),
"Style 0x%08x expect ideal cx %d >= %d and ideal cy %d >= %d\n", style, size.cx, 0,
size.cy, 0);
}
else
{
height = line_count == 2 ? 2 * tm.tmHeight : tm.tmHeight;
ok(size.cx >= 0 && size.cy >= height, "Style 0x%08x expect ideal cx %d >= 0 and ideal cy %d >= %d\n",
style, size.cx, size.cy, height);
}
DestroyWindow(hwnd);
}
}
pImageList_Destroy(himl);
DestroyIcon(hicon);
DeleteObject(hbmp);
DeleteObject(hmask);
ReleaseDC(0, hdc);
DeleteObject(hfont);
}
START_TEST(button)
{
ULONG_PTR ctx_cookie;
@ -839,6 +1741,13 @@ START_TEST(button)
test_button_class();
test_button_messages();
test_note();
test_button_data();
test_bm_get_set_image();
test_get_set_imagelist();
test_get_set_textmargin();
test_state();
test_bcm_get_ideal_size();
unload_v6_module(ctx_cookie, hCtx);
}

View file

@ -264,7 +264,7 @@ static void test_comboex_WM_LBUTTONDOWN(void)
WS_VISIBLE|WS_CHILD|CBS_DROPDOWN, 0, 0, 200, 150,
hComboExParentWnd, NULL, hMainHinst, NULL);
for (i = 0; i < sizeof(choices)/sizeof(UINT); i++){
for (i = 0; i < ARRAY_SIZE(choices); i++){
COMBOBOXEXITEMW cbexItem;
wsprintfW(buffer, stringFormat, choices[i]);
@ -1165,11 +1165,11 @@ static void test_combo_dropdown_size(DWORD style)
int limit;
} info_height[] = {
{33, 50, -1},
{35, 50, 40},
{35, 100, 40},
{15, 50, 3},
};
for (test = 0; test < sizeof(info_height) / sizeof(info_height[0]); test++)
for (test = 0; test < ARRAY_SIZE(info_height); test++)
{
const struct list_size_info *info_test = &info_height[test];
int height_item; /* Height of a list item */
@ -1182,7 +1182,6 @@ static void test_combo_dropdown_size(DWORD style)
info_test->height_combo, hMainWnd, (HMENU)COMBO_ID, NULL, 0);
min_visible_expected = SendMessageA(hCombo, CB_GETMINVISIBLE, 0, 0);
todo_wine
ok(min_visible_expected == 30, "Unexpected number of items %d.\n", min_visible_expected);
cbInfo.cbSize = sizeof(COMBOBOXINFO);
@ -1202,10 +1201,8 @@ static void test_combo_dropdown_size(DWORD style)
min_visible_expected = info_test->limit;
ret = SendMessageA(hCombo, CB_SETMINVISIBLE, min_visible_expected, 0);
todo_wine
ok(ret, "Failed to set visible limit.\n");
min_visible_actual = SendMessageA(hCombo, CB_GETMINVISIBLE, 0, 0);
todo_wine
ok(min_visible_expected == min_visible_actual, "test %d: unexpected number of items %d.\n",
test, min_visible_actual);
}
@ -1242,7 +1239,6 @@ static void test_combo_dropdown_size(DWORD style)
if (expected_height_list < 0)
expected_height_list = 0;
todo_wine
ok(expected_height_list == height_list, "Test %d, expected list height to be %d, got %d\n",
test, expected_height_list, height_list);
}
@ -1250,7 +1246,6 @@ static void test_combo_dropdown_size(DWORD style)
{
expected_height_list = min(info_test->num_items, min_visible_expected) * height_item;
todo_wine
ok(expected_height_list == height_list, "Test %d, expected list height to be %d, got %d\n",
test, expected_height_list, height_list);
}

View file

@ -721,6 +721,46 @@ static void test_dtm_set_and_get_systemtime_with_limits(void)
DestroyWindow(hWnd);
}
static void test_dtm_get_ideal_size(void)
{
HWND hwnd;
HDC hdc;
HFONT hfont;
LOGFONTA lf;
TEXTMETRICA tm;
SIZE size;
BOOL r;
hwnd = create_datetime_control(0);
r = SendMessageA(hwnd, DTM_GETIDEALSIZE, 0, (LPARAM)&size);
if (!r)
{
win_skip("DTM_GETIDEALSIZE is not available\n");
DestroyWindow(hwnd);
return;
}
/* Set font so that the test is consistent on Wine and Windows */
ZeroMemory(&lf, sizeof(lf));
lf.lfWeight = FW_NORMAL;
lf.lfHeight = 20;
lstrcpyA(lf.lfFaceName, "Tahoma");
hfont = CreateFontIndirectA(&lf);
SendMessageA(hwnd, WM_SETFONT, (WPARAM)hfont, (LPARAM)TRUE);
hdc = GetDC(hwnd);
GetTextMetricsA(hdc, &tm);
ReleaseDC(hwnd, hdc);
r = SendMessageA(hwnd, DTM_GETIDEALSIZE, 0, (LPARAM)&size);
ok(r, "Expect DTM_GETIDEALSIZE message to return true\n");
ok(size.cx > 0 && size.cy >= tm.tmHeight,
"Expect size.cx > 0 and size.cy >= %d, got cx:%d cy:%d\n", tm.tmHeight, size.cx, size.cy);
DestroyWindow(hwnd);
DeleteObject(hfont);
}
static void test_wm_set_get_text(void)
{
static const CHAR a_str[] = "a";
@ -821,6 +861,7 @@ START_TEST(datetime)
test_dtm_set_and_get_mccolor();
test_dtm_set_and_get_mcfont();
test_dtm_get_monthcal();
test_dtm_get_ideal_size();
test_wm_set_get_text();
test_dts_shownone();

View file

@ -2969,7 +2969,7 @@ static void test_EM_GETLINE(void)
hwnd[0] = create_editcontrol(ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0);
hwnd[1] = create_editcontrolW(ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0);
for (i = 0; i < sizeof(hwnd)/sizeof(hwnd[0]); i++)
for (i = 0; i < ARRAY_SIZE(hwnd); i++)
{
static const WCHAR strW[] = {'t','e','x','t',0};
static const char *str = "text";
@ -2994,13 +2994,13 @@ static void test_EM_GETLINE(void)
ok(!strcmp(buff, str), "Unexpected line data %s.\n", buff);
memset(buffW, 0, sizeof(buffW));
*(WORD *)buffW = sizeof(buffW)/sizeof(buffW[0]);
*(WORD *)buffW = ARRAY_SIZE(buffW);
r = SendMessageW(hwnd[i], EM_GETLINE, 0, (LPARAM)buffW);
ok(r == lstrlenW(strW), "Failed to get a line %d.\n", r);
ok(!lstrcmpW(buffW, strW), "Unexpected line data %s.\n", wine_dbgstr_w(buffW));
memset(buffW, 0, sizeof(buffW));
*(WORD *)buffW = sizeof(buffW)/sizeof(buffW[0]);
*(WORD *)buffW = ARRAY_SIZE(buffW);
r = SendMessageW(hwnd[i], EM_GETLINE, 1, (LPARAM)buffW);
ok(r == lstrlenW(strW), "Failed to get a line %d.\n", r);
ok(!lstrcmpW(buffW, strW), "Unexpected line data %s.\n", wine_dbgstr_w(buffW));
@ -3061,6 +3061,83 @@ static const struct message killfocus_combined_seq[] =
{ 0 }
};
static void test_cue_banner(void)
{
HWND hwnd_edit;
BOOL ret;
static WCHAR getcuetestW[5] = {'T',0};
static const WCHAR testcmp1W[] = {'T','e','s','t',0};
static const WCHAR testcmp2W[] = {'T','e','s',0};
static const WCHAR emptyW[] = {0};
hwnd_edit = create_editcontrolW(ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0);
ret = SendMessageW(hwnd_edit, EM_GETCUEBANNER, (WPARAM)getcuetestW, 5);
if (lstrcmpW(getcuetestW, emptyW) != 0)
{
win_skip("skipping for Win XP and 2003 Server.\n");
DestroyWindow(hwnd_edit);
return;
}
ok(lstrcmpW(getcuetestW, emptyW) == 0, "First char is %c\n", getcuetestW[0]);
ok(ret == FALSE, "EM_GETCUEBANNER should have returned FALSE.\n");
lstrcpyW(getcuetestW, testcmp1W);
ret = SendMessageW(hwnd_edit, EM_GETCUEBANNER, (WPARAM)getcuetestW, 0);
ok(lstrcmpW(getcuetestW, testcmp1W) == 0, "String was %s.\n", wine_dbgstr_w(getcuetestW));
ok(ret == FALSE, "EM_GETCUEBANNER should have returned FALSE.\n");
ret = SendMessageW(hwnd_edit, EM_GETCUEBANNER, 0, 0);
ok(ret == FALSE, "EM_GETCUEBANNER should have returned FALSE.\n");
ret = SendMessageW(hwnd_edit, EM_SETCUEBANNER, 0, 0);
ok(ret == FALSE, "EM_SETCUEBANNER should have returned FALSE.\n");
ret = SendMessageW(hwnd_edit, EM_GETCUEBANNER, 0, 0);
ok(ret == FALSE, "EM_GETCUEBANNER should have returned FALSE.\n");
lstrcpyW(getcuetestW, testcmp1W);
ret = SendMessageW(hwnd_edit, EM_SETCUEBANNER, 0, (LPARAM)getcuetestW);
ok(ret == TRUE, "EM_SETCUEBANNER should have returned TRUE.\n");
ret = SendMessageW(hwnd_edit, EM_GETCUEBANNER, 0, 5);
ok(ret == TRUE, "EM_GETCUEBANNER should have returned TRUE.\n");
ret = SendMessageW(hwnd_edit, EM_GETCUEBANNER, (WPARAM)getcuetestW, 5);
ok(ret == TRUE, "EM_GETCUEBANNER should have returned TRUE.\n");
ok(lstrcmpW(getcuetestW, testcmp1W) == 0, "EM_GETCUEBANNER returned string %s.\n", wine_dbgstr_w(getcuetestW));
ret = SendMessageW(hwnd_edit, EM_SETCUEBANNER, 0, (LPARAM)emptyW);
ok(ret == TRUE, "EM_SETCUEBANNER should have returned TRUE.\n");
ret = SendMessageW(hwnd_edit, EM_GETCUEBANNER, (WPARAM)getcuetestW, 5);
ok(ret == TRUE, "EM_GETCUEBANNER should have returned TRUE.\n");
ok(lstrcmpW(getcuetestW, emptyW) == 0, "EM_GETCUEBANNER returned string %s.\n", wine_dbgstr_w(getcuetestW));
/* EM_GETCUEBANNER's buffer size includes null char */
ret = SendMessageW(hwnd_edit, EM_SETCUEBANNER, 0, (LPARAM)testcmp1W);
ok(ret == TRUE, "EM_SETCUEBANNER should have returned TRUE.\n");
memset(getcuetestW, 0, lstrlenW(testcmp1W)*sizeof(WCHAR));
ret = SendMessageW(hwnd_edit, EM_GETCUEBANNER, (WPARAM)getcuetestW, (LPARAM)lstrlenW(testcmp1W)+1);
ok(ret == TRUE, "EM_GETCUEBANNER should have returned TRUE.\n");
ok(lstrcmpW(getcuetestW, testcmp1W) == 0, "EM_GETCUEBANNER returned string %s.\n", wine_dbgstr_w(getcuetestW));
memset(getcuetestW, 0, lstrlenW(testcmp1W)*sizeof(WCHAR));
ret = SendMessageW(hwnd_edit, EM_GETCUEBANNER, (WPARAM)getcuetestW, (LPARAM)lstrlenW(testcmp1W));
ok(lstrcmpW(getcuetestW, testcmp2W) == 0, "EM_GETCUEBANNER returned string %s.\n", wine_dbgstr_w(getcuetestW));
DestroyWindow(hwnd_edit);
/* setting cue banner fails for multi-line edit controls */
hwnd_edit = create_editcontrolW(ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_MULTILINE, 0);
lstrcpyW(getcuetestW, testcmp1W);
ret = SendMessageW(hwnd_edit, EM_GETCUEBANNER, (WPARAM)getcuetestW, 5);
ok(ret == FALSE, "EM_SETCUEBANNER.\n");
ok(lstrcmpW(getcuetestW, testcmp1W) == 0, "String was %s.\n", wine_dbgstr_w(getcuetestW));
ret = SendMessageW(hwnd_edit, EM_SETCUEBANNER, 0, (LPARAM)getcuetestW);
ok(ret == FALSE, "EM_SETCUEBANNER.\n");
DestroyWindow(hwnd_edit);
}
static void test_change_focus(void)
{
HWND hwnd, parent_wnd;
@ -3138,6 +3215,7 @@ START_TEST(edit)
test_EM_GETLINE();
test_wordbreak_proc();
test_change_focus();
test_cue_banner();
UnregisterWindowClasses();

View file

@ -1130,7 +1130,7 @@ static void test_hdm_index_messages(HWND hParent)
ok_sequence(sequences, PARENT_SEQ_INDEX, add_header_to_parent_seq,
"adder header control to parent", FALSE);
flush_sequences(sequences, NUM_MSG_SEQUENCES);
for (i = 0; i < sizeof(item_texts)/sizeof(item_texts[0]); i++)
for (i = 0; i < ARRAY_SIZE(item_texts); i++)
{
hdItem.mask = HDI_TEXT | HDI_WIDTH | HDI_FORMAT;
hdItem.pszText = (char*)item_texts[i];
@ -1170,7 +1170,7 @@ static void test_hdm_index_messages(HWND hParent)
hdItem.mask = HDI_TEXT | HDI_WIDTH;
hdItem.pszText = buffA;
hdItem.cchTextMax = sizeof(buffA)/sizeof(buffA[0]);
hdItem.cchTextMax = ARRAY_SIZE(buffA);
retVal = SendMessageA(hChild, HDM_GETITEMA, 0, (LPARAM) &hdItem);
ok(retVal == TRUE, "Getting the 1st header item should return TRUE, got %d\n", retVal);

View file

@ -922,7 +922,6 @@ static void check_ilhead_data(const ILHEAD *ilh, INT cx, INT cy, INT cur, INT ma
}
else
{
grow = (WORD)(grow + 3) & ~3;
ok(ilh->cMaxImage == max, "wrong cMaxImage %d (expected %d)\n", ilh->cMaxImage, max);
ok(ilh->cGrow == grow_aligned, "Unexpected cGrow %d, expected %d\n", ilh->cGrow, grow_aligned);
}
@ -1100,7 +1099,7 @@ static void image_list_init(HIMAGELIST himl, INT grow)
check_iml_data(himl, BMP_CX, BMP_CX, 0, 2, grow, ILC_COLOR24, "total 0");
for (i = 0; i < sizeof(td)/sizeof(td[0]); i++)
for (i = 0; i < ARRAY_SIZE(td); i++)
{
image_list_add_bitmap(himl, td[i].grey, i + 1);
check_iml_data(himl, td[i].cx, td[i].cy, td[i].cur, td[i].max, grow, td[i].bpp, td[i].comment);
@ -2029,7 +2028,11 @@ static void check_color_table(const char *name, HDC hdc, HIMAGELIST himl, UINT i
{
IMAGEINFO info;
INT ret;
#ifdef __REACTOS__
char bmi_buffer[FIELD_OFFSET(BITMAPINFO, bmiColors) + 256 * sizeof(RGBQUAD)];
#else
char bmi_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
#endif
BITMAPINFO *bmi = (BITMAPINFO *)bmi_buffer;
int i, depth = ilc & 0xfe;
@ -2061,7 +2064,11 @@ static void check_color_table(const char *name, HDC hdc, HIMAGELIST himl, UINT i
static void get_default_color_table(HDC hdc, int bpp, RGBQUAD *table)
{
#ifdef __REACTOS__
char bmi_buffer[FIELD_OFFSET(BITMAPINFO, bmiColors) + 256 * sizeof(RGBQUAD)];
#else
char bmi_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
#endif
BITMAPINFO *bmi = (BITMAPINFO *)bmi_buffer;
HBITMAP tmp;
int i;
@ -2109,7 +2116,11 @@ static void test_color_table(UINT ilc)
{
HIMAGELIST himl;
INT ret;
#ifdef __REACTOS__
char bmi_buffer[FIELD_OFFSET(BITMAPINFO, bmiColors) + 256 * sizeof(RGBQUAD)];
#else
char bmi_buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
#endif
BITMAPINFO *bmi = (BITMAPINFO *)bmi_buffer;
HDC hdc = CreateCompatibleDC(0);
HBITMAP dib4, dib8, dib32;

View file

@ -50,12 +50,12 @@ static void test_get_set_text(void)
}
/* check text just after creation */
r = GetWindowTextA(hwnd, ip, sizeof(ip)/sizeof(CHAR));
r = GetWindowTextA(hwnd, ip, ARRAY_SIZE(ip));
expect(7, r);
ok(strcmp(ip, "0.0.0.0") == 0, "Expected null IP address, got %s\n", ip);
SendMessageA(hwnd, IPM_SETADDRESS, 0, MAKEIPADDRESS(127, 0, 0, 1));
r = GetWindowTextA(hwnd, ip, sizeof(ip)/sizeof(CHAR));
r = GetWindowTextA(hwnd, ip, ARRAY_SIZE(ip));
expect(9, r);
ok(strcmp(ip, "127.0.0.1") == 0, "Expected 127.0.0.1, got %s\n", ip);

View file

@ -30,6 +30,52 @@
#include "wine/heap.h"
#include "wine/test.h"
#include "v6util.h"
#include "msg.h"
enum seq_index
{
LB_SEQ_INDEX,
PARENT_SEQ_INDEX,
NUM_MSG_SEQUENCES
};
static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
/* encoded MEASUREITEMSTRUCT into a WPARAM */
typedef struct
{
union
{
struct
{
UINT CtlType : 4;
UINT CtlID : 4;
UINT itemID : 4;
UINT wParam : 20;
} item;
WPARAM wp;
} u;
} MEASURE_ITEM_STRUCT;
static unsigned hash_Ly_W(const WCHAR *str)
{
unsigned hash = 0;
for (; *str; str++)
hash = hash * 1664525u + (unsigned char)(*str) + 1013904223u;
return hash;
}
static unsigned hash_Ly(const char *str)
{
unsigned hash = 0;
for (; *str; str++)
hash = hash * 1664525u + (unsigned char)(*str) + 1013904223u;
return hash;
}
static const char * const strings[4] = {
"First added",
@ -43,22 +89,53 @@ static const char * const strings[4] = {
static const char BAD_EXTENSION[] = "*.badtxt";
static int strcmp_aw(LPCWSTR strw, const char *stra)
{
WCHAR buf[1024];
#define ID_LISTBOX 1
if (!stra) return 1;
MultiByteToWideChar(CP_ACP, 0, stra, -1, buf, sizeof(buf)/sizeof(WCHAR));
return lstrcmpW(strw, buf);
static LRESULT WINAPI listbox_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
static LONG defwndproc_counter = 0;
struct message msg = { 0 };
LRESULT ret;
switch (message)
{
case WM_SIZE:
case WM_GETTEXT:
case WM_PAINT:
case WM_ERASEBKGND:
case WM_WINDOWPOSCHANGING:
case WM_WINDOWPOSCHANGED:
case WM_NCCALCSIZE:
case WM_NCPAINT:
case WM_NCHITTEST:
case WM_DEVICECHANGE:
break;
default:
msg.message = message;
msg.flags = sent|wparam|lparam;
if (defwndproc_counter) msg.flags |= defwinproc;
msg.wParam = wParam;
msg.lParam = lParam;
add_message(sequences, LB_SEQ_INDEX, &msg);
}
defwndproc_counter++;
ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
defwndproc_counter--;
return ret;
}
static HWND create_listbox(DWORD add_style, HWND parent)
{
INT_PTR ctl_id = 0;
WNDPROC oldproc;
HWND handle;
if (parent)
ctl_id=1;
ctl_id = ID_LISTBOX;
handle = CreateWindowA(WC_LISTBOXA, "TestList", (LBS_STANDARD & ~LBS_SORT) | add_style, 0, 0, 100, 100,
parent, (HMENU)ctl_id, NULL, 0);
@ -69,6 +146,9 @@ static HWND create_listbox(DWORD add_style, HWND parent)
SendMessageA(handle, LB_ADDSTRING, 0, (LPARAM) strings[2]);
SendMessageA(handle, LB_ADDSTRING, 0, (LPARAM) strings[3]);
oldproc = (WNDPROC)SetWindowLongPtrA(handle, GWLP_WNDPROC, (LONG_PTR)listbox_wnd_proc);
SetWindowLongPtrA(handle, GWLP_USERDATA, (LONG_PTR)oldproc);
return handle;
}
@ -84,7 +164,6 @@ struct listbox_stat
struct listbox_test
{
struct listbox_prop prop;
struct listbox_stat init, init_todo;
struct listbox_stat click, click_todo;
struct listbox_stat step, step_todo;
@ -117,8 +196,7 @@ static void keypress(HWND handle, WPARAM keycode, BYTE scancode, BOOL extended)
#define listbox_field_ok(t, s, f, got) \
ok (t.s.f==got.f, "style %#x, step " #s ", field " #f \
": expected %d, got %d\n", (unsigned int)t.prop.add_style, \
t.s.f, got.f)
": expected %d, got %d\n", style, t.s.f, got.f)
#define listbox_todo_field_ok(t, s, f, got) \
todo_wine_if (t.s##_todo.f) { listbox_field_ok(t, s, f, got); }
@ -129,12 +207,23 @@ static void keypress(HWND handle, WPARAM keycode, BYTE scancode, BOOL extended)
listbox_todo_field_ok(t, s, caret, got); \
listbox_todo_field_ok(t, s, selcount, got)
static void run_test(const struct listbox_test test)
static void run_test(DWORD style, const struct listbox_test test)
{
static const struct message delete_seq[] =
{
{ LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
{ LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
{ LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
{ LB_DELETESTRING, sent|wparam|lparam, 0, 0 },
{ LB_RESETCONTENT, sent|wparam|lparam|defwinproc, 0, 0 },
{ 0 }
};
struct listbox_stat answer;
HWND hLB=create_listbox (test.prop.add_style, 0);
int i, res, count;
RECT second_item;
int i, res;
HWND hLB;
hLB = create_listbox (style, 0);
listbox_query (hLB, &answer);
listbox_ok (test, init, answer);
@ -152,13 +241,13 @@ static void run_test(const struct listbox_test test)
DestroyWindow(hLB);
hLB = create_listbox(test.prop.add_style, 0);
hLB = create_listbox(style, 0);
SendMessageA(hLB, LB_SELITEMRANGE, TRUE, MAKELPARAM(1, 2));
listbox_query(hLB, &answer);
listbox_ok(test, sel, answer);
for (i = 0; i < 4; i++)
for (i = 0; i < 4 && !(style & LBS_NODATA); i++)
{
DWORD size = SendMessageA(hLB, LB_GETTEXTLEN, i, 0);
int resA, resW;
@ -171,13 +260,9 @@ static void run_test(const struct listbox_test test)
txtw = heap_alloc_zero((size + 1) * sizeof(*txtw));
resW = SendMessageW(hLB, LB_GETTEXT, i, (LPARAM)txtw);
if (resA != resW)
trace("SendMessageW(LB_GETTEXT) not supported on this platform (resA=%d resW=%d), skipping...\n", resA, resW);
else
{
WideCharToMultiByte(CP_ACP, 0, txtw, -1, txt, size, NULL, NULL);
ok(!strcmp (txt, strings[i]), "returned string for item %d does not match %s vs %s\n", i, txt, strings[i]);
}
ok(resA == resW, "Unexpected text length.\n");
WideCharToMultiByte(CP_ACP, 0, txtw, -1, txt, size, NULL, NULL);
ok(!strcmp (txt, strings[i]), "Unexpected string for item %d, %s vs %s.\n", i, txt, strings[i]);
heap_free(txtw);
heap_free(txt);
@ -190,8 +275,17 @@ static void run_test(const struct listbox_test test)
ok(res == LB_ERR, "Expected LB_ERR items, got %d\n", res);
res = SendMessageA(hLB, LB_DELETESTRING, 4, 0);
ok(res == LB_ERR, "Expected LB_ERR items, got %d\n", res);
res = SendMessageA(hLB, LB_GETCOUNT, 0, 0);
ok(res == 4, "Expected 4 items, got %d\n", res);
count = SendMessageA(hLB, LB_GETCOUNT, 0, 0);
ok(count == 4, "Unexpected item count %d.\n", count);
/* Emptying listbox sends a LB_RESETCONTENT to itself. */
flush_sequence(sequences, LB_SEQ_INDEX);
for (i = count; i--;)
{
res = SendMessageA(hLB, LB_DELETESTRING, 0, 0);
ok(res == i, "Unexpected return value %d.\n", res);
}
ok_sequence(sequences, LB_SEQ_INDEX, delete_seq, "Emptying listbox", FALSE);
DestroyWindow(hLB);
}
@ -234,41 +328,85 @@ static void test_item_height(void)
static int got_selchange;
static LRESULT WINAPI main_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
static LRESULT WINAPI main_window_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static LONG defwndproc_counter = 0;
struct message m = { 0 };
LRESULT ret;
m.message = msg;
m.flags = sent|wparam|lparam;
if (defwndproc_counter) m.flags |= defwinproc;
m.wParam = wParam;
m.lParam = lParam;
switch (msg)
{
case WM_MEASUREITEM:
{
DWORD style = GetWindowLongA(GetWindow(hwnd, GW_CHILD), GWL_STYLE);
MEASUREITEMSTRUCT *mi = (void*)lparam;
MEASUREITEMSTRUCT *mis = (void *)lParam;
BOOL is_unicode_data = FALSE;
MEASURE_ITEM_STRUCT mi;
ok(wparam == mi->CtlID, "got wParam=%08lx, expected %08x\n", wparam, mi->CtlID);
ok(mi->CtlType == ODT_LISTBOX, "mi->CtlType = %u\n", mi->CtlType);
ok(mi->CtlID == 1, "mi->CtlID = %u\n", mi->CtlID);
ok(mi->itemHeight, "mi->itemHeight = 0\n");
if (mi->itemID > 4 || style & LBS_OWNERDRAWFIXED)
break;
if (style & LBS_HASSTRINGS)
if (mis->CtlType == ODT_LISTBOX)
{
ok(!strcmp_aw((WCHAR*)mi->itemData, strings[mi->itemID]),
"mi->itemData = %s (%d)\n", wine_dbgstr_w((WCHAR*)mi->itemData), mi->itemID);
HWND ctrl = GetDlgItem(hwnd, mis->CtlID);
is_unicode_data = GetWindowLongA(ctrl, GWL_STYLE) & LBS_HASSTRINGS;
}
mi.u.wp = 0;
mi.u.item.CtlType = mis->CtlType;
mi.u.item.CtlID = mis->CtlID;
mi.u.item.itemID = mis->itemID;
mi.u.item.wParam = wParam;
m.wParam = mi.u.wp;
if (is_unicode_data)
m.lParam = mis->itemData ? hash_Ly_W((const WCHAR *)mis->itemData) : 0;
else
m.lParam = mis->itemData ? hash_Ly((const char *)mis->itemData) : 0;
add_message(sequences, PARENT_SEQ_INDEX, &m);
ok(wParam == mis->CtlID, "got wParam=%08lx, expected %08x\n", wParam, mis->CtlID);
ok(mis->CtlType == ODT_LISTBOX, "mi->CtlType = %u\n", mis->CtlType);
ok(mis->CtlID == 1, "mi->CtlID = %u\n", mis->CtlID);
ok(mis->itemHeight, "mi->itemHeight = 0\n");
break;
}
case WM_COMPAREITEM:
{
COMPAREITEMSTRUCT *cis = (COMPAREITEMSTRUCT *)lParam;
HWND ctrl = GetDlgItem(hwnd, cis->CtlID);
BOOL is_unicode_data = TRUE;
ok(wParam == cis->CtlID, "expected %#x, got %#lx\n", cis->CtlID, wParam);
ok(cis->hwndItem == ctrl, "expected %p, got %p\n", ctrl, cis->hwndItem);
ok((int)cis->itemID1 >= 0, "expected >= 0, got %d\n", cis->itemID1);
ok((int)cis->itemID2 == -1, "expected -1, got %d\n", cis->itemID2);
if (cis->CtlType == ODT_LISTBOX)
is_unicode_data = GetWindowLongA(ctrl, GWL_STYLE) & LBS_HASSTRINGS;
if (is_unicode_data)
{
m.wParam = cis->itemData1 ? hash_Ly_W((const WCHAR *)cis->itemData1) : 0;
m.lParam = cis->itemData2 ? hash_Ly_W((const WCHAR *)cis->itemData2) : 0;
}
else
{
ok((void*)mi->itemData == strings[mi->itemID],
"mi->itemData = %08lx, expected %p\n", mi->itemData, strings[mi->itemID]);
m.wParam = cis->itemData1 ? hash_Ly((const char *)cis->itemData1) : 0;
m.lParam = cis->itemData2 ? hash_Ly((const char *)cis->itemData2) : 0;
}
add_message(sequences, PARENT_SEQ_INDEX, &m);
break;
}
case WM_DRAWITEM:
{
RECT rc_item, rc_client, rc_clip;
DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)lparam;
DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)lParam;
ok(wparam == dis->CtlID, "got wParam=%08lx instead of %08x\n", wparam, dis->CtlID);
ok(wParam == dis->CtlID, "got wParam=%08lx instead of %08x\n", wParam, dis->CtlID);
ok(dis->CtlType == ODT_LISTBOX, "wrong CtlType %04x\n", dis->CtlType);
GetClientRect(dis->hwndItem, &rc_client);
@ -284,14 +422,18 @@ static LRESULT WINAPI main_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARA
}
case WM_COMMAND:
if (HIWORD( wparam ) == LBN_SELCHANGE) got_selchange++;
if (HIWORD( wParam ) == LBN_SELCHANGE) got_selchange++;
break;
default:
break;
}
return DefWindowProcA(hwnd, msg, wparam, lparam);
defwndproc_counter++;
ret = DefWindowProcA(hwnd, msg, wParam, lParam);
defwndproc_counter--;
return msg == WM_COMPAREITEM ? -1 : ret;
}
static HWND create_parent( void )
@ -320,33 +462,72 @@ static HWND create_parent( void )
static void test_ownerdraw(void)
{
static const DWORD styles[] =
{
0,
LBS_NODATA
};
HWND parent, hLB;
INT ret;
RECT rc;
UINT i;
parent = create_parent();
ok(parent != NULL, "Failed to create parent window.\n");
hLB = create_listbox(LBS_OWNERDRAWFIXED | WS_CHILD | WS_VISIBLE, parent);
ok(hLB != NULL, "Failed to create listbox window.\n");
for (i = 0; i < ARRAY_SIZE(styles); i++)
{
hLB = create_listbox(LBS_OWNERDRAWFIXED | WS_CHILD | WS_VISIBLE | styles[i], parent);
ok(hLB != NULL, "Failed to create listbox window.\n");
SetForegroundWindow(hLB);
UpdateWindow(hLB);
SetForegroundWindow(hLB);
UpdateWindow(hLB);
/* make height short enough */
SendMessageA(hLB, LB_GETITEMRECT, 0, (LPARAM)&rc);
SetWindowPos(hLB, 0, 0, 0, 100, rc.bottom - rc.top + 1, SWP_NOZORDER | SWP_NOMOVE);
/* make height short enough */
SendMessageA(hLB, LB_GETITEMRECT, 0, (LPARAM)&rc);
SetWindowPos(hLB, 0, 0, 0, 100, rc.bottom - rc.top + 1, SWP_NOZORDER | SWP_NOMOVE);
/* make 0 item invisible */
SendMessageA(hLB, LB_SETTOPINDEX, 1, 0);
ret = SendMessageA(hLB, LB_GETTOPINDEX, 0, 0);
ok(ret == 1, "wrong top index %d\n", ret);
/* make 0 item invisible */
SendMessageA(hLB, LB_SETTOPINDEX, 1, 0);
ret = SendMessageA(hLB, LB_GETTOPINDEX, 0, 0);
ok(ret == 1, "wrong top index %d\n", ret);
SendMessageA(hLB, LB_GETITEMRECT, 0, (LPARAM)&rc);
ok(!IsRectEmpty(&rc), "empty item rect\n");
ok(rc.top < 0, "rc.top is not negative (%d)\n", rc.top);
SendMessageA(hLB, LB_GETITEMRECT, 0, (LPARAM)&rc);
ok(!IsRectEmpty(&rc), "empty item rect\n");
ok(rc.top < 0, "rc.top is not negative (%d)\n", rc.top);
DestroyWindow(hLB);
/* Both FIXED and VARIABLE, FIXED should override VARIABLE. */
hLB = CreateWindowA(WC_LISTBOXA, "TestList", LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE | styles[i],
0, 0, 100, 100, NULL, NULL, NULL, 0);
ok(hLB != NULL, "last error 0x%08x\n", GetLastError());
ok(GetWindowLongA(hLB, GWL_STYLE) & LBS_OWNERDRAWVARIABLE, "Unexpected window style.\n");
ret = SendMessageA(hLB, LB_INSERTSTRING, -1, 0);
ok(ret == 0, "Unexpected return value %d.\n", ret);
ret = SendMessageA(hLB, LB_INSERTSTRING, -1, 0);
ok(ret == 1, "Unexpected return value %d.\n", ret);
ret = SendMessageA(hLB, LB_SETITEMHEIGHT, 0, 13);
ok(ret == LB_OKAY, "Failed to set item height, %d.\n", ret);
ret = SendMessageA(hLB, LB_GETITEMHEIGHT, 0, 0);
ok(ret == 13, "Unexpected item height %d.\n", ret);
ret = SendMessageA(hLB, LB_SETITEMHEIGHT, 1, 42);
ok(ret == LB_OKAY, "Failed to set item height, %d.\n", ret);
ret = SendMessageA(hLB, LB_GETITEMHEIGHT, 0, 0);
ok(ret == 42, "Unexpected item height %d.\n", ret);
ret = SendMessageA(hLB, LB_GETITEMHEIGHT, 1, 0);
ok(ret == 42, "Unexpected item height %d.\n", ret);
DestroyWindow (hLB);
}
DestroyWindow(hLB);
DestroyWindow(parent);
}
@ -447,17 +628,121 @@ static void test_LB_SETCURSEL(void)
SendMessageA(hLB, LB_SETITEMHEIGHT, 0, 32);
ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0);
ok(ret == -1, "Unexpected anchor index %d.\n", ret);
ret = SendMessageA(hLB, LB_SETCURSEL, 2, 0);
ok(ret == 2, "LB_SETCURSEL returned %d instead of 2\n", ret);
ret = GetScrollPos(hLB, SB_VERT);
ok(ret == 0, "expected vscroll 0, got %d\n", ret);
ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0);
ok(ret == -1, "Unexpected anchor index %d.\n", ret);
ret = SendMessageA(hLB, LB_SETCURSEL, 3, 0);
ok(ret == 3, "LB_SETCURSEL returned %d instead of 3\n", ret);
ret = GetScrollPos(hLB, SB_VERT);
ok(ret == 1, "expected vscroll 1, got %d\n", ret);
ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0);
ok(ret == -1, "Unexpected anchor index %d.\n", ret);
DestroyWindow(hLB);
hLB = create_listbox(0, 0);
ok(hLB != NULL, "Failed to create ListBox window.\n");
ret = SendMessageA(hLB, LB_SETCURSEL, 1, 0);
ok(ret == 1, "Unexpected return value %d.\n", ret);
ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0);
ok(ret == -1, "Unexpected anchor index %d.\n", ret);
DestroyWindow(hLB);
/* LBS_EXTENDEDSEL */
hLB = create_listbox(LBS_EXTENDEDSEL, 0);
ok(hLB != NULL, "Failed to create listbox.\n");
ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0);
ok(ret == -1, "Unexpected anchor index %d.\n", ret);
ret = SendMessageA(hLB, LB_SETCURSEL, 2, 0);
ok(ret == -1, "LB_SETCURSEL returned %d instead of 2\n", ret);
ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0);
ok(ret == -1, "Unexpected anchor index %d.\n", ret);
DestroyWindow(hLB);
/* LBS_MULTIPLESEL */
hLB = create_listbox(LBS_MULTIPLESEL, 0);
ok(hLB != NULL, "Failed to create listbox.\n");
ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0);
ok(ret == -1, "Unexpected anchor index %d.\n", ret);
ret = SendMessageA(hLB, LB_SETCURSEL, 2, 0);
ok(ret == -1, "LB_SETCURSEL returned %d instead of 2\n", ret);
ret = SendMessageA(hLB, LB_GETANCHORINDEX, 0, 0);
ok(ret == -1, "Unexpected anchor index %d.\n", ret);
DestroyWindow(hLB);
}
static void test_LB_SETSEL(void)
{
HWND list;
int ret;
/* LBS_EXTENDEDSEL */
list = create_listbox(LBS_EXTENDEDSEL, 0);
ok(list != NULL, "Failed to create ListBox window.\n");
ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0);
ok(ret == -1, "Unexpected anchor index %d.\n", ret);
ret = SendMessageA(list, LB_SETSEL, TRUE, 0);
ok(ret == 0, "Unexpected return value %d.\n", ret);
ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0);
ok(ret == 0, "Unexpected anchor index %d.\n", ret);
ret = SendMessageA(list, LB_SETSEL, TRUE, 1);
ok(ret == 0, "Unexpected return value %d.\n", ret);
ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0);
ok(ret == 1, "Unexpected anchor index %d.\n", ret);
ret = SendMessageA(list, LB_SETSEL, FALSE, 1);
ok(ret == 0, "Unexpected return value %d.\n", ret);
ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0);
ok(ret == 1, "Unexpected anchor index %d.\n", ret);
DestroyWindow(list);
/* LBS_MULTIPLESEL */
list = create_listbox(LBS_MULTIPLESEL, 0);
ok(list != NULL, "Failed to create ListBox window.\n");
ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0);
ok(ret == -1, "Unexpected anchor index %d.\n", ret);
ret = SendMessageA(list, LB_SETSEL, TRUE, 0);
ok(ret == 0, "Unexpected return value %d.\n", ret);
ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0);
ok(ret == 0, "Unexpected anchor index %d.\n", ret);
ret = SendMessageA(list, LB_SETSEL, TRUE, 1);
ok(ret == 0, "Unexpected return value %d.\n", ret);
ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0);
ok(ret == 1, "Unexpected anchor index %d.\n", ret);
ret = SendMessageA(list, LB_SETSEL, FALSE, 1);
ok(ret == 0, "Unexpected return value %d.\n", ret);
ret = SendMessageA(list, LB_GETANCHORINDEX, 0, 0);
ok(ret == 1, "Unexpected anchor index %d.\n", ret);
DestroyWindow(list);
}
static void test_listbox_height(void)
@ -603,6 +888,7 @@ static void test_listbox_item_data(void)
static void test_listbox_LB_DIR(void)
{
char path[MAX_PATH], curdir[MAX_PATH];
HWND hList;
int res, itemCount;
int itemCount_justFiles;
@ -615,6 +901,16 @@ static void test_listbox_LB_DIR(void)
char driveletter;
const char *wildcard = "*";
HANDLE file;
BOOL ret;
GetCurrentDirectoryA(ARRAY_SIZE(curdir), curdir);
GetTempPathA(ARRAY_SIZE(path), path);
ret = SetCurrentDirectoryA(path);
ok(ret, "Failed to set current directory.\n");
ret = CreateDirectoryA("lb_dir_test", NULL);
ok(ret, "Failed to create test directory.\n");
file = CreateFileA( "wtest1.tmp.c", GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL );
ok(file != INVALID_HANDLE_VALUE, "Error creating the test file: %d\n", GetLastError());
@ -945,11 +1241,11 @@ static void test_listbox_LB_DIR(void)
itemCount, itemCount_allDirs);
ok(res + 1 == itemCount, "SendMessage(LB_DIR, DDL_DIRECTORY|DDL_EXCLUSIVE, *) returned incorrect index!\n");
if (itemCount && GetCurrentDirectoryA( MAX_PATH, pathBuffer ) > 3) /* there's no [..] in drive root */
if (itemCount)
{
memset(pathBuffer, 0, MAX_PATH);
SendMessageA(hList, LB_GETTEXT, 0, (LPARAM)pathBuffer);
ok( !strcmp(pathBuffer, "[..]"), "First element is not [..]\n");
ok( !strcmp(pathBuffer, "[..]"), "First element is %s, not [..]\n", pathBuffer);
}
/* This tests behavior when no files match the wildcard */
@ -1034,6 +1330,9 @@ static void test_listbox_LB_DIR(void)
DestroyWindow(hList);
DeleteFileA( "wtest1.tmp.c" );
RemoveDirectoryA("lb_dir_test");
SetCurrentDirectoryA(curdir);
}
static HWND g_listBox;
@ -1533,7 +1832,13 @@ static void test_listbox_dlgdir(void)
static void test_set_count( void )
{
static const DWORD styles[] =
{
LBS_OWNERDRAWFIXED,
LBS_HASSTRINGS,
};
HWND parent, listbox;
unsigned int i;
LONG ret;
RECT r;
@ -1563,37 +1868,39 @@ static void test_set_count( void )
ok( !IsRectEmpty( &r ), "got empty rect\n");
DestroyWindow( listbox );
for (i = 0; i < ARRAY_SIZE(styles); ++i)
{
listbox = create_listbox( styles[i] | WS_CHILD | WS_VISIBLE, parent );
SetLastError( 0xdeadbeef );
ret = SendMessageA( listbox, LB_SETCOUNT, 100, 0 );
ok( ret == LB_ERR, "expected %d, got %d\n", LB_ERR, ret );
ok( GetLastError() == 0xdeadbeef, "Unexpected error %d.\n", GetLastError() );
DestroyWindow( listbox );
}
DestroyWindow( parent );
}
static int lb_getlistboxinfo;
static LRESULT WINAPI listbox_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
if (message == LB_GETLISTBOXINFO)
lb_getlistboxinfo++;
return CallWindowProcA(oldproc, hwnd, message, wParam, lParam);
}
static void test_GetListBoxInfo(void)
{
static const struct message getlistboxinfo_seq[] =
{
{ LB_GETLISTBOXINFO, sent },
{ 0 }
};
HWND listbox, parent;
WNDPROC oldproc;
DWORD ret;
parent = create_parent();
listbox = create_listbox(WS_CHILD | WS_VISIBLE, parent);
oldproc = (WNDPROC)SetWindowLongPtrA(listbox, GWLP_WNDPROC, (LONG_PTR)listbox_subclass_proc);
SetWindowLongPtrA(listbox, GWLP_USERDATA, (LONG_PTR)oldproc);
lb_getlistboxinfo = 0;
flush_sequences(sequences, NUM_MSG_SEQUENCES);
ret = GetListBoxInfo(listbox);
ok(ret > 0, "got %d\n", ret);
ok(lb_getlistboxinfo == 1, "got %d\n", lb_getlistboxinfo);
ok_sequence(sequences, LB_SEQ_INDEX, getlistboxinfo_seq, "GetListBoxInfo()", FALSE);
DestroyWindow(listbox);
DestroyWindow(parent);
@ -1805,76 +2112,101 @@ static void test_listbox(void)
{
static const struct listbox_test SS =
/* {add_style} */
{{0},
{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
{{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
{ 1, 1, 1, LB_ERR}, {0,0,0,0},
{ 2, 2, 2, LB_ERR}, {0,0,0,0},
{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
/* {selected, anchor, caret, selcount}{TODO fields} */
static const struct listbox_test SS_NS =
{{LBS_NOSEL},
{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
{{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
{ 1, 1, 1, LB_ERR}, {0,0,0,0},
{ 2, 2, 2, LB_ERR}, {0,0,0,0},
{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
static const struct listbox_test MS =
{{LBS_MULTIPLESEL},
{ 0, LB_ERR, 0, 0}, {0,0,0,0},
{{ 0, LB_ERR, 0, 0}, {0,0,0,0},
{ 1, 1, 1, 1}, {0,0,0,0},
{ 2, 1, 2, 1}, {0,0,0,0},
{ 0, LB_ERR, 0, 2}, {0,0,0,0}};
static const struct listbox_test MS_NS =
{{LBS_MULTIPLESEL | LBS_NOSEL},
{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
{{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
{ 1, 1, 1, LB_ERR}, {0,0,0,0},
{ 2, 2, 2, LB_ERR}, {0,0,0,0},
{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
static const struct listbox_test ES =
{{LBS_EXTENDEDSEL},
{ 0, LB_ERR, 0, 0}, {0,0,0,0},
{{ 0, LB_ERR, 0, 0}, {0,0,0,0},
{ 1, 1, 1, 1}, {0,0,0,0},
{ 2, 2, 2, 1}, {0,0,0,0},
{ 0, LB_ERR, 0, 2}, {0,0,0,0}};
static const struct listbox_test ES_NS =
{{LBS_EXTENDEDSEL | LBS_NOSEL},
{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
{{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
{ 1, 1, 1, LB_ERR}, {0,0,0,0},
{ 2, 2, 2, LB_ERR}, {0,0,0,0},
{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
static const struct listbox_test EMS =
{{LBS_EXTENDEDSEL | LBS_MULTIPLESEL},
{ 0, LB_ERR, 0, 0}, {0,0,0,0},
{{ 0, LB_ERR, 0, 0}, {0,0,0,0},
{ 1, 1, 1, 1}, {0,0,0,0},
{ 2, 2, 2, 1}, {0,0,0,0},
{ 0, LB_ERR, 0, 2}, {0,0,0,0}};
static const struct listbox_test EMS_NS =
{{LBS_EXTENDEDSEL | LBS_MULTIPLESEL | LBS_NOSEL},
{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
{{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0},
{ 1, 1, 1, LB_ERR}, {0,0,0,0},
{ 2, 2, 2, LB_ERR}, {0,0,0,0},
{LB_ERR, LB_ERR, 0, LB_ERR}, {0,0,0,0}};
run_test(SS);
run_test(SS_NS);
run_test(MS);
run_test(MS_NS);
run_test(ES);
run_test(ES_NS);
run_test(EMS);
run_test(EMS_NS);
run_test(0, SS);
run_test(LBS_NOSEL, SS_NS);
run_test(LBS_MULTIPLESEL, MS);
run_test(LBS_MULTIPLESEL | LBS_NOSEL, MS_NS);
run_test(LBS_EXTENDEDSEL, ES);
run_test(LBS_EXTENDEDSEL | LBS_NOSEL, ES_NS);
run_test(LBS_EXTENDEDSEL | LBS_MULTIPLESEL, EMS);
run_test(LBS_EXTENDEDSEL | LBS_MULTIPLESEL | LBS_NOSEL, EMS_NS);
run_test(LBS_NODATA | LBS_OWNERDRAWFIXED, SS);
run_test(LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_NOSEL, SS_NS);
run_test(LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_MULTIPLESEL, MS);
run_test(LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_MULTIPLESEL | LBS_NOSEL, MS_NS);
run_test(LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_EXTENDEDSEL, ES);
run_test(LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_EXTENDEDSEL | LBS_NOSEL, ES_NS);
run_test(LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_EXTENDEDSEL | LBS_MULTIPLESEL, EMS);
run_test(LBS_NODATA | LBS_OWNERDRAWFIXED | LBS_EXTENDEDSEL | LBS_MULTIPLESEL | LBS_NOSEL, EMS_NS);
}
static const struct message lb_addstring_ownerdraw_parent_seq[] =
{
{ WM_MEASUREITEM, sent|wparam|lparam, 0x1012, 0xf30604ed },
{ WM_MEASUREITEM, sent|wparam|lparam, 0x1112, 0xf30604ee },
{ WM_MEASUREITEM, sent|wparam|lparam, 0x1212, 0xf30604ef },
{ 0 }
};
static const struct message lb_addstring_sort_parent_seq[] =
{
{ WM_MEASUREITEM, sent|wparam|lparam, 0x1012, 0xf30604ed },
{ WM_COMPAREITEM, sent|wparam|lparam, 0xf30604ed, 0xf30604ee },
{ WM_MEASUREITEM, sent|wparam|lparam, 0x1112, 0xf30604ee },
{ WM_COMPAREITEM, sent|wparam|lparam, 0xf30604ed, 0xf30604ef },
{ WM_COMPAREITEM, sent|wparam|lparam, 0xf30604ee, 0xf30604ef },
{ WM_MEASUREITEM, sent|wparam|lparam, 0x1212, 0xf30604ef },
{ 0 }
};
static const struct message empty_seq[] =
{
{ 0 }
};
static void test_WM_MEASUREITEM(void)
{
HWND parent, listbox;
LRESULT data;
LRESULT data, ret;
parent = create_parent();
listbox = create_listbox(WS_CHILD | LBS_OWNERDRAWVARIABLE, parent);
@ -1888,6 +2220,187 @@ static void test_WM_MEASUREITEM(void)
data = SendMessageA(listbox, LB_GETITEMDATA, 0, 0);
ok(!data, "data = %08lx\n", data);
/* LBS_HASSTRINGS */
parent = create_parent();
listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, WC_LISTBOXA, NULL,
WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | WS_VISIBLE,
10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
flush_sequences(sequences, NUM_MSG_SEQUENCES);
ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
ok(ret == 0, "expected 0, got %ld\n", ret);
ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
ok(ret == 1, "expected 1, got %ld\n", ret);
ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
ok(ret == 2, "expected 2, got %ld\n", ret);
ok_sequence(sequences, PARENT_SEQ_INDEX, lb_addstring_ownerdraw_parent_seq,
"LB_ADDSTRING (LBS_HASSTRINGS, ownerdraw)", FALSE);
DestroyWindow(listbox);
/* LBS_SORT, no LBS_HASSTRINGS */
listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, WC_LISTBOXA, NULL,
WS_CHILD | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE | LBS_SORT | WS_VISIBLE,
10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
flush_sequences(sequences, NUM_MSG_SEQUENCES);
ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
ok(ret == 0, "expected 0, got %ld\n", ret);
ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
ok(ret == 1, "expected 1, got %ld\n", ret);
ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
ok(ret == 2, "expected 2, got %ld\n", ret);
ok_sequence(sequences, PARENT_SEQ_INDEX, lb_addstring_sort_parent_seq, "LB_ADDSTRING (LBS_SORT)", FALSE);
DestroyWindow(listbox);
/* LBS_HASSTRINGS */
listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, WC_LISTBOXA, NULL,
WS_CHILD | LBS_NOTIFY | LBS_HASSTRINGS | WS_VISIBLE,
10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
flush_sequences(sequences, NUM_MSG_SEQUENCES);
ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
ok(ret == 0, "expected 0, got %ld\n", ret);
ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
ok(ret == 1, "expected 1, got %ld\n", ret);
ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
ok(ret == 2, "expected 2, got %ld\n", ret);
ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "LB_ADDSTRING (LBS_HASSTRINGS)", FALSE);
DestroyWindow(listbox);
/* LBS_HASSTRINGS, LBS_SORT */
listbox = CreateWindowExA(WS_EX_NOPARENTNOTIFY, WC_LISTBOXA, NULL,
WS_CHILD | LBS_NOTIFY | LBS_HASSTRINGS | LBS_SORT | WS_VISIBLE,
10, 10, 80, 80, parent, (HMENU)ID_LISTBOX, 0, NULL);
flush_sequences(sequences, NUM_MSG_SEQUENCES);
ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 2");
ok(ret == 0, "expected 0, got %ld\n", ret);
ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 0");
ok(ret == 0, "expected 0, got %ld\n", ret);
ret = SendMessageA(listbox, LB_ADDSTRING, 0, (LPARAM)"item 1");
ok(ret == 1, "expected 1, got %ld\n", ret);
ok_sequence(sequences, PARENT_SEQ_INDEX, empty_seq, "LB_ADDSTRING (LBS_HASSTRINGS, LBS_SORT)", FALSE);
DestroyWindow(listbox);
DestroyWindow(parent);
}
static void test_LBS_NODATA(void)
{
static const DWORD invalid_styles[] =
{
0,
LBS_OWNERDRAWVARIABLE,
LBS_SORT,
LBS_HASSTRINGS,
LBS_OWNERDRAWFIXED | LBS_SORT,
LBS_OWNERDRAWFIXED | LBS_HASSTRINGS,
};
static const UINT invalid_idx[] = { -2, 2 };
static const UINT valid_idx[] = { 0, 1 };
static const ULONG_PTR zero_data;
HWND listbox, parent;
INT ret, text_len;
unsigned int i;
ULONG_PTR data;
BOOL is_wow64;
listbox = CreateWindowA(WC_LISTBOXA, "TestList", LBS_NODATA | LBS_OWNERDRAWFIXED | WS_VISIBLE,
0, 0, 100, 100, NULL, NULL, NULL, 0);
ok(listbox != NULL, "Failed to create ListBox window.\n");
ret = SendMessageA(listbox, LB_INSERTSTRING, -1, 0);
ok(ret == 0, "Unexpected return value %d.\n", ret);
ret = SendMessageA(listbox, LB_INSERTSTRING, -1, 0);
ok(ret == 1, "Unexpected return value %d.\n", ret);
ret = SendMessageA(listbox, LB_GETCOUNT, 0, 0);
ok(ret == 2, "Unexpected return value %d.\n", ret);
/* Invalid indices. */
for (i = 0; i < ARRAY_SIZE(invalid_idx); ++i)
{
ret = SendMessageA(listbox, LB_SETITEMDATA, invalid_idx[i], 42);
ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
ret = SendMessageA(listbox, LB_GETTEXTLEN, invalid_idx[i], 0);
ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
if (ret == LB_ERR)
{
ret = SendMessageA(listbox, LB_GETTEXT, invalid_idx[i], (LPARAM)&data);
ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
}
ret = SendMessageA(listbox, LB_GETITEMDATA, invalid_idx[i], 0);
ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
}
IsWow64Process(GetCurrentProcess(), &is_wow64);
#ifdef _WIN64
text_len = 8;
#else
text_len = is_wow64 ? 8 : 4;
#endif
/* Valid indices. */
for (i = 0; i < ARRAY_SIZE(valid_idx); ++i)
{
ret = SendMessageA(listbox, LB_SETITEMDATA, valid_idx[i], 42);
ok(ret == TRUE, "Unexpected return value %d.\n", ret);
ret = SendMessageA(listbox, LB_GETTEXTLEN, valid_idx[i], 0);
todo_wine_if(is_wow64)
ok(ret == text_len, "Unexpected return value %d.\n", ret);
memset(&data, 0xee, sizeof(data));
ret = SendMessageA(listbox, LB_GETTEXT, valid_idx[i], (LPARAM)&data);
ok(ret == sizeof(data), "Unexpected return value %d.\n", ret);
ok(!memcmp(&data, &zero_data, sizeof(data)), "Unexpected item data.\n");
ret = SendMessageA(listbox, LB_GETITEMDATA, valid_idx[i], 0);
ok(ret == 0, "Unexpected return value %d.\n", ret);
}
/* More messages that don't work with LBS_NODATA. */
ret = SendMessageA(listbox, LB_FINDSTRING, 1, 0);
ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
ret = SendMessageA(listbox, LB_FINDSTRING, 1, 42);
ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
ret = SendMessageA(listbox, LB_FINDSTRINGEXACT, 1, 0);
ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
ret = SendMessageA(listbox, LB_FINDSTRINGEXACT, 1, 42);
ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
ret = SendMessageA(listbox, LB_SELECTSTRING, 1, 0);
ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
ret = SendMessageA(listbox, LB_SELECTSTRING, 1, 42);
ok(ret == LB_ERR, "Unexpected return value %d.\n", ret);
DestroyWindow(listbox);
/* Invalid window style combinations. */
parent = create_parent();
ok(parent != NULL, "Failed to create parent window.\n");
for (i = 0; i < ARRAY_SIZE(invalid_styles); ++i)
{
DWORD style;
listbox = CreateWindowA(WC_LISTBOXA, "TestList", LBS_NODATA | WS_CHILD | invalid_styles[i],
0, 0, 100, 100, parent, (HMENU)ID_LISTBOX, NULL, 0);
ok(listbox != NULL, "Failed to create a listbox.\n");
style = GetWindowLongA(listbox, GWL_STYLE);
ok((style & invalid_styles[i]) == invalid_styles[i], "%u: unexpected window styles %#x.\n", i, style);
ret = SendMessageA(listbox, LB_SETCOUNT, 100, 0);
ok(ret == LB_ERR, "%u: unexpected return value %d.\n", i, ret);
DestroyWindow(listbox);
}
DestroyWindow(parent);
}
@ -1899,6 +2412,8 @@ START_TEST(listbox)
if (!load_v6_module(&ctx_cookie, &hCtx))
return;
init_msg_sequences(sequences, NUM_MSG_SEQUENCES);
test_listbox();
test_item_height();
test_ownerdraw();
@ -1914,6 +2429,8 @@ START_TEST(listbox)
test_missing_lbuttonup();
test_extents();
test_WM_MEASUREITEM();
test_LB_SETSEL();
test_LBS_NODATA();
unload_v6_module(ctx_cookie, hCtx);
}

View file

@ -75,6 +75,8 @@ static BOOL g_disp_A_to_W;
static NMLVDISPINFOA g_editbox_disp_info;
/* when this is set focus will be tested on LVN_DELETEITEM */
static BOOL g_focus_test_LVN_DELETEITEM;
/* Whether to send WM_KILLFOCUS to the edit control during LVN_ENDLABELEDIT */
static BOOL g_WM_KILLFOCUS_on_LVN_ENDLABELEDIT;
static HWND subclass_editbox(HWND hwndListview);
@ -445,6 +447,25 @@ static const struct message parent_list_cd_seq[] = {
{ 0 }
};
static const struct message listview_end_label_edit[] = {
{ WM_NOTIFY, sent|id, 0, 0, LVN_ENDLABELEDITA },
{ WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING},
{ WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
{ WM_NOTIFY, sent|id|optional, 0, 0, NM_CUSTOMDRAW }, /* XP */
{ WM_NOTIFY, sent|id, 0, 0, NM_SETFOCUS },
{ 0 }
};
static const struct message listview_end_label_edit_kill_focus[] = {
{ WM_NOTIFY, sent|id, 0, 0, LVN_ENDLABELEDITA },
{ WM_COMMAND, sent|id|optional, 0, 0, EN_KILLFOCUS }, /* todo: not sent by wine yet */
{ WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
{ WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
{ WM_NOTIFY, sent|id|optional, 0, 0, NM_CUSTOMDRAW }, /* XP */
{ WM_NOTIFY, sent|id, 0, 0, NM_SETFOCUS },
{ 0 }
};
static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static LONG defwndproc_counter = 0;
@ -457,6 +478,7 @@ static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LP
msg.wParam = wParam;
msg.lParam = lParam;
if (message == WM_NOTIFY && lParam) msg.id = ((NMHDR*)lParam)->code;
if (message == WM_COMMAND) msg.id = HIWORD(wParam);
/* log system messages, except for painting */
if (message < WM_USER &&
@ -503,24 +525,17 @@ static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LP
/* always accept new item text */
NMLVDISPINFOA *di = (NMLVDISPINFOA*)lParam;
g_editbox_disp_info = *di;
trace("LVN_ENDLABELEDIT: text=%s\n", di->item.pszText ? di->item.pszText : "(null)");
/* edit control still available from this notification */
edit = (HWND)SendMessageA(((NMHDR*)lParam)->hwndFrom, LVM_GETEDITCONTROL, 0, 0);
ok(IsWindow(edit), "expected valid edit control handle\n");
ok((GetWindowLongA(edit, GWL_STYLE) & ES_MULTILINE) == 0, "edit is multiline\n");
if (g_WM_KILLFOCUS_on_LVN_ENDLABELEDIT)
SendMessageA(edit, WM_KILLFOCUS, 0, 0);
return TRUE;
}
case LVN_BEGINSCROLL:
case LVN_ENDSCROLL:
{
NMLVSCROLL *pScroll = (NMLVSCROLL*)lParam;
trace("LVN_%sSCROLL: (%d,%d)\n", pScroll->hdr.code == LVN_BEGINSCROLL ?
"BEGIN" : "END", pScroll->dx, pScroll->dy);
}
break;
case LVN_ITEMCHANGING:
{
NMLISTVIEW *nmlv = (NMLISTVIEW*)lParam;
@ -1781,6 +1796,7 @@ static void test_redraw(void)
HDC hdc;
BOOL res;
DWORD r;
RECT rect;
hwnd = create_listview_control(LVS_REPORT);
subclass_header(hwnd);
@ -1838,6 +1854,13 @@ static void test_redraw(void)
ReleaseDC(hwndparent, hdc);
/* test setting the window style to what it already was */
UpdateWindow(hwnd);
SetWindowLongA(hwnd, GWL_STYLE, GetWindowLongA(hwnd, GWL_STYLE));
GetUpdateRect(hwnd, &rect, FALSE);
ok(rect.left == 0 && rect.top == 0 && rect.right == 0 && rect.bottom == 0,
"Expected empty update rect, got %s\n", wine_dbgstr_rect(&rect));
DestroyWindow(hwnd);
}
@ -2337,7 +2360,7 @@ static void test_multiselect(void)
r = SendMessageA(hwnd, LVM_GETSELECTIONMARK, 0, 0);
ok(r == 0, "got %d\n", r);
for (i = 0; i < sizeof(task_list)/sizeof(task_list[0]); i++) {
for (i = 0; i < ARRAY_SIZE(task_list); i++) {
DWORD selected_count;
LVITEMA item;
@ -3490,7 +3513,7 @@ static void test_norecompute(void)
item.mask = LVIF_TEXT | LVIF_NORECOMPUTE;
item.iItem = 0;
item.pszText = buff;
item.cchTextMax = sizeof(buff)/sizeof(CHAR);
item.cchTextMax = ARRAY_SIZE(buff);
res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
expect(TRUE, res);
ok(lstrcmpA(buff, testA) == 0, "Expected (%s), got (%s)\n", testA, buff);
@ -3504,7 +3527,7 @@ static void test_norecompute(void)
item.mask = LVIF_TEXT | LVIF_NORECOMPUTE;
item.iItem = 1;
item.pszText = buff;
item.cchTextMax = sizeof(buff)/sizeof(CHAR);
item.cchTextMax = ARRAY_SIZE(buff);
flush_sequences(sequences, NUM_MSG_SEQUENCES);
res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
@ -3529,7 +3552,7 @@ static void test_norecompute(void)
item.mask = LVIF_TEXT | LVIF_NORECOMPUTE;
item.iItem = 0;
item.pszText = buff;
item.cchTextMax = sizeof(buff)/sizeof(CHAR);
item.cchTextMax = ARRAY_SIZE(buff);
flush_sequences(sequences, NUM_MSG_SEQUENCES);
res = SendMessageA(hwnd, LVM_GETITEMA, 0, (LPARAM)&item);
expect(TRUE, res);
@ -4671,7 +4694,7 @@ static void test_canceleditlabel(void)
ok(!IsWindow(hwndedit), "Expected edit control to be destroyed\n");
memset(&itema, 0, sizeof(itema));
itema.pszText = buff;
itema.cchTextMax = sizeof(buff)/sizeof(CHAR);
itema.cchTextMax = ARRAY_SIZE(buff);
ret = SendMessageA(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&itema);
expect(5, ret);
ok(strcmp(buff, test1) == 0, "Expected label text not to change\n");
@ -5499,7 +5522,7 @@ static void test_header_notification2(void)
memset(&itemW, 0, sizeof(itemW));
itemW.mask = HDI_WIDTH | HDI_ORDER | HDI_TEXT;
itemW.pszText = buffer;
itemW.cchTextMax = sizeof(buffer);
itemW.cchTextMax = ARRAY_SIZE(buffer);
ret = SendMessageW(header, HDM_GETITEMW, 0, (LPARAM)&itemW);
expect(1, ret);
@ -5667,7 +5690,7 @@ static void test_dispinfo(void)
g_disp_A_to_W = TRUE;
item.pszText = (char*)buff;
item.cchTextMax = sizeof(buff)/sizeof(WCHAR);
item.cchTextMax = ARRAY_SIZE(buff);
ret = SendMessageA(hwnd, LVM_GETITEMTEXTA, 0, (LPARAM)&item);
ok(ret == sizeof(testA)-1, "got %d, expected 4\n", ret);
g_disp_A_to_W = FALSE;
@ -6186,7 +6209,7 @@ static void test_state_image(void)
};
int i;
for (i = 0; i < sizeof(styles)/sizeof(styles[0]); i++)
for (i = 0; i < ARRAY_SIZE(styles); i++)
{
static char text[] = "Item";
static char subtext[] = "Subitem";
@ -6331,6 +6354,127 @@ static void test_LVSCW_AUTOSIZE(void)
DestroyWindow(hwnd);
}
static void test_LVN_ENDLABELEDIT(void)
{
WCHAR text[] = {'l','a','l','a',0};
HWND hwnd, hwndedit;
LVITEMW item = {0};
DWORD ret;
hwnd = create_listview_control(LVS_REPORT | LVS_EDITLABELS);
insert_column(hwnd, 0);
item.mask = LVIF_TEXT;
item.pszText = text;
SendMessageW(hwnd, LVM_INSERTITEMW, 0, (LPARAM)&item);
/* Test normal editing */
SetFocus(hwnd);
hwndedit = (HWND)SendMessageW(hwnd, LVM_EDITLABELW, 0, 0);
ok(hwndedit != NULL, "Failed to get edit control.\n");
ret = SendMessageA(hwndedit, WM_SETTEXT, 0, (LPARAM)"test");
ok(ret, "Failed to set edit text.\n");
flush_sequences(sequences, NUM_MSG_SEQUENCES);
ret = SendMessageA(hwndedit, WM_KEYDOWN, VK_RETURN, 0);
ok_sequence(sequences, PARENT_SEQ_INDEX, listview_end_label_edit, "Label edit", FALSE);
/* Test editing with kill focus */
SetFocus(hwnd);
hwndedit = (HWND)SendMessageW(hwnd, LVM_EDITLABELW, 0, 0);
ok(hwndedit != NULL, "Failed to get edit control.\n");
ret = SendMessageA(hwndedit, WM_SETTEXT, 0, (LPARAM)"test2");
ok(ret, "Failed to set edit text.\n");
flush_sequences(sequences, NUM_MSG_SEQUENCES);
g_WM_KILLFOCUS_on_LVN_ENDLABELEDIT = TRUE;
ret = SendMessageA(hwndedit, WM_KEYDOWN, VK_RETURN, 0);
g_WM_KILLFOCUS_on_LVN_ENDLABELEDIT = FALSE;
ok_sequence(sequences, PARENT_SEQ_INDEX, listview_end_label_edit_kill_focus,
"Label edit, kill focus", FALSE);
ok(GetFocus() == hwnd, "Unexpected focused window.\n");
flush_sequences(sequences, NUM_MSG_SEQUENCES);
DestroyWindow(hwnd);
}
static LRESULT CALLBACK create_item_height_wndproc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
if (msg == WM_CREATE)
return 0;
return CallWindowProcA(listviewWndProc, hwnd, msg, wParam, lParam);
}
static void test_LVM_GETCOUNTPERPAGE(void)
{
static const DWORD styles[] = { LVS_ICON, LVS_LIST, LVS_REPORT, LVS_SMALLICON };
unsigned int i, j;
WNDCLASSEXA cls;
ATOM class;
HWND hwnd;
BOOL ret;
cls.cbSize = sizeof(WNDCLASSEXA);
ret = GetClassInfoExA(GetModuleHandleA(NULL), WC_LISTVIEWA, &cls);
ok(ret, "Failed to get class info.\n");
listviewWndProc = cls.lpfnWndProc;
cls.lpfnWndProc = create_item_height_wndproc;
cls.lpszClassName = "CountPerPageClass";
class = RegisterClassExA(&cls);
ok(class, "Failed to register class.\n");
for (i = 0; i < ARRAY_SIZE(styles); i++)
{
static char text[] = "item text";
LVITEMA item = { 0 };
UINT count, count2;
hwnd = create_listview_control(styles[i]);
ok(hwnd != NULL, "Failed to create listview window.\n");
count = SendMessageA(hwnd, LVM_GETCOUNTPERPAGE, 0, 0);
if (styles[i] == LVS_LIST || styles[i] == LVS_REPORT)
ok(count > 0 || broken(styles[i] == LVS_LIST && count == 0), "%u: unexpected count %u.\n", i, count);
else
ok(count == 0, "%u: unexpected count %u.\n", i, count);
for (j = 0; j < 10; j++)
{
item.mask = LVIF_TEXT;
item.pszText = text;
SendMessageA(hwnd, LVM_INSERTITEMA, 0, (LPARAM)&item);
}
count2 = SendMessageA(hwnd, LVM_GETCOUNTPERPAGE, 0, 0);
if (styles[i] == LVS_LIST || styles[i] == LVS_REPORT)
ok(count == count2, "%u: unexpected count %u.\n", i, count2);
else
ok(count2 == 10, "%u: unexpected count %u.\n", i, count2);
DestroyWindow(hwnd);
hwnd = CreateWindowA("CountPerPageClass", "Test", WS_VISIBLE | styles[i], 0, 0, 100, 100, NULL, NULL,
GetModuleHandleA(NULL), 0);
ok(hwnd != NULL, "Failed to create a window.\n");
count = SendMessageA(hwnd, LVM_GETCOUNTPERPAGE, 0, 0);
ok(count == 0, "%u: unexpected count %u.\n", i, count);
DestroyWindow(hwnd);
}
ret = UnregisterClassA("CountPerPageClass", NULL);
ok(ret, "Failed to unregister test class.\n");
}
START_TEST(listview)
{
ULONG_PTR ctx_cookie;
@ -6392,6 +6536,8 @@ START_TEST(listview)
test_callback_mask();
test_state_image();
test_LVSCW_AUTOSIZE();
test_LVN_ENDLABELEDIT();
test_LVM_GETCOUNTPERPAGE();
if (!load_v6_module(&ctx_cookie, &hCtx))
{
@ -6434,6 +6580,8 @@ START_TEST(listview)
test_oneclickactivate();
test_state_image();
test_LVSCW_AUTOSIZE();
test_LVN_ENDLABELEDIT();
test_LVM_GETCOUNTPERPAGE();
unload_v6_module(ctx_cookie, hCtx);

View file

@ -269,8 +269,7 @@ static void test_LoadIconWithScaleDown(void)
/* non-existing filename */
hr = pLoadIconMetric(NULL, nonexisting_fileW, LIM_LARGE, &icon);
todo_wine
ok(hr == HRESULT_FROM_WIN32(ERROR_RESOURCE_TYPE_NOT_FOUND),
ok(hr == HRESULT_FROM_WIN32(ERROR_RESOURCE_TYPE_NOT_FOUND) || hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) /* Win7 */,
"Expected HRESULT_FROM_WIN32(ERROR_RESOURCE_TYPE_NOT_FOUND), got %x\n", hr);
hr = pLoadIconWithScaleDown(NULL, nonexisting_fileW, 32, 32, &icon);
@ -343,23 +342,32 @@ static void test_LoadIconWithScaleDown(void)
FreeLibrary(hinst);
}
static void check_class( const char *name, int must_exist, UINT style, UINT ignore )
static void check_class( const char *name, int must_exist, UINT style, UINT ignore, BOOL v6 )
{
WNDCLASSA wc;
if (GetClassInfoA( 0, name, &wc ))
{
todo_wine_if(strcmp(name, "Button") &&
strcmp(name, "ComboBox") &&
strcmp(name, "Edit") &&
strcmp(name, "Static") &&
strcmp(name, "ListBox") &&
strcmp(name, "ComboLBox"))
char buff[64];
HWND hwnd;
todo_wine_if(!strcmp(name, "SysLink") && !must_exist && !v6)
ok( must_exist, "System class %s should %sexist\n", name, must_exist ? "" : "NOT " );
if (!must_exist) return;
todo_wine_if(!strcmp(name, "ScrollBar") || (!strcmp(name, "tooltips_class32") && v6))
ok( !(~wc.style & style & ~ignore), "System class %s is missing bits %x (%08x/%08x)\n",
name, ~wc.style & style, wc.style, style );
todo_wine_if((!strcmp(name, "tooltips_class32") && v6) || !strcmp(name, "SysLink"))
ok( !(wc.style & ~style), "System class %s has extra bits %x (%08x/%08x)\n",
name, wc.style & ~style, wc.style, style );
ok( !wc.hInstance, "System class %s has hInstance %p\n", name, wc.hInstance );
hwnd = CreateWindowA(name, 0, 0, 0, 0, 0, 0, 0, NULL, GetModuleHandleA(NULL), 0);
ok( hwnd != NULL, "Failed to create window for class %s.\n", name );
GetClassNameA(hwnd, buff, ARRAY_SIZE(buff));
ok( !strcmp(name, buff), "Unexpected class name %s, expected %s.\n", buff, name );
DestroyWindow(hwnd);
}
else
ok( !must_exist, "System class %s does not exist\n", name );
@ -369,13 +377,40 @@ todo_wine_if(strcmp(name, "Button") &&
static void test_builtin_classes(void)
{
/* check style bits */
check_class( "Button", 1, CS_PARENTDC | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW | CS_GLOBALCLASS, 0 );
check_class( "ComboBox", 1, CS_PARENTDC | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW | CS_GLOBALCLASS, 0 );
check_class( "Edit", 1, CS_PARENTDC | CS_DBLCLKS | CS_GLOBALCLASS, 0 );
check_class( "ListBox", 1, CS_PARENTDC | CS_DBLCLKS | CS_GLOBALCLASS, 0 );
check_class( "ScrollBar", 1, CS_PARENTDC | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW | CS_GLOBALCLASS, 0 );
check_class( "Static", 1, CS_PARENTDC | CS_DBLCLKS | CS_GLOBALCLASS, 0 );
check_class( "ComboLBox", 1, CS_SAVEBITS | CS_DBLCLKS | CS_DROPSHADOW | CS_GLOBALCLASS, CS_DROPSHADOW );
check_class( "Button", 1, CS_PARENTDC | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW | CS_GLOBALCLASS, 0, FALSE );
check_class( "ComboBox", 1, CS_PARENTDC | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW | CS_GLOBALCLASS, 0, FALSE );
check_class( "Edit", 1, CS_PARENTDC | CS_DBLCLKS | CS_GLOBALCLASS, 0, FALSE );
check_class( "ListBox", 1, CS_PARENTDC | CS_DBLCLKS | CS_GLOBALCLASS, 0, FALSE );
check_class( "ScrollBar", 1, CS_PARENTDC | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW | CS_GLOBALCLASS, 0, FALSE );
check_class( "Static", 1, CS_PARENTDC | CS_DBLCLKS | CS_GLOBALCLASS, 0, FALSE );
check_class( "ComboLBox", 1, CS_SAVEBITS | CS_DBLCLKS | CS_DROPSHADOW | CS_GLOBALCLASS, CS_DROPSHADOW, FALSE );
}
static void test_comctl32_classes(BOOL v6)
{
check_class(ANIMATE_CLASSA, 1, CS_DBLCLKS | CS_GLOBALCLASS, 0, FALSE);
check_class(WC_COMBOBOXEXA, 1, CS_GLOBALCLASS, 0, FALSE);
check_class(DATETIMEPICK_CLASSA, 1, CS_GLOBALCLASS, 0, FALSE);
check_class(WC_HEADERA, 1, CS_DBLCLKS | CS_GLOBALCLASS, 0, FALSE);
check_class(HOTKEY_CLASSA, 1, CS_GLOBALCLASS, 0, FALSE);
check_class(WC_IPADDRESSA, 1, CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW | CS_GLOBALCLASS, 0, FALSE);
check_class(WC_LISTVIEWA, 1, CS_DBLCLKS | CS_GLOBALCLASS, 0, FALSE);
check_class(MONTHCAL_CLASSA, 1, CS_GLOBALCLASS, 0, FALSE);
check_class(WC_NATIVEFONTCTLA, 1, CS_GLOBALCLASS, 0, FALSE);
check_class(WC_PAGESCROLLERA, 1, CS_GLOBALCLASS, 0, FALSE);
check_class(PROGRESS_CLASSA, 1, CS_HREDRAW | CS_VREDRAW | CS_GLOBALCLASS, 0, FALSE);
check_class(REBARCLASSNAMEA, 1, CS_DBLCLKS | CS_GLOBALCLASS, 0, FALSE);
check_class(STATUSCLASSNAMEA, 1, CS_DBLCLKS | CS_VREDRAW | CS_GLOBALCLASS, 0, FALSE);
check_class(WC_TABCONTROLA, 1, CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW | CS_GLOBALCLASS, 0, FALSE);
check_class(TOOLBARCLASSNAMEA, 1, CS_DBLCLKS | CS_GLOBALCLASS, 0, FALSE);
if (v6)
check_class(TOOLTIPS_CLASSA, 1, CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW | CS_GLOBALCLASS | CS_DROPSHADOW, CS_SAVEBITS | CS_HREDRAW | CS_VREDRAW /* XP */, TRUE);
else
check_class(TOOLTIPS_CLASSA, 1, CS_DBLCLKS | CS_GLOBALCLASS | CS_SAVEBITS, CS_HREDRAW | CS_VREDRAW /* XP */, FALSE);
check_class(TRACKBAR_CLASSA, 1, CS_GLOBALCLASS, 0, FALSE);
check_class(WC_TREEVIEWA, 1, CS_DBLCLKS | CS_GLOBALCLASS, 0, FALSE);
check_class(UPDOWN_CLASSA, 1, CS_HREDRAW | CS_VREDRAW | CS_GLOBALCLASS, 0, FALSE);
check_class("SysLink", v6, CS_GLOBALCLASS, 0, FALSE);
}
START_TEST(misc)
@ -389,9 +424,12 @@ START_TEST(misc)
test_GetPtrAW();
test_Alloc();
test_comctl32_classes(FALSE);
if (!load_v6_module(&ctx_cookie, &hCtx))
return;
test_comctl32_classes(TRUE);
test_builtin_classes();
test_LoadIconWithScaleDown();

View file

@ -1216,7 +1216,7 @@ if (0)
} else {
title_index++;
if (sizeof(title_hits) / sizeof(title_hits[0]) <= title_index)
if (ARRAY_SIZE(title_hits) <= title_index)
break;
todo_wine_if(title_hits[title_index].todo)
@ -1241,8 +1241,7 @@ if (0)
todo_wine ok(month_count + year_count >= 1, "Not enough month and year items\n");
ok(r.right <= x && title_index + 1 == sizeof(title_hits) / sizeof(title_hits[0]),
"Wrong title layout\n");
ok(r.right <= x && title_index + 1 == ARRAY_SIZE(title_hits), "Wrong title layout\n");
DestroyWindow(hwnd);
}
@ -1799,7 +1798,7 @@ static void test_hittest_v6(void)
mchit.iOffset = -1;
mchit.iCol = mchit.iRow = -1;
mchit.uHit = 0;
mchit.rc.left = mchit.rc.right = mchit.rc.top = mchit.rc.bottom = -1;
SetRect(&mchit.rc, -1, -1, -1, -1);
ret = SendMessageA(hwnd, MCM_HITTEST, 0, (LPARAM)&mchit);
expect_hex(MCHT_CALENDARDATE, ret);
expect_hex(MCHT_CALENDARDATE, mchit.uHit);
@ -1816,7 +1815,7 @@ static void test_hittest_v6(void)
mchit.iOffset = -1;
mchit.iCol = mchit.iRow = -1;
mchit.uHit = 0;
mchit.rc.left = mchit.rc.right = mchit.rc.top = mchit.rc.bottom = -1;
SetRect(&mchit.rc, -1, -1, -1, -1);
ret = SendMessageA(hwnd, MCM_HITTEST, 0, (LPARAM)&mchit);
expect_hex(MCHT_TITLE, ret);
expect_hex(MCHT_TITLE, mchit.uHit);
@ -1835,7 +1834,7 @@ static void test_hittest_v6(void)
mchit.iOffset = -2;
mchit.iCol = mchit.iRow = -2;
mchit.uHit = ~0;
mchit.rc.left = mchit.rc.right = mchit.rc.top = mchit.rc.bottom = -1;
SetRect(&mchit.rc, -1, -1, -1, -1);
ret = SendMessageA(hwnd, MCM_HITTEST, 0, (LPARAM)&mchit);
todo_wine expect_hex(MCHT_NOWHERE, ret);
todo_wine expect_hex(MCHT_NOWHERE, mchit.uHit);
@ -2016,7 +2015,7 @@ static void test_sel_notify(void)
};
int i;
for(i = 0; i < sizeof styles / sizeof styles[0]; i++)
for(i = 0; i < ARRAY_SIZE(styles); i++)
{
hwnd = create_monthcal_control(styles[i].val);
SetWindowLongPtrA(hwnd, GWLP_ID, SEL_NOTIFY_TEST_ID);

View file

@ -118,7 +118,7 @@ static LSTATUS mru_RegDeleteTreeA(HKEY hKey, LPCSTR lpszSubKey)
dwMaxSubkeyLen++;
dwMaxValueLen++;
dwMaxLen = max(dwMaxSubkeyLen, dwMaxValueLen);
if (dwMaxLen > sizeof(szNameBuf)/sizeof(CHAR))
if (dwMaxLen > ARRAY_SIZE(szNameBuf))
{
/* Name too big: alloc a buffer for it */
if (!(lpszName = heap_alloc(dwMaxLen * sizeof(CHAR))))
@ -480,7 +480,7 @@ static void test_CreateMRUListLazyA(void)
return;
}
for (i = 0; i < sizeof(create_lazyA)/sizeof(create_lazya_t); i++)
for (i = 0; i < ARRAY_SIZE(create_lazyA); i++)
{
const create_lazya_t *ptr = &create_lazyA[i];
HANDLE hMRU;

File diff suppressed because it is too large Load diff

View file

@ -258,7 +258,7 @@ static void test_PBM_STEPIT(void)
HWND progress;
int i, j;
for (i = 0; i < sizeof(stepit_tests)/sizeof(stepit_tests[0]); i++)
for (i = 0; i < ARRAY_SIZE(stepit_tests); i++)
{
struct stepit_test *test = &stepit_tests[i];
LRESULT ret;

View file

@ -280,7 +280,6 @@ static void test_disableowner(void)
psh.pfnCallback = disableowner_callback;
p = pPropertySheetA(&psh);
todo_wine
ok(p == 0, "Expected 0, got %ld\n", p);
ok(IsWindowEnabled(parenthwnd) != 0, "parent window should be enabled\n");
DestroyWindow(parenthwnd);
@ -1147,6 +1146,46 @@ static void test_CreatePropertySheetPage(void)
}
}
static void test_bad_control_class(void)
{
PROPSHEETPAGEA psp;
PROPSHEETHEADERA psh;
HPROPSHEETPAGE hpsp;
INT_PTR ret;
memset(&psp, 0, sizeof(psp));
psp.dwSize = sizeof(psp);
psp.hInstance = GetModuleHandleA(NULL);
U(psp).pszTemplate = (LPCSTR)MAKEINTRESOURCE(IDD_PROP_PAGE_BAD_CONTROL);
psp.pfnDlgProc = page_dlg_proc;
hpsp = pCreatePropertySheetPageA(&psp);
ok(hpsp != 0, "CreatePropertySheetPage failed\n");
memset(&psh, 0, sizeof(psh));
psh.dwSize = PROPSHEETHEADERA_V1_SIZE;
psh.nPages = 1;
psh.hwndParent = GetDesktopWindow();
U3(psh).phpage = &hpsp;
#ifndef __REACTOS__ /* FIXME: Inspect why this causes a hang */
ret = pPropertySheetA(&psh);
ok(ret == 0, "got %ld\n", ret);
#endif
/* Need to recreate hpsp otherwise the test fails under Windows */
hpsp = pCreatePropertySheetPageA(&psp);
ok(hpsp != 0, "CreatePropertySheetPage failed\n");
U3(psh).phpage = &hpsp;
psh.dwFlags = PSH_MODELESS;
ret = pPropertySheetA(&psh);
ok(ret != 0, "got %ld\n", ret);
ok(IsWindow((HWND)ret), "bad window handle %#lx\n", ret);
DestroyWindow((HWND)ret);
}
static void init_functions(void)
{
HMODULE hComCtl32 = LoadLibraryA("comctl32.dll");
@ -1172,6 +1211,7 @@ START_TEST(propsheet)
init_functions();
test_bad_control_class();
test_title();
test_nopage();
test_disableowner();

View file

@ -828,7 +828,7 @@ static DWORD resize_numtests = 0;
RECT r; \
int value; \
const rbresize_test_result_t *res = &resize_results[resize_numtests++]; \
assert(resize_numtests <= sizeof(resize_results)/sizeof(resize_results[0])); \
assert(resize_numtests <= ARRAY_SIZE(resize_results)); \
GetWindowRect(hRebar, &r); \
MapWindowPoints(HWND_DESKTOP, hMainWnd, (LPPOINT)&r, 2); \
if ((dwStyles[i] & (CCS_NOPARENTALIGN|CCS_NODIVIDER)) == CCS_NOPARENTALIGN) {\
@ -855,7 +855,7 @@ static void test_resize(void)
CCS_TOP | WS_BORDER, CCS_NOPARENTALIGN | CCS_NODIVIDER | WS_BORDER, CCS_NORESIZE | WS_BORDER,
CCS_NOMOVEY | WS_BORDER};
const int styles_count = sizeof(dwStyles) / sizeof(dwStyles[0]);
const int styles_count = ARRAY_SIZE(dwStyles);
int i;
for (i = 0; i < styles_count; i++)

View file

@ -39,6 +39,7 @@
#define IDD_PROP_PAGE_WITH_CUSTOM_DEFAULT_BUTTON 34
#define IDD_PROP_PAGE_MESSAGE_TEST 35
#define IDD_PROP_PAGE_ERROR 36
#define IDD_PROP_PAGE_BAD_CONTROL 37
#define IDC_PS_EDIT1 1000
#define IDC_PS_EDIT2 1001

View file

@ -78,6 +78,13 @@ FONT 8, "MS Shell Dlg"
{
}
IDD_PROP_PAGE_BAD_CONTROL DIALOG 0, 0, 100, 100
STYLE WS_POPUP | WS_CAPTION | WS_CLIPSIBLINGS | WS_VISIBLE
FONT 8, "MS Shell Dlg"
{
CONTROL "", -1, "invalid class", 0, 0, 0, 0, 0
}
STRINGTABLE
{
IDS_TBADD1 "abc"

View file

@ -127,7 +127,7 @@ static int CALLBACK check_height_font_enumproc(ENUMLOGFONTEXA *enumlf, NEWTEXTME
if (type != TRUETYPE_FONTTYPE)
facename = enumlf->elfLogFont.lfFaceName;
for (i = 0; i < sizeof(sizes)/sizeof(sizes[0]); i++)
for (i = 0; i < ARRAY_SIZE(sizes); i++)
{
HFONT hFont;
TEXTMETRICA tm;
@ -586,6 +586,131 @@ static void test_notify(void)
ok(g_got_contextmenu, "WM_RBUTTONUP did not activate the context menu!\n");
}
static void test_sizegrip(void)
{
HWND hwndStatus;
LONG style;
RECT rc, rcClient;
POINT pt;
int width, r;
hwndStatus = CreateWindowA(SUBCLASS_NAME, "", WS_CHILD|WS_VISIBLE|SBARS_SIZEGRIP,
0, 0, 100, 100, g_hMainWnd, NULL, NULL, NULL);
style = GetWindowLongPtrA(g_hMainWnd, GWL_STYLE);
width = GetSystemMetrics(SM_CXVSCROLL);
GetClientRect(hwndStatus, &rcClient);
pt.x = rcClient.right;
pt.y = rcClient.top;
ClientToScreen(hwndStatus, &pt);
rc.left = pt.x - width;
rc.right = pt.x;
rc.top = pt.y;
pt.y = rcClient.bottom;
ClientToScreen(hwndStatus, &pt);
rc.bottom = pt.y;
/* check bounds when not maximized */
r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.left, rc.top));
expect(HTBOTTOMRIGHT, r);
r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.left - 1, rc.top));
expect(HTCLIENT, r);
r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.left, rc.top - 1));
expect(HTBOTTOMRIGHT, r);
r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.right, rc.bottom));
expect(HTBOTTOMRIGHT, r);
r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.right + 1, rc.bottom));
expect(HTBOTTOMRIGHT, r);
r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.right, rc.bottom + 1));
expect(HTBOTTOMRIGHT, r);
r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.right - 1, rc.bottom - 1));
expect(HTBOTTOMRIGHT, r);
/* not maximized and right-to-left */
SetWindowLongA(hwndStatus, GWL_EXSTYLE, WS_EX_LAYOUTRTL);
pt.x = rcClient.right;
ClientToScreen(hwndStatus, &pt);
rc.left = pt.x + width;
rc.right = pt.x;
r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.left, rc.top));
expect(HTBOTTOMLEFT, r);
r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.left + 1, rc.top));
expect(HTCLIENT, r);
r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.left, rc.top - 1));
expect(HTBOTTOMLEFT, r);
r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.right, rc.bottom));
expect(HTBOTTOMLEFT, r);
r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.right - 1, rc.bottom));
expect(HTBOTTOMLEFT, r);
r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.right, rc.bottom + 1));
expect(HTBOTTOMLEFT, r);
r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.right + 1, rc.bottom - 1));
expect(HTBOTTOMLEFT, r);
/* maximize with left-to-right */
SetWindowLongA(g_hMainWnd, GWL_STYLE, style|WS_MAXIMIZE);
SetWindowLongA(hwndStatus, GWL_EXSTYLE, 0);
GetClientRect(hwndStatus, &rcClient);
pt.x = rcClient.right;
pt.y = rcClient.top;
ClientToScreen(hwndStatus, &pt);
rc.left = pt.x - width;
rc.right = pt.x;
rc.top = pt.y;
pt.y = rcClient.bottom;
ClientToScreen(hwndStatus, &pt);
rc.bottom = pt.y;
r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.left, rc.top));
expect(HTCLIENT, r);
r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.left - 1, rc.top));
expect(HTCLIENT, r);
r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.left, rc.top - 1));
expect(HTNOWHERE, r);
r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.right, rc.bottom));
expect(HTNOWHERE, r);
r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.right + 1, rc.bottom));
expect(HTNOWHERE, r);
r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.right, rc.bottom + 1));
expect(HTNOWHERE, r);
r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.right - 1, rc.bottom - 1));
expect(HTCLIENT, r);
/* maximized with right-to-left */
SetWindowLongA(hwndStatus, GWL_EXSTYLE, WS_EX_LAYOUTRTL);
pt.x = rcClient.right;
ClientToScreen(hwndStatus, &pt);
rc.left = pt.x + width;
rc.right = pt.x;
r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.left, rc.top));
expect(HTCLIENT, r);
r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.left + 1, rc.top));
expect(HTCLIENT, r);
r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.left, rc.top - 1));
expect(HTNOWHERE, r);
r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.right, rc.bottom));
expect(HTNOWHERE, r);
r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.right - 1, rc.bottom));
expect(HTNOWHERE, r);
r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.right, rc.bottom + 1));
expect(HTNOWHERE, r);
r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.right + 1, rc.bottom - 1));
expect(HTCLIENT, r);
SetWindowLongA(g_hMainWnd, GWL_STYLE, style);
DestroyWindow(hwndStatus);
}
static void init_functions(void)
{
HMODULE hComCtl32 = LoadLibraryA("comctl32.dll");
@ -620,4 +745,5 @@ START_TEST(status)
test_status_ownerdraw();
test_gettext();
test_notify();
test_sizegrip();
}

View file

@ -218,46 +218,61 @@ static LRESULT WINAPI wnd_proc_sub(HWND hwnd, UINT message, WPARAM wParam, LPARA
static void test_subclass(void)
{
BOOL ret;
HWND hwnd = CreateWindowExA(0, "TestSubclass", "Test subclass", WS_OVERLAPPEDWINDOW,
100, 100, 200, 200, 0, 0, 0, NULL);
ok(hwnd != NULL, "failed to create test subclass wnd\n");
pSetWindowSubclass(hwnd, wnd_proc_sub, 2, 0);
ret = pSetWindowSubclass(hwnd, wnd_proc_sub, 2, 0);
ok(ret == TRUE, "Expected TRUE\n");
SendMessageA(hwnd, WM_USER, 1, 0);
SendMessageA(hwnd, WM_USER, 2, 0);
ok_sequence(Sub_BasicTest, "Basic");
pSetWindowSubclass(hwnd, wnd_proc_sub, 2, DELETE_SELF);
ret = pSetWindowSubclass(hwnd, wnd_proc_sub, 2, DELETE_SELF);
ok(ret == TRUE, "Expected TRUE\n");
SendMessageA(hwnd, WM_USER, 1, 1);
ok_sequence(Sub_DeletedTest, "Deleted");
SendMessageA(hwnd, WM_USER, 1, 0);
ok_sequence(Sub_AfterDeletedTest, "After Deleted");
pSetWindowSubclass(hwnd, wnd_proc_sub, 2, 0);
ret = pSetWindowSubclass(hwnd, wnd_proc_sub, 2, 0);
ok(ret == TRUE, "Expected TRUE\n");
orig_proc_3 = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)wnd_proc_3);
SendMessageA(hwnd, WM_USER, 1, 0);
SendMessageA(hwnd, WM_USER, 2, 0);
ok_sequence(Sub_OldAfterNewTest, "Old after New");
pSetWindowSubclass(hwnd, wnd_proc_sub, 4, 0);
ret = pSetWindowSubclass(hwnd, wnd_proc_sub, 4, 0);
ok(ret == TRUE, "Expected TRUE\n");
SendMessageA(hwnd, WM_USER, 1, 0);
ok_sequence(Sub_MixTest, "Mix");
/* Now the fun starts */
pSetWindowSubclass(hwnd, wnd_proc_sub, 4, SEND_NEST);
ret = pSetWindowSubclass(hwnd, wnd_proc_sub, 4, SEND_NEST);
ok(ret == TRUE, "Expected TRUE\n");
SendMessageA(hwnd, WM_USER, 1, 1);
ok_sequence(Sub_MixAndNestTest, "Mix and nest");
pSetWindowSubclass(hwnd, wnd_proc_sub, 4, SEND_NEST | DELETE_SELF);
ret = pSetWindowSubclass(hwnd, wnd_proc_sub, 4, SEND_NEST | DELETE_SELF);
ok(ret == TRUE, "Expected TRUE\n");
SendMessageA(hwnd, WM_USER, 1, 1);
ok_sequence(Sub_MixNestDelTest, "Mix, nest, del");
pSetWindowSubclass(hwnd, wnd_proc_sub, 4, 0);
pSetWindowSubclass(hwnd, wnd_proc_sub, 5, DELETE_PREV);
ret = pSetWindowSubclass(hwnd, wnd_proc_sub, 4, 0);
ok(ret == TRUE, "Expected TRUE\n");
ret = pSetWindowSubclass(hwnd, wnd_proc_sub, 5, DELETE_PREV);
ok(ret == TRUE, "Expected TRUE\n");
SendMessageA(hwnd, WM_USER, 1, 1);
ok_sequence(Sub_MixDelPrevTest, "Mix and del prev");
ret = pSetWindowSubclass(NULL, wnd_proc_sub, 1, 0);
ok(ret == FALSE, "Expected FALSE\n");
ret = pSetWindowSubclass(hwnd, NULL, 1, 0);
ok(ret == FALSE, "Expected FALSE\n");
DestroyWindow(hwnd);
}

View file

@ -29,15 +29,21 @@
#include "v6util.h"
#include "msg.h"
#ifdef __REACTOS__
#define WM_KEYF1 0x004d
#endif
#define WM_TD_CALLBACK (WM_APP) /* Custom dummy message to wrap callback notifications */
#define NUM_MSG_SEQUENCES 1
#define TASKDIALOG_SEQ_INDEX 0
#define TEST_NUM_BUTTONS 10 /* Number of custom buttons to test with */
#define TEST_NUM_RADIO_BUTTONS 3
#define ID_START 20 /* Lower IDs might be used by the system */
#define ID_START_BUTTON (ID_START + 0)
#define ID_START_RADIO_BUTTON (ID_START + 20)
static HRESULT (WINAPI *pTaskDialogIndirect)(const TASKDIALOGCONFIG *, int *, int *, BOOL *);
static HRESULT (WINAPI *pTaskDialog)(HWND, HINSTANCE, const WCHAR *, const WCHAR *, const WCHAR *,
@ -121,6 +127,261 @@ static const struct message_info msg_return_press_custom10[] =
{ 0 }
};
static const struct message_info msg_send_click_ok[] =
{
{ TDM_CLICK_BUTTON, IDOK, 0 },
{ 0 }
};
static const struct message_info msg_send_f1[] =
{
{ WM_KEYF1, 0, 0, 0},
{ 0 }
};
static const struct message_info msg_got_tdn_help[] =
{
{ TDN_CREATED, 0, 0, S_OK, msg_send_f1 },
{ TDN_HELP, 0, 0, S_OK, msg_send_click_ok },
{ TDN_BUTTON_CLICKED, IDOK, 0, S_OK, NULL },
{ 0 }
};
/* Three radio buttons */
static const struct message_info msg_return_default_radio_button_1[] =
{
{ TDN_CREATED, 0, 0, S_OK, NULL },
{ TDN_RADIO_BUTTON_CLICKED, ID_START_RADIO_BUTTON, 0, S_OK, msg_send_click_ok },
{ TDN_BUTTON_CLICKED, IDOK, 0, S_OK, NULL },
{ 0 }
};
static const struct message_info msg_return_default_radio_button_2[] =
{
{ TDN_CREATED, 0, 0, S_OK, NULL },
{ TDN_RADIO_BUTTON_CLICKED, ID_START_RADIO_BUTTON + 1, 0, S_OK, msg_send_click_ok },
{ TDN_BUTTON_CLICKED, IDOK, 0, S_OK, NULL },
{ 0 }
};
static const struct message_info msg_return_default_radio_button_3[] =
{
{ TDN_CREATED, 0, 0, S_OK, NULL },
{ TDN_RADIO_BUTTON_CLICKED, -2, 0, S_OK, msg_send_click_ok },
{ TDN_BUTTON_CLICKED, IDOK, 0, S_OK, NULL },
{ 0 }
};
static const struct message_info msg_select_first_radio_button[] =
{
{ TDM_CLICK_RADIO_BUTTON, ID_START_RADIO_BUTTON, 0 },
{ 0 }
};
static const struct message_info msg_return_first_radio_button[] =
{
{ TDN_CREATED, 0, 0, S_OK, NULL },
{ TDN_RADIO_BUTTON_CLICKED, ID_START_RADIO_BUTTON + 1, 0, S_OK, msg_select_first_radio_button },
{ TDN_RADIO_BUTTON_CLICKED, ID_START_RADIO_BUTTON, 0, S_OK, msg_send_click_ok },
{ TDN_BUTTON_CLICKED, IDOK, 0, S_OK, NULL },
{ 0 }
};
static const struct message_info msg_select_first_disabled_radio_button_and_press_ok[] =
{
{ TDM_ENABLE_RADIO_BUTTON, ID_START_RADIO_BUTTON, 0 },
{ TDM_CLICK_RADIO_BUTTON, ID_START_RADIO_BUTTON, 0 },
{ TDM_CLICK_BUTTON, IDOK, 0 },
{ 0 }
};
static const struct message_info msg_return_default_radio_button_clicking_disabled[] =
{
{ TDN_CREATED, 0, 0, S_OK, NULL },
{ TDN_RADIO_BUTTON_CLICKED, ID_START_RADIO_BUTTON + 1, 0, S_OK, msg_select_first_disabled_radio_button_and_press_ok },
{ TDN_RADIO_BUTTON_CLICKED, ID_START_RADIO_BUTTON, 0, S_OK, NULL },
{ TDN_BUTTON_CLICKED, IDOK, 0, S_OK, NULL },
{ 0 }
};
static const struct message_info msg_return_no_default_radio_button_flag[] =
{
{ TDN_CREATED, 0, 0, S_OK, msg_send_click_ok },
{ TDN_RADIO_BUTTON_CLICKED, ID_START_RADIO_BUTTON, 0, S_OK, NULL },
{ TDN_BUTTON_CLICKED, IDOK, 0, S_OK, NULL },
{ 0 }
};
static const struct message_info msg_return_no_default_radio_button_id_and_flag[] =
{
{ TDN_CREATED, 0, 0, S_OK, msg_send_click_ok },
{ TDN_BUTTON_CLICKED, IDOK, 0, S_OK, NULL },
{ 0 }
};
static const struct message_info msg_select_negative_id_radio_button[] =
{
{ TDM_CLICK_RADIO_BUTTON, -2, 0 },
{ 0 }
};
static const struct message_info msg_return_press_negative_id_radio_button[] =
{
{ TDN_CREATED, 0, 0, S_OK, msg_select_negative_id_radio_button },
{ TDN_RADIO_BUTTON_CLICKED, -2, 0, S_OK, msg_send_click_ok },
{ TDN_BUTTON_CLICKED, IDOK, 0, S_OK, NULL },
{ 0 }
};
static const struct message_info msg_send_all_common_button_click[] =
{
{ TDM_CLICK_BUTTON, IDOK, 0 },
{ TDM_CLICK_BUTTON, IDYES, 0 },
{ TDM_CLICK_BUTTON, IDNO, 0 },
{ TDM_CLICK_BUTTON, IDCANCEL, 0 },
{ TDM_CLICK_BUTTON, IDRETRY, 0 },
{ TDM_CLICK_BUTTON, IDCLOSE, 0 },
{ TDM_CLICK_BUTTON, ID_START_BUTTON + 99, 0 },
{ 0 }
};
static const struct message_info msg_press_nonexistent_buttons[] =
{
{ TDN_CREATED, 0, 0, S_OK, msg_send_all_common_button_click },
{ TDN_BUTTON_CLICKED, IDOK, 0, S_FALSE, NULL },
{ TDN_BUTTON_CLICKED, IDYES, 0, S_FALSE, NULL },
{ TDN_BUTTON_CLICKED, IDNO, 0, S_FALSE, NULL },
{ TDN_BUTTON_CLICKED, IDCANCEL, 0, S_FALSE, NULL },
{ TDN_BUTTON_CLICKED, IDRETRY, 0, S_FALSE, NULL },
{ TDN_BUTTON_CLICKED, IDCLOSE, 0, S_FALSE, NULL },
{ TDN_BUTTON_CLICKED, ID_START_BUTTON + 99, 0, S_OK, NULL },
{ 0 }
};
static const struct message_info msg_send_all_common_button_click_with_command[] =
{
{ WM_COMMAND, MAKEWORD(IDOK, BN_CLICKED), 0 },
{ WM_COMMAND, MAKEWORD(IDYES, BN_CLICKED), 0 },
{ WM_COMMAND, MAKEWORD(IDNO, BN_CLICKED), 0 },
{ WM_COMMAND, MAKEWORD(IDCANCEL, BN_CLICKED), 0 },
{ WM_COMMAND, MAKEWORD(IDRETRY, BN_CLICKED), 0 },
{ WM_COMMAND, MAKEWORD(IDCLOSE, BN_CLICKED), 0 },
{ WM_COMMAND, MAKEWORD(ID_START_BUTTON + 99, BN_CLICKED), 0 },
{ WM_COMMAND, MAKEWORD(IDOK, BN_CLICKED), 0 },
{ 0 }
};
static const struct message_info msg_press_nonexistent_buttons_with_command[] =
{
{ TDN_CREATED, 0, 0, S_OK, msg_send_all_common_button_click_with_command },
{ TDN_BUTTON_CLICKED, ID_START_BUTTON, 0, S_FALSE, NULL },
{ TDN_BUTTON_CLICKED, ID_START_BUTTON, 0, S_OK, NULL },
{ 0 }
};
static const struct message_info msg_send_nonexistent_radio_button_click[] =
{
{ TDM_CLICK_RADIO_BUTTON, ID_START_RADIO_BUTTON + 99, 0 },
{ TDM_CLICK_BUTTON, IDOK, 0 },
{ 0 }
};
static const struct message_info msg_press_nonexistent_radio_button[] =
{
{ TDN_CREATED, 0, 0, S_OK, msg_send_nonexistent_radio_button_click },
{ TDN_BUTTON_CLICKED, IDOK, 0, S_OK, NULL },
{ 0 }
};
static const struct message_info msg_return_default_verification_unchecked[] =
{
{ TDN_CREATED, 0, 0, S_OK, msg_send_click_ok },
{ TDN_BUTTON_CLICKED, IDOK, 0, S_OK, NULL },
{ 0 }
};
static const struct message_info msg_return_default_verification_checked[] =
{
{ TDN_CREATED, 0, 0, S_OK, msg_send_click_ok },
{ TDN_BUTTON_CLICKED, IDOK, 0, S_OK, NULL },
{ 0 }
};
static const struct message_info msg_uncheck_verification[] =
{
{ TDM_CLICK_VERIFICATION, FALSE, 0 },
{ 0 }
};
static const struct message_info msg_return_verification_unchecked[] =
{
{ TDN_CREATED, 0, 0, S_OK, msg_uncheck_verification },
{ TDN_VERIFICATION_CLICKED, FALSE, 0, S_OK, msg_send_click_ok },
{ TDN_BUTTON_CLICKED, IDOK, 0, S_OK, NULL },
{ 0 }
};
static const struct message_info msg_check_verification[] =
{
{ TDM_CLICK_VERIFICATION, TRUE, 0 },
{ 0 }
};
static const struct message_info msg_return_verification_checked[] =
{
{ TDN_CREATED, 0, 0, S_OK, msg_check_verification },
{ TDN_VERIFICATION_CLICKED, TRUE, 0, S_OK, msg_send_click_ok },
{ TDN_BUTTON_CLICKED, IDOK, 0, S_OK, NULL },
{ 0 }
};
static TASKDIALOGCONFIG navigated_info = {0};
static const struct message_info msg_send_navigate[] =
{
{ TDM_NAVIGATE_PAGE, 0, (LPARAM)&navigated_info, 0},
{ 0 }
};
static const struct message_info msg_return_navigated_page[] =
{
{ TDN_CREATED, 0, 0, S_OK, NULL },
{ TDN_RADIO_BUTTON_CLICKED, ID_START_RADIO_BUTTON, 0, S_OK, msg_send_navigate },
{ TDN_DIALOG_CONSTRUCTED, 0, 0, S_OK, NULL },
{ TDN_RADIO_BUTTON_CLICKED, ID_START_RADIO_BUTTON, 0, S_OK, NULL },
{ TDN_NAVIGATED, 0, 0, S_OK, msg_send_click_ok },
{ TDN_BUTTON_CLICKED, IDOK, 0, S_OK, NULL },
{ 0 }
};
static const struct message_info msg_send_close[] =
{
{ WM_CLOSE, 0, 0, 0},
{ 0 }
};
static const struct message_info msg_handle_wm_close[] =
{
{ TDN_CREATED, 0, 0, S_OK, msg_send_close },
{ TDN_BUTTON_CLICKED, IDCANCEL, 0, S_FALSE, msg_send_close },
{ TDN_BUTTON_CLICKED, IDCANCEL, 0, S_OK, NULL },
{ 0 }
};
static const struct message_info msg_send_close_then_ok[] =
{
{ WM_CLOSE, 0, 0, 0},
{ TDM_CLICK_BUTTON, IDOK, 0 },
{ 0 }
};
static const struct message_info msg_handle_wm_close_without_cancel_button[] =
{
{ TDN_CREATED, 0, 0, S_OK, msg_send_close_then_ok },
{ TDN_BUTTON_CLICKED, IDOK, 0, S_OK, NULL },
{ 0 }
};
static void init_test_message(UINT message, WPARAM wParam, LPARAM lParam, struct message *msg)
{
msg->message = WM_TD_CALLBACK;
@ -131,16 +392,18 @@ static void init_test_message(UINT message, WPARAM wParam, LPARAM lParam, struct
msg->stage = 0;
}
#define run_test(info, expect_button, seq, context) \
run_test_(info, expect_button, seq, context, \
sizeof(seq)/sizeof(seq[0]) - 1, __FILE__, __LINE__)
#define run_test(info, expect_button, expect_radio_button, verification_checked, seq, context) \
run_test_(info, expect_button, expect_radio_button, verification_checked, seq, context, \
ARRAY_SIZE(seq) - 1, __FILE__, __LINE__)
static void run_test_(TASKDIALOGCONFIG *info, int expect_button, const struct message_info *test_messages,
const char *context, int test_messages_len, const char *file, int line)
static void run_test_(TASKDIALOGCONFIG *info, int expect_button, int expect_radio_button, BOOL verification_checked,
const struct message_info *test_messages, const char *context, int test_messages_len,
const char *file, int line)
{
struct message *msg, *msg_start;
int ret_button = 0;
int ret_radio = 0;
BOOL ret_verification = FALSE;
HRESULT hr;
int i;
@ -157,12 +420,14 @@ static void run_test_(TASKDIALOGCONFIG *info, int expect_button, const struct me
current_message_info = test_messages;
flush_sequences(sequences, NUM_MSG_SEQUENCES);
hr = pTaskDialogIndirect(info, &ret_button, &ret_radio, NULL);
hr = pTaskDialogIndirect(info, &ret_button, &ret_radio, &ret_verification);
ok_(file, line)(hr == S_OK, "TaskDialogIndirect() failed, got %#x.\n", hr);
ok_sequence_(sequences, TASKDIALOG_SEQ_INDEX, msg_start, context, FALSE, file, line);
ok_(file, line)(ret_button == expect_button,
"Wrong button. Expected %d, got %d\n", expect_button, ret_button);
ok_(file, line)(ret_radio == expect_radio_button,
"Wrong radio button. Expected %d, got %d\n", expect_radio_button, ret_radio);
heap_free(msg_start);
}
@ -220,16 +485,17 @@ static void test_callback(void)
info.pfCallback = taskdialog_callback_proc;
info.lpCallbackData = test_ref_data;
run_test(&info, IDOK, msg_return_press_ok, "Press VK_RETURN.");
run_test(&info, IDOK, 0, FALSE, msg_return_press_ok, "Press VK_RETURN.");
}
static void test_buttons(void)
{
TASKDIALOGCONFIG info = {0};
TASKDIALOG_BUTTON custom_buttons[TEST_NUM_BUTTONS];
static const DWORD command_link_flags[] = {0, TDF_USE_COMMAND_LINKS, TDF_USE_COMMAND_LINKS_NO_ICON};
TASKDIALOG_BUTTON custom_buttons[TEST_NUM_BUTTONS], radio_buttons[TEST_NUM_RADIO_BUTTONS];
const WCHAR button_format[] = {'%','0','2','d',0};
WCHAR button_titles[TEST_NUM_BUTTONS * 3]; /* Each button has two digits as title, plus null-terminator */
/* Each button has two digits as title, plus null-terminator */
WCHAR button_titles[TEST_NUM_BUTTONS * 3], radio_button_titles[TEST_NUM_BUTTONS * 3];
int i;
info.cbSize = sizeof(TASKDIALOGCONFIG);
@ -247,48 +513,359 @@ static void test_buttons(void)
}
custom_buttons[TEST_NUM_BUTTONS - 1].nButtonID = -1;
/* Init radio buttons */
for (i = 0; i < TEST_NUM_RADIO_BUTTONS; i++)
{
WCHAR *text = &radio_button_titles[i * 3];
wsprintfW(text, button_format, i);
radio_buttons[i].pszButtonText = text;
radio_buttons[i].nButtonID = ID_START_RADIO_BUTTON + i;
}
radio_buttons[TEST_NUM_RADIO_BUTTONS - 1].nButtonID = -2;
/* Test nDefaultButton */
/* Test common buttons with invalid default ID */
info.nDefaultButton = 0; /* Should default to first created button */
info.dwCommonButtons = TDCBF_OK_BUTTON | TDCBF_YES_BUTTON | TDCBF_NO_BUTTON
| TDCBF_CANCEL_BUTTON | TDCBF_RETRY_BUTTON | TDCBF_CLOSE_BUTTON;
run_test(&info, IDOK, msg_return_press_ok, "default button: unset default");
run_test(&info, IDOK, 0, FALSE, msg_return_press_ok, "default button: unset default");
info.dwCommonButtons = TDCBF_YES_BUTTON | TDCBF_NO_BUTTON
| TDCBF_CANCEL_BUTTON | TDCBF_RETRY_BUTTON | TDCBF_CLOSE_BUTTON;
run_test(&info, IDYES, msg_return_press_yes, "default button: unset default");
run_test(&info, IDYES, 0, FALSE, msg_return_press_yes, "default button: unset default");
info.dwCommonButtons = TDCBF_NO_BUTTON | TDCBF_CANCEL_BUTTON | TDCBF_RETRY_BUTTON | TDCBF_CLOSE_BUTTON;
run_test(&info, IDNO, msg_return_press_no, "default button: unset default");
run_test(&info, IDNO, 0, FALSE, msg_return_press_no, "default button: unset default");
info.dwCommonButtons = TDCBF_CANCEL_BUTTON | TDCBF_RETRY_BUTTON | TDCBF_CLOSE_BUTTON;
run_test(&info, IDRETRY, msg_return_press_retry, "default button: unset default");
run_test(&info, IDRETRY, 0, FALSE, msg_return_press_retry, "default button: unset default");
info.dwCommonButtons = TDCBF_CANCEL_BUTTON | TDCBF_CLOSE_BUTTON;
run_test(&info, IDCANCEL, msg_return_press_cancel, "default button: unset default");
run_test(&info, IDCANCEL, 0, FALSE, msg_return_press_cancel, "default button: unset default");
/* Test with all common and custom buttons and invalid default ID */
info.nDefaultButton = 0xff; /* Random ID, should also default to first created button */
/* Custom buttons could be command links */
for (i = 0; i < ARRAY_SIZE(command_link_flags); i++)
{
info.dwFlags = command_link_flags[i];
/* Test with all common and custom buttons and invalid default ID */
info.nDefaultButton = 0xff; /* Random ID, should also default to first created button */
info.cButtons = TEST_NUM_BUTTONS;
info.pButtons = custom_buttons;
run_test(&info, ID_START_BUTTON, 0, FALSE, msg_return_press_custom1,
"default button: invalid default, with common buttons - 1");
info.nDefaultButton = -1; /* Should work despite button ID -1 */
run_test(&info, -1, 0, FALSE, msg_return_press_custom10, "default button: invalid default, with common buttons - 2");
info.nDefaultButton = -2; /* Should also default to first created button */
run_test(&info, ID_START_BUTTON, 0, FALSE, msg_return_press_custom1,
"default button: invalid default, with common buttons - 3");
/* Test with only custom buttons and invalid default ID */
info.dwCommonButtons = 0;
run_test(&info, ID_START_BUTTON, 0, FALSE, msg_return_press_custom1,
"default button: invalid default, no common buttons");
/* Test with common and custom buttons and valid default ID */
info.dwCommonButtons = TDCBF_OK_BUTTON | TDCBF_YES_BUTTON | TDCBF_NO_BUTTON | TDCBF_CANCEL_BUTTON
| TDCBF_RETRY_BUTTON | TDCBF_CLOSE_BUTTON;
info.nDefaultButton = IDRETRY;
run_test(&info, IDRETRY, 0, FALSE, msg_return_press_retry, "default button: valid default - 1");
/* Test with common and custom buttons and valid default ID */
info.nDefaultButton = ID_START_BUTTON + 3;
run_test(&info, ID_START_BUTTON + 3, 0, FALSE, msg_return_press_custom4, "default button: valid default - 2");
}
/* Test radio buttons */
info.nDefaultButton = 0;
info.cButtons = 0;
info.pButtons = 0;
info.dwCommonButtons = TDCBF_OK_BUTTON;
info.cRadioButtons = TEST_NUM_RADIO_BUTTONS;
info.pRadioButtons = radio_buttons;
/* Test default first radio button */
run_test(&info, IDOK, ID_START_RADIO_BUTTON, FALSE, msg_return_default_radio_button_1,
"default radio button: default first radio button");
/* Test default radio button */
info.nDefaultRadioButton = ID_START_RADIO_BUTTON + 1;
run_test(&info, IDOK, info.nDefaultRadioButton, FALSE, msg_return_default_radio_button_2,
"default radio button: default radio button");
/* Test default radio button with -2 */
info.nDefaultRadioButton = -2;
run_test(&info, IDOK, info.nDefaultRadioButton, FALSE, msg_return_default_radio_button_3,
"default radio button: default radio button with id -2");
/* Test default radio button after clicking the first, messages still work even radio button is disabled */
info.nDefaultRadioButton = ID_START_RADIO_BUTTON + 1;
run_test(&info, IDOK, ID_START_RADIO_BUTTON, FALSE, msg_return_first_radio_button,
"default radio button: radio button after clicking");
/* Test radio button after disabling and clicking the first */
info.nDefaultRadioButton = ID_START_RADIO_BUTTON + 1;
run_test(&info, IDOK, ID_START_RADIO_BUTTON, FALSE, msg_return_default_radio_button_clicking_disabled,
"default radio button: disable radio button before clicking");
/* Test no default radio button, TDF_NO_DEFAULT_RADIO_BUTTON is set, TDN_RADIO_BUTTON_CLICKED will still be received, just radio button not selected */
info.nDefaultRadioButton = ID_START_RADIO_BUTTON;
info.dwFlags = TDF_NO_DEFAULT_RADIO_BUTTON;
run_test(&info, IDOK, info.nDefaultRadioButton, FALSE, msg_return_no_default_radio_button_flag,
"default radio button: no default radio flag");
/* Test no default radio button, TDF_NO_DEFAULT_RADIO_BUTTON is set and nDefaultRadioButton is 0.
* TDN_RADIO_BUTTON_CLICKED will not be sent, and just radio button not selected */
info.nDefaultRadioButton = 0;
info.dwFlags = TDF_NO_DEFAULT_RADIO_BUTTON;
run_test(&info, IDOK, 0, FALSE, msg_return_no_default_radio_button_id_and_flag,
"default radio button: no default radio id and flag");
/* Test no default radio button, TDF_NO_DEFAULT_RADIO_BUTTON is set and nDefaultRadioButton is invalid.
* TDN_RADIO_BUTTON_CLICKED will not be sent, and just radio button not selected */
info.nDefaultRadioButton = 0xff;
info.dwFlags = TDF_NO_DEFAULT_RADIO_BUTTON;
run_test(&info, IDOK, 0, FALSE, msg_return_no_default_radio_button_id_and_flag,
"default radio button: no default flag, invalid id");
info.nDefaultRadioButton = 0;
info.dwFlags = TDF_NO_DEFAULT_RADIO_BUTTON;
run_test(&info, IDOK, -2, FALSE, msg_return_press_negative_id_radio_button,
"radio button: manually click radio button with negative id");
/* Test sending clicks to non-existent buttons. Notification of non-existent buttons will be sent */
info.cButtons = TEST_NUM_BUTTONS;
info.pButtons = custom_buttons;
run_test(&info, ID_START_BUTTON, msg_return_press_custom1, "default button: invalid default, with common buttons - 1");
info.nDefaultButton = -1; /* Should work despite button ID -1 */
run_test(&info, -1, msg_return_press_custom10, "default button: invalid default, with common buttons - 2");
info.nDefaultButton = -2; /* Should also default to first created button */
run_test(&info, ID_START_BUTTON, msg_return_press_custom1, "default button: invalid default, with common buttons - 3");
/* Test with only custom buttons and invalid default ID */
info.cRadioButtons = TEST_NUM_RADIO_BUTTONS;
info.pRadioButtons = radio_buttons;
info.dwCommonButtons = 0;
run_test(&info, ID_START_BUTTON, msg_return_press_custom1, "default button: invalid default, no common buttons");
info.dwFlags = TDF_NO_DEFAULT_RADIO_BUTTON;
run_test(&info, ID_START_BUTTON + 99, 0, FALSE, msg_press_nonexistent_buttons, "sends click to non-existent buttons");
/* Test with common and custom buttons and valid default ID */
info.dwCommonButtons = TDCBF_OK_BUTTON | TDCBF_YES_BUTTON | TDCBF_NO_BUTTON
| TDCBF_CANCEL_BUTTON | TDCBF_RETRY_BUTTON | TDCBF_CLOSE_BUTTON;
info.nDefaultButton = IDRETRY;
run_test(&info, IDRETRY, msg_return_press_retry, "default button: valid default - 1");
/* Non-existent button clicks sent by WM_COMMAND won't generate TDN_BUTTON_CLICKED except IDOK.
* And will get the first existent button identifier instead of IDOK */
run_test(&info, ID_START_BUTTON, 0, FALSE, msg_press_nonexistent_buttons_with_command,
"sends click to non-existent buttons with WM_COMMAND");
/* Test with common and custom buttons and valid default ID */
info.nDefaultButton = ID_START_BUTTON + 3;
run_test(&info, ID_START_BUTTON + 3, msg_return_press_custom4, "default button: valid default - 2");
/* Non-existent radio button won't get notifications */
run_test(&info, IDOK, 0, FALSE, msg_press_nonexistent_radio_button, "sends click to non-existent radio buttons");
}
static void test_help(void)
{
TASKDIALOGCONFIG info = {0};
info.cbSize = sizeof(TASKDIALOGCONFIG);
info.pfCallback = taskdialog_callback_proc;
info.lpCallbackData = test_ref_data;
info.dwCommonButtons = TDCBF_OK_BUTTON;
run_test(&info, IDOK, 0, FALSE, msg_got_tdn_help, "send f1");
}
struct timer_notification_data
{
DWORD last_elapsed_ms;
DWORD num_fired;
};
static HRESULT CALLBACK taskdialog_callback_proc_timer(HWND hwnd, UINT notification,
WPARAM wParam, LPARAM lParam, LONG_PTR ref_data)
{
struct timer_notification_data *data = (struct timer_notification_data *)ref_data;
if (notification == TDN_TIMER)
{
DWORD elapsed_ms;
int delta;
elapsed_ms = (DWORD)wParam;
if (data->num_fired == 3)
ok(data->last_elapsed_ms > elapsed_ms, "Expected reference time update.\n");
else
{
delta = elapsed_ms - data->last_elapsed_ms;
ok(delta > 0, "Expected positive time tick difference.\n");
}
data->last_elapsed_ms = elapsed_ms;
if (data->num_fired == 3)
PostMessageW(hwnd, TDM_CLICK_BUTTON, IDOK, 0);
++data->num_fired;
return data->num_fired == 3 ? S_FALSE : S_OK;
}
return S_OK;
}
static void test_timer(void)
{
struct timer_notification_data data = { 0 };
TASKDIALOGCONFIG info = { 0 };
info.cbSize = sizeof(TASKDIALOGCONFIG);
info.pfCallback = taskdialog_callback_proc_timer;
info.lpCallbackData = (LONG_PTR)&data;
info.dwFlags = TDF_CALLBACK_TIMER;
info.dwCommonButtons = TDCBF_OK_BUTTON;
pTaskDialogIndirect(&info, NULL, NULL, NULL);
}
static HRESULT CALLBACK taskdialog_callback_proc_progress_bar(HWND hwnd, UINT notification, WPARAM wParam,
LPARAM lParam, LONG_PTR ref_data)
{
unsigned long ret;
LONG flags = (LONG)ref_data;
if (notification == TDN_CREATED)
{
/* TDM_SET_PROGRESS_BAR_STATE */
ret = SendMessageW(hwnd, TDM_SET_PROGRESS_BAR_STATE, PBST_NORMAL, 0);
ok(ret == PBST_NORMAL, "Expect state: %d got state: %lx\n", PBST_NORMAL, ret);
ret = SendMessageW(hwnd, TDM_SET_PROGRESS_BAR_STATE, PBST_PAUSED, 0);
ok(ret == PBST_NORMAL, "Expect state: %d got state: %lx\n", PBST_NORMAL, ret);
ret = SendMessageW(hwnd, TDM_SET_PROGRESS_BAR_STATE, PBST_ERROR, 0);
/* Progress bar has fixme on handling PBM_SETSTATE message */
todo_wine ok(ret == PBST_PAUSED, "Expect state: %d got state: %lx\n", PBST_PAUSED, ret);
ret = SendMessageW(hwnd, TDM_SET_PROGRESS_BAR_STATE, PBST_NORMAL, 0);
todo_wine ok(ret == PBST_ERROR, "Expect state: %d got state: %lx\n", PBST_ERROR, ret);
/* TDM_SET_PROGRESS_BAR_RANGE */
ret = SendMessageW(hwnd, TDM_SET_PROGRESS_BAR_RANGE, 0, MAKELPARAM(0, 200));
ok(ret == MAKELONG(0, 100), "Expect range:%x got:%lx\n", MAKELONG(0, 100), ret);
ret = SendMessageW(hwnd, TDM_SET_PROGRESS_BAR_RANGE, 0, MAKELPARAM(0, 200));
ok(ret == MAKELONG(0, 200), "Expect range:%x got:%lx\n", MAKELONG(0, 200), ret);
/* TDM_SET_PROGRESS_BAR_POS */
if (flags & TDF_SHOW_MARQUEE_PROGRESS_BAR)
{
ret = SendMessageW(hwnd, TDM_SET_PROGRESS_BAR_POS, 1, 0);
ok(ret == 0, "Expect position:%x got:%lx\n", 0, ret);
ret = SendMessageW(hwnd, TDM_SET_PROGRESS_BAR_POS, 2, 0);
ok(ret == 0, "Expect position:%x got:%lx\n", 0, ret);
}
else
{
ret = SendMessageW(hwnd, TDM_SET_PROGRESS_BAR_POS, 1, 0);
ok(ret == 0, "Expect position:%x got:%lx\n", 0, ret);
ret = SendMessageW(hwnd, TDM_SET_PROGRESS_BAR_POS, 2, 0);
ok(ret == 1, "Expect position:%x got:%lx\n", 1, ret);
}
SendMessageW(hwnd, TDM_CLICK_BUTTON, IDOK, 0);
}
return S_OK;
}
static void test_progress_bar(void)
{
TASKDIALOGCONFIG info = {0};
info.cbSize = sizeof(TASKDIALOGCONFIG);
info.dwFlags = TDF_SHOW_PROGRESS_BAR;
info.pfCallback = taskdialog_callback_proc_progress_bar;
info.lpCallbackData = (LONG_PTR)info.dwFlags;
info.dwCommonButtons = TDCBF_OK_BUTTON;
pTaskDialogIndirect(&info, NULL, NULL, NULL);
info.dwFlags = TDF_SHOW_MARQUEE_PROGRESS_BAR;
info.lpCallbackData = (LONG_PTR)info.dwFlags;
pTaskDialogIndirect(&info, NULL, NULL, NULL);
info.dwFlags = TDF_SHOW_PROGRESS_BAR | TDF_SHOW_MARQUEE_PROGRESS_BAR;
info.lpCallbackData = (LONG_PTR)info.dwFlags;
pTaskDialogIndirect(&info, NULL, NULL, NULL);
}
static void test_verification_box(void)
{
TASKDIALOGCONFIG info = {0};
WCHAR textW[] = {'t', 'e', 'x', 't', 0};
info.cbSize = sizeof(TASKDIALOGCONFIG);
info.pfCallback = taskdialog_callback_proc;
info.lpCallbackData = test_ref_data;
info.dwCommonButtons = TDCBF_OK_BUTTON;
/* TDF_VERIFICATION_FLAG_CHECKED works even if pszVerificationText is not set */
run_test(&info, IDOK, 0, FALSE, msg_return_default_verification_unchecked, "default verification box: unchecked");
info.dwFlags = TDF_VERIFICATION_FLAG_CHECKED;
run_test(&info, IDOK, 0, FALSE, msg_return_default_verification_checked, "default verification box: checked");
info.pszVerificationText = textW;
run_test(&info, IDOK, 0, FALSE, msg_return_default_verification_unchecked, "default verification box: unchecked");
info.dwFlags = TDF_VERIFICATION_FLAG_CHECKED;
run_test(&info, IDOK, 0, FALSE, msg_return_default_verification_checked, "default verification box: checked");
run_test(&info, IDOK, 0, FALSE, msg_return_verification_unchecked,
"default verification box: default checked and then unchecked");
info.dwFlags = 0;
run_test(&info, IDOK, 0, FALSE, msg_return_verification_checked,
"default verification box: default unchecked and then checked");
}
static void test_navigate_page(void)
{
TASKDIALOGCONFIG info = {0};
static const WCHAR textW[] = {'t', 'e', 'x', 't', 0};
static const WCHAR button_format[] = {'%', '0', '2', 'd', 0};
TASKDIALOG_BUTTON radio_buttons[TEST_NUM_RADIO_BUTTONS];
WCHAR radio_button_titles[TEST_NUM_BUTTONS * 3];
int i;
/* Init radio buttons */
for (i = 0; i < TEST_NUM_RADIO_BUTTONS; i++)
{
WCHAR *text = &radio_button_titles[i * 3];
wsprintfW(text, button_format, i);
radio_buttons[i].pszButtonText = text;
radio_buttons[i].nButtonID = ID_START_RADIO_BUTTON + i;
}
info.cbSize = sizeof(TASKDIALOGCONFIG);
info.pfCallback = taskdialog_callback_proc;
info.lpCallbackData = test_ref_data;
info.dwCommonButtons = TDCBF_OK_BUTTON;
info.cRadioButtons = TEST_NUM_RADIO_BUTTONS;
info.pRadioButtons = radio_buttons;
navigated_info = info;
navigated_info.pszVerificationText = textW;
navigated_info.dwFlags = TDF_VERIFICATION_FLAG_CHECKED;
run_test(&info, IDOK, ID_START_RADIO_BUTTON, TRUE, msg_return_navigated_page, "navigate page: default");
/* TDM_NAVIGATE_PAGE doesn't check cbSize.
* And null taskconfig pointer crash applicatioin, thus doesn't check pointer either */
navigated_info.cbSize = 0;
run_test(&info, IDOK, ID_START_RADIO_BUTTON, TRUE, msg_return_navigated_page, "navigate page: invalid taskconfig cbSize");
}
static void test_wm_close(void)
{
TASKDIALOGCONFIG info = {0};
info.cbSize = sizeof(TASKDIALOGCONFIG);
info.pfCallback = taskdialog_callback_proc;
info.lpCallbackData = test_ref_data;
/* WM_CLOSE can end the dialog only when a cancel button is present or dwFlags has TDF_ALLOW_DIALOG_CANCELLATION */
info.dwCommonButtons = TDCBF_OK_BUTTON;
run_test(&info, IDOK, 0, FALSE, msg_handle_wm_close_without_cancel_button, "send WM_CLOSE without cancel button");
info.dwFlags = TDF_ALLOW_DIALOG_CANCELLATION;
run_test(&info, IDCANCEL, 0, FALSE, msg_handle_wm_close, "send WM_CLOSE with TDF_ALLOW_DIALOG_CANCELLATION");
info.dwFlags = 0;
info.dwCommonButtons = TDCBF_CANCEL_BUTTON;
run_test(&info, IDCANCEL, 0, FALSE, msg_handle_wm_close, "send WM_CLOSE with a cancel button");
}
START_TEST(taskdialog)
@ -327,6 +904,12 @@ START_TEST(taskdialog)
test_invalid_parameters();
test_callback();
test_buttons();
test_help();
test_timer();
test_progress_bar();
test_verification_box();
test_navigate_page();
test_wm_close();
unload_v6_module(ctx_cookie, hCtx);
}

View file

@ -56,7 +56,6 @@ static BOOL g_ResetDispTextPtr;
static const struct message ttgetdispinfo_parent_seq[] = {
{ WM_NOTIFY, sent|id, 0, 0, TBN_GETINFOTIPA },
/* next line is todo, currently TTN_GETDISPINFOW is raised here */
{ WM_NOTIFY, sent|id, 0, 0, TTN_GETDISPINFOA },
{ 0 }
};
@ -388,7 +387,7 @@ static void basic_test(void)
WS_CHILD | TBSTYLE_LIST,
100,
0, NULL, 0,
buttons, sizeof(buttons)/sizeof(buttons[0]),
buttons, ARRAY_SIZE(buttons),
0, 0, 20, 16, sizeof(TBBUTTON));
ok(hToolbar != NULL, "Toolbar creation\n");
SendMessageA(hToolbar, TB_ADDSTRINGA, 0, (LPARAM)"test\000");
@ -1316,7 +1315,7 @@ static DWORD tbsize_alt_numtests = 0;
compare(buttonCount, res->nButtons, "%d"); \
for (i=0; i<min(buttonCount, res->nButtons); i++) { \
ok(SendMessageA(hToolbar, TB_GETITEMRECT, i, (LPARAM)&rc) == 1, "TB_GETITEMRECT\n"); \
if (broken(tbsize_alt_numtests < sizeof(tbsize_alt_results)/sizeof(tbsize_alt_results[0]) && \
if (broken(tbsize_alt_numtests < ARRAY_SIZE(tbsize_alt_results) && \
EqualRect(&rc, &tbsize_alt_results[tbsize_alt_numtests].rcButton))) { \
win_skip("Alternate rect found\n"); \
tbsize_alt_numtests++; \
@ -1940,13 +1939,13 @@ static void test_setrows(void)
| CCS_NOMOVEY | CCS_TOP,
0,
0, NULL, 0,
buttons, sizeof(buttons)/sizeof(buttons[0]),
buttons, ARRAY_SIZE(buttons),
20, 20, 0, 0, sizeof(TBBUTTON));
ok(hToolbar != NULL, "Toolbar creation\n");
ok(SendMessageA(hToolbar, TB_AUTOSIZE, 0, 0) == 0, "TB_AUTOSIZE failed\n");
/* test setting rows to each of 1-10 with bLarger true and false */
for (i=0; i<(sizeof(tbrows_results) / sizeof(tbrows_result_t)); i++) {
for (i=0; i<ARRAY_SIZE(tbrows_results); i++) {
RECT rc;
int rows;
@ -2026,7 +2025,7 @@ static void test_tooltip(void)
flush_sequences(sequences, NUM_MSG_SEQUENCES);
SendMessageA(hToolbar, WM_NOTIFY, 0, (LPARAM)&nmtti);
ok_sequence(sequences, PARENT_SEQ_INDEX, ttgetdispinfo_parent_seq,
"dispinfo from tooltip", TRUE);
"dispinfo from tooltip", FALSE);
g_ResetDispTextPtr = TRUE;
SendMessageA(hToolbar, WM_NOTIFY, 0, (LPARAM)&nmtti);
@ -2059,7 +2058,7 @@ static void test_get_set_style(void)
WS_CHILD | TBSTYLE_LIST,
100,
0, NULL, 0,
buttons, sizeof(buttons)/sizeof(buttons[0]),
buttons, ARRAY_SIZE(buttons),
0, 0, 20, 16, sizeof(TBBUTTON));
ok(hToolbar != NULL, "Toolbar creation\n");
SendMessageA(hToolbar, TB_ADDSTRINGA, 0, (LPARAM)"test\000");
@ -2277,7 +2276,7 @@ static void test_TB_GET_SET_EXTENDEDSTYLE(void)
return;
}
for (i = 0; i < sizeof(extended_style_test)/sizeof(extended_style_t); i++)
for (i = 0; i < ARRAY_SIZE(extended_style_test); i++)
{
ptr = &extended_style_test[i];
@ -2398,7 +2397,7 @@ static void test_save(void)
params.pszValueName = value;
rebuild_toolbar_with_buttons( &wnd );
SendMessageW( wnd, TB_ADDBUTTONSW, sizeof(more_btns) / sizeof(more_btns[0]), (LPARAM)more_btns );
SendMessageW(wnd, TB_ADDBUTTONSW, ARRAY_SIZE(more_btns), (LPARAM)more_btns);
flush_sequences(sequences, NUM_MSG_SEQUENCES);
res = SendMessageW( wnd, TB_SAVERESTOREW, TRUE, (LPARAM)&params );
@ -2424,7 +2423,7 @@ static void test_save(void)
ok( res, "restoring failed\n" );
ok_sequence(sequences, PARENT_SEQ_INDEX, restore_parent_seq, "restore", FALSE);
count = SendMessageW( wnd, TB_BUTTONCOUNT, 0, 0 );
ok( count == sizeof(expect_btns) / sizeof(expect_btns[0]), "got %d\n", count );
ok( count == ARRAY_SIZE(expect_btns), "got %d\n", count );
for (i = 0; i < count; i++)
{

View file

@ -183,7 +183,7 @@ static void test_customdraw(void) {
GetCursorPos(&orig_pos);
for (iterationNumber = 0;
iterationNumber < sizeof(expectedResults)/sizeof(expectedResults[0]);
iterationNumber < ARRAY_SIZE(expectedResults);
iterationNumber++) {
HWND parent, hwndTip;
@ -821,7 +821,7 @@ static void test_longtextW(void)
toolinfoW.hinst = GetModuleHandleW(NULL);
toolinfoW.uFlags = 0;
toolinfoW.uId = 0x1234ABCD;
MultiByteToWideChar(CP_ACP, 0, longtextA, -1, bufW, sizeof(bufW)/sizeof(bufW[0]));
MultiByteToWideChar(CP_ACP, 0, longtextA, -1, bufW, ARRAY_SIZE(bufW));
lenW = lstrlenW(bufW);
toolinfoW.lpszText = bufW;
toolinfoW.lParam = 0xdeadbeef;

View file

@ -577,6 +577,58 @@ static void test_page_size(void)
hWndTrackbar = create_trackbar(defaultstyle, hWndParent);
ok(hWndTrackbar != NULL, "Expected non NULL value\n");
r = SendMessageA(hWndTrackbar, TBM_GETPAGESIZE, 0, 0);
ok(r == 20, "Unexpected page size %d.\n", r);
SendMessageA(hWndTrackbar, TBM_SETRANGE, 0, MAKELPARAM(0, 65));
r = SendMessageA(hWndTrackbar, TBM_GETPAGESIZE, 0, 0);
ok(r == 13, "Unexpected page size %d.\n", r);
SendMessageA(hWndTrackbar, TBM_SETRANGEMIN, 0, 10);
r = SendMessageA(hWndTrackbar, TBM_GETPAGESIZE, 0, 0);
ok(r == 11, "Unexpected page size %d.\n", r);
SendMessageA(hWndTrackbar, TBM_SETRANGEMAX, 0, 50);
r = SendMessageA(hWndTrackbar, TBM_GETPAGESIZE, 0, 0);
ok(r == 8, "Unexpected page size %d.\n", r);
r = SendMessageA(hWndTrackbar, TBM_SETPAGESIZE, 0, 10);
ok(r == 8, "Unexpected page size %d.\n", r);
SendMessageA(hWndTrackbar, TBM_SETRANGE, 0, MAKELPARAM(0, 30));
r = SendMessageA(hWndTrackbar, TBM_GETPAGESIZE, 0, 0);
ok(r == 10, "Unexpected page size %d.\n", r);
SendMessageA(hWndTrackbar, TBM_SETRANGEMIN, 0, 5);
r = SendMessageA(hWndTrackbar, TBM_GETPAGESIZE, 0, 0);
ok(r == 10, "Unexpected page size %d.\n", r);
SendMessageA(hWndTrackbar, TBM_SETRANGEMAX, 0, 40);
r = SendMessageA(hWndTrackbar, TBM_GETPAGESIZE, 0, 0);
ok(r == 10, "Unexpected page size %d.\n", r);
r = SendMessageA(hWndTrackbar, TBM_SETPAGESIZE, 0, -1);
ok(r == 10, "Unexpected page size %d.\n", r);
r = SendMessageA(hWndTrackbar, TBM_GETPAGESIZE, 0, 0);
ok(r == 7, "Unexpected page size %d.\n", r);
SendMessageA(hWndTrackbar, TBM_SETRANGEMAX, 0, 100);
r = SendMessageA(hWndTrackbar, TBM_GETPAGESIZE, 0, 0);
ok(r == 19, "Unexpected page size %d.\n", r);
DestroyWindow(hWndTrackbar);
hWndTrackbar = create_trackbar(defaultstyle, hWndParent);
ok(hWndTrackbar != NULL, "Failed to create trackbar window.\n");
flush_sequences(sequences, NUM_MSG_SEQUENCE);
/* test TBM_SETPAGESIZE */

View file

@ -527,7 +527,7 @@ static void test_callback(void)
tvi.hItem = hRoot;
tvi.mask = TVIF_TEXT;
tvi.pszText = buf;
tvi.cchTextMax = sizeof(buf)/sizeof(buf[0]);
tvi.cchTextMax = ARRAY_SIZE(buf);
ret = TreeView_GetItemA(hTree, &tvi);
expect(TRUE, ret);
ok(strcmp(tvi.pszText, TEST_CALLBACK_TEXT) == 0, "Callback item text mismatch %s vs %s\n",
@ -706,7 +706,7 @@ static void test_getitemtext(void)
HWND hTree;
CHAR szBuffer[80] = "Blah";
int nBufferSize = sizeof(szBuffer)/sizeof(CHAR);
int nBufferSize = ARRAY_SIZE(szBuffer);
hTree = create_treeview_control(0);
fill_tree(hTree);
@ -1528,6 +1528,49 @@ static void test_expandinvisible(void)
DestroyWindow(hTree);
}
static void test_expand(void)
{
HTREEITEM first, second, last, child;
TVINSERTSTRUCTA ins;
BOOL visible;
RECT rect;
HWND tv;
int i;
tv = create_treeview_control(0);
ins.hParent = TVI_ROOT;
ins.hInsertAfter = TVI_LAST;
U(ins).item.mask = 0;
first = TreeView_InsertItemA(tv, &ins);
ok(first != NULL, "failed to insert first node\n");
second = TreeView_InsertItemA(tv, &ins);
ok(second != NULL, "failed to insert second node\n");
for (i=0; i<100; i++)
{
last = TreeView_InsertItemA(tv, &ins);
ok(last != NULL, "failed to insert %d node\n", i);
}
ins.hParent = second;
child = TreeView_InsertItemA(tv, &ins);
ok(child != NULL, "failed to insert child node\n");
ok(SendMessageA(tv, TVM_SELECTITEM, TVGN_CARET, (LPARAM)last), "last node selection failed\n");
ok(SendMessageA(tv, TVM_EXPAND, TVE_EXPAND, (LPARAM)second), "expand of second node failed\n");
ok(SendMessageA(tv, TVM_SELECTITEM, TVGN_CARET, (LPARAM)first), "first node selection failed\n");
*(HTREEITEM *)&rect = first;
visible = SendMessageA(tv, TVM_GETITEMRECT, FALSE, (LPARAM)&rect);
ok(visible, "first node should be visible\n");
ok(!rect.left, "rect.left = %d\n", rect.left);
ok(!rect.top, "rect.top = %d\n", rect.top);
ok(rect.right, "rect.right = 0\n");
ok(rect.bottom, "rect.bottom = 0\n");
DestroyWindow(tv);
}
static void test_itemedit(void)
{
DWORD r;
@ -1587,7 +1630,7 @@ static void test_itemedit(void)
item.mask = TVIF_TEXT;
item.hItem = hRoot;
item.pszText = buffA;
item.cchTextMax = sizeof(buffA)/sizeof(CHAR);
item.cchTextMax = ARRAY_SIZE(buffA);
r = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item);
expect(TRUE, r);
ok(!strcmp("x", buffA), "Expected item text to change\n");
@ -1621,7 +1664,7 @@ static void test_itemedit(void)
ok(IsWindow(edit), "Expected valid handle\n");
g_beginedit_alter_text = FALSE;
GetWindowTextA(edit, buffA, sizeof(buffA)/sizeof(CHAR));
GetWindowTextA(edit, buffA, ARRAY_SIZE(buffA));
ok(!strcmp(buffA, "<edittextaltered>"), "got string %s\n", buffA);
DestroyWindow(hTree);
@ -1948,7 +1991,7 @@ static void test_TVS_SINGLEEXPAND(void)
SetWindowLongA(hTree, GWL_STYLE, GetWindowLongA(hTree, GWL_STYLE) | TVS_SINGLEEXPAND);
/* to avoid painting related notifications */
ShowWindow(hTree, SW_HIDE);
for (i = 0; i < sizeof(items)/sizeof(items[0]); i++)
for (i = 0; i < ARRAY_SIZE(items); i++)
{
ins.hParent = items[i].parent ? *items[i].parent : TVI_ROOT;
ins.hInsertAfter = TVI_FIRST;
@ -1957,7 +2000,7 @@ static void test_TVS_SINGLEEXPAND(void)
*items[i].handle = TreeView_InsertItemA(hTree, &ins);
}
for (i = 0; i < sizeof(sequence_tests)/sizeof(sequence_tests[0]); i++)
for (i = 0; i < ARRAY_SIZE(sequence_tests); i++)
{
flush_sequences(sequences, NUM_MSG_SEQUENCES);
ret = SendMessageA(hTree, TVM_SELECTITEM, TVGN_CARET, (LPARAM)(*sequence_tests[i].select));
@ -1966,7 +2009,7 @@ static void test_TVS_SINGLEEXPAND(void)
ok_sequence(sequences, PARENT_SEQ_INDEX, sequence_tests[i].sequence, context, FALSE);
}
for (i = 0; i < sizeof(items)/sizeof(items[0]); i++)
for (i = 0; i < ARRAY_SIZE(items); i++)
{
ret = SendMessageA(hTree, TVM_GETITEMSTATE, (WPARAM)(*items[i].handle), 0xFFFF);
ok(ret == items[i].final_state, "singleexpand items[%d]: expected state 0x%x got 0x%x\n",
@ -2132,20 +2175,64 @@ struct _ITEM_DATA
HTREEITEM parent; /* for root value of parent field is unidetified */
HTREEITEM nextsibling;
HTREEITEM firstchild;
void *unk[2];
DWORD unk2;
WORD pad;
WORD width;
};
static void _check_item(HTREEITEM item, HTREEITEM parent, HTREEITEM nextsibling, HTREEITEM firstchild, int line)
struct _ITEM_DATA_V6
{
struct _ITEM_DATA *data = (struct _ITEM_DATA*)item;
HTREEITEM parent; /* for root value of parent field is unidetified */
HTREEITEM nextsibling;
HTREEITEM firstchild;
void *unk[3];
DWORD unk2[2];
WORD pad;
WORD width;
};
ok_(__FILE__, line)(data->parent == parent, "parent %p, got %p\n", parent, data->parent);
ok_(__FILE__, line)(data->nextsibling == nextsibling, "sibling %p, got %p\n", nextsibling, data->nextsibling);
ok_(__FILE__, line)(data->firstchild == firstchild, "firstchild %p, got %p\n", firstchild, data->firstchild);
static void _check_item(HWND hwnd, HTREEITEM item, BOOL is_version_6, int line)
{
struct _ITEM_DATA *data = (struct _ITEM_DATA *)item;
HTREEITEM parent, nextsibling, firstchild, root;
RECT rect;
BOOL ret;
root = (HTREEITEM)SendMessageA(hwnd, TVM_GETNEXTITEM, TVGN_ROOT, (LPARAM)item);
parent = (HTREEITEM)SendMessageA(hwnd, TVM_GETNEXTITEM, TVGN_PARENT, (LPARAM)item);
nextsibling = (HTREEITEM)SendMessageA(hwnd, TVM_GETNEXTITEM, TVGN_NEXT, (LPARAM)item);
firstchild = (HTREEITEM)SendMessageA(hwnd, TVM_GETNEXTITEM, TVGN_CHILD, (LPARAM)item);
*(HTREEITEM*)&rect = item;
ret = SendMessageA(hwnd, TVM_GETITEMRECT, TRUE, (LPARAM)&rect);
ok_(__FILE__, line)(item == root ? data->parent != NULL : data->parent == parent,
"Unexpected parent item %p, got %p, %p\n", parent, data->parent, hwnd);
ok_(__FILE__, line)(data->nextsibling == nextsibling, "Unexpected sibling %p, got %p\n",
nextsibling, data->nextsibling);
ok_(__FILE__, line)(data->firstchild == firstchild, "Unexpected first child %p, got %p\n",
firstchild, data->firstchild);
if (ret)
{
WORD width;
if (is_version_6)
{
struct _ITEM_DATA_V6 *data_v6 = (struct _ITEM_DATA_V6 *)item;
width = data_v6->width;
}
else
width = data->width;
todo_wine
ok_(__FILE__, line)(width == (rect.right - rect.left) || broken(is_version_6 && width == 0) /* XP */,
"Width %d, rect width %d.\n", width, rect.right - rect.left);
}
}
#define check_item(a, b, c, d) _check_item(a, b, c, d, __LINE__)
#define CHECK_ITEM(a, b) _check_item(a, b, is_version_6, __LINE__)
static void test_htreeitem_layout(void)
static void test_htreeitem_layout(BOOL is_version_6)
{
TVINSERTSTRUCTA ins;
HTREEITEM item1, item2;
@ -2155,27 +2242,27 @@ static void test_htreeitem_layout(void)
fill_tree(hTree);
/* root has some special pointer in parent field */
check_item(hRoot, ((struct _ITEM_DATA*)hRoot)->parent, 0, hChild);
check_item(hChild, hRoot, 0, 0);
CHECK_ITEM(hTree, hRoot);
CHECK_ITEM(hTree, hChild);
ins.hParent = hChild;
ins.hInsertAfter = TVI_FIRST;
U(ins).item.mask = 0;
item1 = TreeView_InsertItemA(hTree, &ins);
check_item(item1, hChild, 0, 0);
CHECK_ITEM(hTree, item1);
ins.hParent = hRoot;
ins.hInsertAfter = TVI_FIRST;
U(ins).item.mask = 0;
item2 = TreeView_InsertItemA(hTree, &ins);
check_item(item2, hRoot, hChild, 0);
CHECK_ITEM(hTree, item2);
SendMessageA(hTree, TVM_DELETEITEM, 0, (LPARAM)hChild);
/* without children now */
check_item(hRoot, ((struct _ITEM_DATA*)hRoot)->parent, 0, item2);
CHECK_ITEM(hTree, hRoot);
DestroyWindow(hTree);
}
@ -2722,15 +2809,7 @@ static void test_right_click(void)
HTREEITEM selected;
RECT rc;
LRESULT result;
POINT pt;
#ifdef __REACTOS__
if (!winetest_interactive)
{
skip("test_right_click() (set WINETEST_INTERACTIVE=1), until CORE-14975 is fixed upstream and WINESYNC\n");
return;
}
#endif
POINT pt, orig_pos;
hTree = create_treeview_control(0);
fill_tree(hTree);
@ -2749,6 +2828,8 @@ static void test_right_click(void)
pt.x = (rc.left + rc.right) / 2;
pt.y = (rc.top + rc.bottom) / 2;
ClientToScreen(hMainWnd, &pt);
GetCursorPos(&orig_pos);
SetCursorPos(pt.x, pt.y);
flush_events();
flush_sequences(sequences, NUM_MSG_SEQUENCES);
@ -2764,6 +2845,7 @@ static void test_right_click(void)
selected = (HTREEITEM)SendMessageA(hTree, TVM_GETNEXTITEM, TVGN_CARET, 0);
ok(selected == hChild, "child item should still be selected\n");
SetCursorPos(orig_pos.x, orig_pos.y);
DestroyWindow(hTree);
}
@ -2835,7 +2917,7 @@ START_TEST(treeview)
test_WM_PAINT();
test_delete_items();
test_cchildren();
test_htreeitem_layout();
test_htreeitem_layout(FALSE);
test_TVS_CHECKBOXES();
test_TVM_GETNEXTITEM();
test_TVM_HITTEST();
@ -2867,11 +2949,12 @@ START_TEST(treeview)
test_get_set_tooltips();
test_get_set_unicodeformat();
test_expandinvisible();
test_expand();
test_itemedit();
test_treeview_classinfo();
test_delete_items();
test_cchildren();
test_htreeitem_layout();
test_htreeitem_layout(TRUE);
test_TVM_GETNEXTITEM();
test_TVM_HITTEST();
test_WM_GETDLGCODE();

View file

@ -697,13 +697,13 @@ static void test_updown_base(void)
r = SendMessageA(updown, UDM_SETPOS, 0, 10);
expect(50, r);
GetWindowTextA(g_edit, text, sizeof(text)/sizeof(CHAR));
GetWindowTextA(g_edit, text, ARRAY_SIZE(text));
ok(lstrcmpA(text, "10") == 0, "Expected '10', got '%s'\n", text);
r = SendMessageA(updown, UDM_SETBASE, 16, 0);
expect(10, r);
GetWindowTextA(g_edit, text, sizeof(text)/sizeof(CHAR));
GetWindowTextA(g_edit, text, ARRAY_SIZE(text));
/* FIXME: currently hex output isn't properly formatted, but for this
test only change from initial text matters */
ok(lstrcmpA(text, "10") != 0, "Expected '0x000A', got '%s'\n", text);
@ -837,20 +837,20 @@ static void test_UDS_SETBUDDYINT(void)
style = GetWindowLongA(updown, GWL_STYLE);
ok(style & UDS_SETBUDDYINT, "Expected UDS_SETBUDDY to be set\n");
SendMessageA(updown, UDM_SETPOS, 0, 20);
GetWindowTextA(g_edit, text, sizeof(text)/sizeof(CHAR));
GetWindowTextA(g_edit, text, ARRAY_SIZE(text));
ok(lstrlenA(text) == 0, "Expected empty string\n");
DestroyWindow(updown);
/* creating with UDS_SETBUDDYINT */
updown = create_updown_control(UDS_SETBUDDYINT | UDS_ALIGNRIGHT, g_edit);
GetWindowTextA(g_edit, text, sizeof(text)/sizeof(CHAR));
GetWindowTextA(g_edit, text, ARRAY_SIZE(text));
/* 50 is initial value here */
ok(lstrcmpA(text, "50") == 0, "Expected '50', got '%s'\n", text);
/* now remove style flag */
style = GetWindowLongA(updown, GWL_STYLE);
SetWindowLongA(updown, GWL_STYLE, style & ~UDS_SETBUDDYINT);
SendMessageA(updown, UDM_SETPOS, 0, 20);
GetWindowTextA(g_edit, text, sizeof(text)/sizeof(CHAR));
GetWindowTextA(g_edit, text, ARRAY_SIZE(text));
ok(lstrcmpA(text, "20") == 0, "Expected '20', got '%s'\n", text);
/* set edit text directly, check position */
strcpy(text, "10");
@ -872,7 +872,7 @@ static void test_UDS_SETBUDDYINT(void)
style = GetWindowLongA(updown, GWL_STYLE);
SetWindowLongA(updown, GWL_STYLE, style | UDS_SETBUDDYINT);
SendMessageA(updown, UDM_SETPOS, 0, 30);
GetWindowTextA(g_edit, text, sizeof(text)/sizeof(CHAR));
GetWindowTextA(g_edit, text, ARRAY_SIZE(text));
ok(lstrcmpA(text, "30") == 0, "Expected '30', got '%s'\n", text);
DestroyWindow(updown);
}