Newer
Older
/*
* ListView tests
*
* Copyright 2006 Mike McCormack for CodeWeavers
* Copyright 2009 Nikolay Sivov
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <stdio.h>
#include <windows.h>
#include <commctrl.h>
#include "wine/test.h"
#include "v6util.h"
#include "msg.h"
Nikolay Sivov
committed
#define PARENT_SEQ_INDEX 0
#define PARENT_FULL_SEQ_INDEX 1
#define LISTVIEW_SEQ_INDEX 2
Nikolay Sivov
committed
#define EDITBOX_SEQ_INDEX 3
#define NUM_MSG_SEQUENCES 4
#define LISTVIEW_ID 0
#define HEADER_ID 1
#define expect(expected, got) ok(got == expected, "Expected %d, got %d\n", expected, got)
#define expect2(expected1, expected2, got1, got2) ok(expected1 == got1 && expected2 == got2, \
"expected (%d,%d), got (%d,%d)\n", expected1, expected2, got1, got2)
static const WCHAR testparentclassW[] =
{'L','i','s','t','v','i','e','w',' ','t','e','s','t',' ','p','a','r','e','n','t','W', 0};
HWND hwndparent, hwndparentW;
Nikolay Sivov
committed
/* prevents edit box creation, LVN_BEGINLABELEDIT return value */
BOOL blockEdit;
/* dumps LVN_ITEMCHANGED message data */
static BOOL g_dump_itemchanged;
/* format reported to control:
-1 falls to defproc, anything else returned */
INT notifyFormat;
/* indicates we're running < 5.80 version */
BOOL g_is_below_5;
Nikolay Sivov
committed
static HWND subclass_editbox(HWND hwndListview);
static struct msg_sequence *sequences[NUM_MSG_SEQUENCES];
Nikolay Sivov
committed
static const struct message create_ownerdrawfixed_parent_seq[] = {
{ WM_NOTIFYFORMAT, sent },
{ WM_QUERYUISTATE, sent|optional }, /* Win2K and higher */
{ WM_MEASUREITEM, sent },
{ WM_PARENTNOTIFY, sent },
{ 0 }
};
static const struct message redraw_listview_seq[] = {
{ WM_PAINT, sent|id, 0, 0, LISTVIEW_ID },
{ WM_PAINT, sent|id, 0, 0, HEADER_ID },
{ WM_NCPAINT, sent|id|defwinproc, 0, 0, HEADER_ID },
{ WM_ERASEBKGND, sent|id|defwinproc|optional, 0, 0, HEADER_ID },
{ WM_NOTIFY, sent|id|defwinproc, 0, 0, LISTVIEW_ID },
{ WM_NCPAINT, sent|id|defwinproc, 0, 0, LISTVIEW_ID },
{ WM_ERASEBKGND, sent|id|defwinproc|optional, 0, 0, LISTVIEW_ID },
static const struct message listview_icon_spacing_seq[] = {
{ LVM_SETICONSPACING, sent|lparam, 0, MAKELPARAM(20, 30) },
{ LVM_SETICONSPACING, sent|lparam, 0, MAKELPARAM(25, 35) },
{ LVM_SETICONSPACING, sent|lparam, 0, MAKELPARAM(-1, -1) },
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
{ 0 }
};
static const struct message listview_color_seq[] = {
{ LVM_SETBKCOLOR, sent|lparam, 0, RGB(0,0,0) },
{ LVM_GETBKCOLOR, sent },
{ LVM_SETTEXTCOLOR, sent|lparam, 0, RGB(0,0,0) },
{ LVM_GETTEXTCOLOR, sent },
{ LVM_SETTEXTBKCOLOR, sent|lparam, 0, RGB(0,0,0) },
{ LVM_GETTEXTBKCOLOR, sent },
{ LVM_SETBKCOLOR, sent|lparam, 0, RGB(100,50,200) },
{ LVM_GETBKCOLOR, sent },
{ LVM_SETTEXTCOLOR, sent|lparam, 0, RGB(100,50,200) },
{ LVM_GETTEXTCOLOR, sent },
{ LVM_SETTEXTBKCOLOR, sent|lparam, 0, RGB(100,50,200) },
{ LVM_GETTEXTBKCOLOR, sent },
{ LVM_SETBKCOLOR, sent|lparam, 0, CLR_NONE },
{ LVM_GETBKCOLOR, sent },
{ LVM_SETTEXTCOLOR, sent|lparam, 0, CLR_NONE },
{ LVM_GETTEXTCOLOR, sent },
{ LVM_SETTEXTBKCOLOR, sent|lparam, 0, CLR_NONE },
{ LVM_GETTEXTBKCOLOR, sent },
{ LVM_SETBKCOLOR, sent|lparam, 0, RGB(255,255,255) },
{ LVM_GETBKCOLOR, sent },
{ LVM_SETTEXTCOLOR, sent|lparam, 0, RGB(255,255,255) },
{ LVM_GETTEXTCOLOR, sent },
{ LVM_SETTEXTBKCOLOR, sent|lparam, 0, RGB(255,255,255) },
{ LVM_GETTEXTBKCOLOR, sent },
{ 0 }
};
static const struct message listview_item_count_seq[] = {
{ LVM_GETITEMCOUNT, sent },
{ LVM_INSERTITEM, sent },
{ LVM_INSERTITEM, sent },
{ LVM_INSERTITEM, sent },
{ LVM_GETITEMCOUNT, sent },
{ LVM_DELETEITEM, sent|wparam, 2 },
{ WM_NCPAINT, sent|optional },
{ WM_ERASEBKGND, sent|optional },
{ LVM_GETITEMCOUNT, sent },
{ LVM_DELETEALLITEMS, sent },
{ LVM_GETITEMCOUNT, sent },
{ LVM_INSERTITEM, sent },
{ LVM_INSERTITEM, sent },
{ LVM_GETITEMCOUNT, sent },
{ LVM_INSERTITEM, sent },
{ LVM_GETITEMCOUNT, sent },
{ 0 }
};
static const struct message listview_itempos_seq[] = {
{ LVM_INSERTITEM, sent },
{ LVM_INSERTITEM, sent },
{ LVM_INSERTITEM, sent },
{ LVM_SETITEMPOSITION, sent|wparam|lparam, 1, MAKELPARAM(10,5) },
{ WM_NCPAINT, sent|optional },
{ WM_ERASEBKGND, sent|optional },
{ LVM_GETITEMPOSITION, sent|wparam, 1 },
{ LVM_SETITEMPOSITION, sent|wparam|lparam, 2, MAKELPARAM(0,0) },
{ LVM_GETITEMPOSITION, sent|wparam, 2 },
{ LVM_SETITEMPOSITION, sent|wparam|lparam, 0, MAKELPARAM(20,20) },
{ LVM_GETITEMPOSITION, sent|wparam, 0 },
{ 0 }
};
Nikolay Sivov
committed
static const struct message listview_ownerdata_switchto_seq[] = {
{ WM_STYLECHANGING, sent },
{ WM_STYLECHANGED, sent },
{ 0 }
};
Nikolay Sivov
committed
static const struct message listview_getorderarray_seq[] = {
{ LVM_GETCOLUMNORDERARRAY, sent|id|wparam, 2, 0, LISTVIEW_ID },
{ HDM_GETORDERARRAY, sent|id|wparam, 2, 0, HEADER_ID },
{ 0 }
};
static const struct message empty_seq[] = {
{ 0 }
};
Nikolay Sivov
committed
static const struct message forward_erasebkgnd_parent_seq[] = {
{ WM_ERASEBKGND, sent },
{ 0 }
};
static const struct message ownderdata_select_focus_parent_seq[] = {
{ WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
{ WM_NOTIFY, sent|id, 0, 0, LVN_GETDISPINFOA },
{ WM_NOTIFY, sent|id|optional, 0, 0, LVN_GETDISPINFOA }, /* version 4.7x */
{ 0 }
};
static const struct message ownerdata_setstate_all_parent_seq[] = {
{ WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
{ 0 }
};
static const struct message ownerdata_defocus_all_parent_seq[] = {
{ WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
{ WM_NOTIFY, sent|id, 0, 0, LVN_GETDISPINFOA },
{ WM_NOTIFY, sent|id|optional, 0, 0, LVN_GETDISPINFOA },
{ WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
{ 0 }
};
static const struct message ownerdata_deselect_all_parent_seq[] = {
{ WM_NOTIFY, sent|id, 0, 0, LVN_ODCACHEHINT },
{ WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
{ 0 }
};
static const struct message select_all_parent_seq[] = {
{ WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
{ WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
{ WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
{ WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
{ WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
{ WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
{ WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
{ WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
{ WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
{ WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
{ 0 }
};
static const struct message textcallback_set_again_parent_seq[] = {
{ WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGING },
{ WM_NOTIFY, sent|id, 0, 0, LVN_ITEMCHANGED },
{ 0 }
};
Nikolay Sivov
committed
static const struct message single_getdispinfo_parent_seq[] = {
{ WM_NOTIFY, sent|id, 0, 0, LVN_GETDISPINFOA },
{ 0 }
};
static const struct message getitemposition_seq1[] = {
{ LVM_GETITEMPOSITION, sent|id, 0, 0, LISTVIEW_ID },
{ 0 }
};
static const struct message getitemposition_seq2[] = {
{ LVM_GETITEMPOSITION, sent|id, 0, 0, LISTVIEW_ID },
{ HDM_GETITEMRECT, sent|id, 0, 0, HEADER_ID },
{ 0 }
};
Nikolay Sivov
committed
static const struct message editbox_create_pos[] = {
/* sequence sent after LVN_BEGINLABELEDIT */
/* next two are 4.7x specific */
Nikolay Sivov
committed
{ WM_WINDOWPOSCHANGING, sent },
{ WM_WINDOWPOSCHANGED, sent|optional },
{ WM_WINDOWPOSCHANGING, sent|optional },
Nikolay Sivov
committed
{ WM_NCCALCSIZE, sent },
{ WM_WINDOWPOSCHANGED, sent },
{ WM_MOVE, sent|defwinproc },
{ WM_SIZE, sent|defwinproc },
/* the rest is todo, skipped in 4.7x */
{ WM_WINDOWPOSCHANGING, sent|optional },
{ WM_WINDOWPOSCHANGED, sent|optional },
Nikolay Sivov
committed
{ 0 }
};
static const struct message scroll_parent_seq[] = {
{ WM_NOTIFY, sent|id, 0, 0, LVN_BEGINSCROLL },
{ WM_NOTIFY, sent|id, 0, 0, LVN_ENDSCROLL },
{ 0 }
};
static const struct message setredraw_seq[] = {
{ WM_SETREDRAW, sent|id|wparam, FALSE, 0, LISTVIEW_ID },
{ 0 }
};
static const struct message lvs_ex_transparentbkgnd_seq[] = {
{ WM_PRINTCLIENT, sent|lparam, 0, PRF_ERASEBKGND },
{ 0 }
};
struct subclass_info
{
WNDPROC oldproc;
};
static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static LONG defwndproc_counter = 0;
LRESULT ret;
struct message msg;
Nikolay Sivov
committed
msg.message = message;
msg.flags = sent|wparam|lparam;
if (defwndproc_counter) msg.flags |= defwinproc;
msg.wParam = wParam;
msg.lParam = lParam;
if (message == WM_NOTIFY && lParam) msg.id = ((NMHDR*)lParam)->code;
Nikolay Sivov
committed
/* log system messages, except for painting */
if (message < WM_USER &&
message != WM_PAINT &&
message != WM_ERASEBKGND &&
message != WM_NCPAINT &&
message != WM_NCHITTEST &&
message != WM_GETTEXT &&
message != WM_GETICON &&
message != WM_DEVICECHANGE)
{
trace("parent: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
add_message(sequences, PARENT_SEQ_INDEX, &msg);
}
Nikolay Sivov
committed
add_message(sequences, PARENT_FULL_SEQ_INDEX, &msg);
switch (message)
Nikolay Sivov
committed
{
case WM_NOTIFY:
{
switch (((NMHDR*)lParam)->code)
{
case LVN_BEGINLABELEDIT:
/* subclass edit box */
if (!blockEdit)
subclass_editbox(((NMHDR*)lParam)->hwndFrom);
return blockEdit;
case LVN_ENDLABELEDIT:
/* always accept new item text */
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_ITEMCHANGED:
if (g_dump_itemchanged)
{
NMLISTVIEW *nmlv = (NMLISTVIEW*)lParam;
trace("LVN_ITEMCHANGED: item=%d,new=%x,old=%x,changed=%x\n",
nmlv->iItem, nmlv->uNewState, nmlv->uOldState, nmlv->uChanged);
}
break;
}
break;
}
case WM_NOTIFYFORMAT:
{
/* force to return format */
if (lParam == NF_QUERY && notifyFormat != -1) return notifyFormat;
break;
}
Nikolay Sivov
committed
}
defwndproc_counter++;
ret = DefWindowProcA(hwnd, message, wParam, lParam);
defwndproc_counter--;
return ret;
}
static BOOL register_parent_wnd_class(BOOL Unicode)
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
WNDCLASSA clsA;
WNDCLASSW clsW;
if (Unicode)
{
clsW.style = 0;
clsW.lpfnWndProc = parent_wnd_proc;
clsW.cbClsExtra = 0;
clsW.cbWndExtra = 0;
clsW.hInstance = GetModuleHandleW(NULL);
clsW.hIcon = 0;
clsW.hCursor = LoadCursorA(0, IDC_ARROW);
clsW.hbrBackground = GetStockObject(WHITE_BRUSH);
clsW.lpszMenuName = NULL;
clsW.lpszClassName = testparentclassW;
}
else
{
clsA.style = 0;
clsA.lpfnWndProc = parent_wnd_proc;
clsA.cbClsExtra = 0;
clsA.cbWndExtra = 0;
clsA.hInstance = GetModuleHandleA(NULL);
clsA.hIcon = 0;
clsA.hCursor = LoadCursorA(0, IDC_ARROW);
clsA.hbrBackground = GetStockObject(WHITE_BRUSH);
clsA.lpszMenuName = NULL;
clsA.lpszClassName = "Listview test parent class";
}
return Unicode ? RegisterClassW(&clsW) : RegisterClassA(&clsA);
static HWND create_parent_window(BOOL Unicode)
static const WCHAR nameW[] = {'t','e','s','t','p','a','r','e','n','t','n','a','m','e','W'};
HWND hwnd;
if (!register_parent_wnd_class(Unicode))
return NULL;
Nikolay Sivov
committed
blockEdit = FALSE;
notifyFormat = -1;
if (Unicode)
hwnd = CreateWindowExW(0, testparentclassW, nameW,
WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
WS_MAXIMIZEBOX | WS_VISIBLE,
0, 0, 100, 100,
GetDesktopWindow(), NULL, GetModuleHandleW(NULL), NULL);
else
hwnd = CreateWindowExA(0, "Listview test parent class",
"Listview test parent window",
WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
WS_MAXIMIZEBOX | WS_VISIBLE,
0, 0, 100, 100,
GetDesktopWindow(), NULL, GetModuleHandleA(NULL), NULL);
SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE );
return hwnd;
}
static LRESULT WINAPI listview_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
Dmitry Timoshkov
committed
struct subclass_info *info = (struct subclass_info *)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
static LONG defwndproc_counter = 0;
LRESULT ret;
struct message msg;
trace("listview: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
Nikolay Sivov
committed
/* some debug output for style changing */
if ((message == WM_STYLECHANGING ||
message == WM_STYLECHANGED) && lParam)
{
STYLESTRUCT *style = (STYLESTRUCT*)lParam;
trace("\told style: 0x%08x, new style: 0x%08x\n", style->styleOld, style->styleNew);
}
msg.message = message;
msg.flags = sent|wparam|lparam;
if (defwndproc_counter) msg.flags |= defwinproc;
msg.wParam = wParam;
msg.lParam = lParam;
msg.id = LISTVIEW_ID;
add_message(sequences, LISTVIEW_SEQ_INDEX, &msg);
defwndproc_counter++;
ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam);
defwndproc_counter--;
return ret;
}
Nikolay Sivov
committed
static HWND create_listview_control(DWORD style)
{
struct subclass_info *info;
HWND hwnd;
RECT rect;
info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info));
if (!info)
return NULL;
GetClientRect(hwndparent, &rect);
hwnd = CreateWindowExA(0, WC_LISTVIEW, "foo",
Nikolay Sivov
committed
WS_CHILD | WS_BORDER | WS_VISIBLE | LVS_REPORT | style,
0, 0, rect.right, rect.bottom,
hwndparent, NULL, GetModuleHandleA(NULL), NULL);
ok(hwnd != NULL, "gle=%d\n", GetLastError());
if (!hwnd)
{
HeapFree(GetProcessHeap(), 0, info);
return NULL;
}
Dmitry Timoshkov
committed
info->oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
(LONG_PTR)listview_subclass_proc);
SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)info);
return hwnd;
}
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
/* unicode listview window with specified parent */
static HWND create_listview_controlW(DWORD style, HWND parent)
{
struct subclass_info *info;
HWND hwnd;
RECT rect;
static const WCHAR nameW[] = {'f','o','o',0};
info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info));
if (!info)
return NULL;
GetClientRect(parent, &rect);
hwnd = CreateWindowExW(0, WC_LISTVIEWW, nameW,
WS_CHILD | WS_BORDER | WS_VISIBLE | LVS_REPORT | style,
0, 0, rect.right, rect.bottom,
parent, NULL, GetModuleHandleW(NULL), NULL);
ok(hwnd != NULL, "gle=%d\n", GetLastError());
if (!hwnd)
{
HeapFree(GetProcessHeap(), 0, info);
return NULL;
}
info->oldproc = (WNDPROC)SetWindowLongPtrW(hwnd, GWLP_WNDPROC,
(LONG_PTR)listview_subclass_proc);
SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR)info);
return hwnd;
}
static HWND create_custom_listview_control(DWORD style)
{
struct subclass_info *info;
HWND hwnd;
RECT rect;
info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info));
if (!info)
return NULL;
GetClientRect(hwndparent, &rect);
hwnd = CreateWindowExA(0, WC_LISTVIEW, "foo",
WS_CHILD | WS_BORDER | WS_VISIBLE | style,
0, 0, rect.right, rect.bottom,
hwndparent, NULL, GetModuleHandleA(NULL), NULL);
ok(hwnd != NULL, "gle=%d\n", GetLastError());
if (!hwnd)
{
HeapFree(GetProcessHeap(), 0, info);
return NULL;
}
Dmitry Timoshkov
committed
info->oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
(LONG_PTR)listview_subclass_proc);
SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)info);
static LRESULT WINAPI header_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
Dmitry Timoshkov
committed
struct subclass_info *info = (struct subclass_info *)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
static LONG defwndproc_counter = 0;
LRESULT ret;
struct message msg;
trace("header: %p, %04x, %08lx, %08lx\n", hwnd, message, wParam, lParam);
msg.message = message;
msg.flags = sent|wparam|lparam;
if (defwndproc_counter) msg.flags |= defwinproc;
msg.wParam = wParam;
msg.lParam = lParam;
msg.id = HEADER_ID;
add_message(sequences, LISTVIEW_SEQ_INDEX, &msg);
defwndproc_counter++;
ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam);
defwndproc_counter--;
return ret;
}
static HWND subclass_header(HWND hwndListview)
{
struct subclass_info *info;
HWND hwnd;
info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info));
if (!info)
return NULL;
hwnd = ListView_GetHeader(hwndListview);
Dmitry Timoshkov
committed
info->oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
(LONG_PTR)header_subclass_proc);
SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)info);
return hwnd;
}
Nikolay Sivov
committed
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
static LRESULT WINAPI editbox_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
struct subclass_info *info = (struct subclass_info *)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
static LONG defwndproc_counter = 0;
LRESULT ret;
struct message msg;
msg.message = message;
msg.flags = sent|wparam|lparam;
if (defwndproc_counter) msg.flags |= defwinproc;
msg.wParam = wParam;
msg.lParam = lParam;
/* all we need is sizing */
if (message == WM_WINDOWPOSCHANGING ||
message == WM_NCCALCSIZE ||
message == WM_WINDOWPOSCHANGED ||
message == WM_MOVE ||
message == WM_SIZE)
{
add_message(sequences, EDITBOX_SEQ_INDEX, &msg);
}
defwndproc_counter++;
ret = CallWindowProcA(info->oldproc, hwnd, message, wParam, lParam);
defwndproc_counter--;
return ret;
}
static HWND subclass_editbox(HWND hwndListview)
{
struct subclass_info *info;
HWND hwnd;
info = HeapAlloc(GetProcessHeap(), 0, sizeof(struct subclass_info));
if (!info)
return NULL;
hwnd = (HWND)SendMessage(hwndListview, LVM_GETEDITCONTROL, 0, 0);
info->oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC,
(LONG_PTR)editbox_subclass_proc);
SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)info);
return hwnd;
}
/* Performs a single LVM_HITTEST test */
static void test_lvm_hittest(HWND hwnd, INT x, INT y, INT item, UINT flags, UINT broken_flags,
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
BOOL todo_item, BOOL todo_flags, int line)
{
LVHITTESTINFO lpht;
DWORD ret;
lpht.pt.x = x;
lpht.pt.y = y;
lpht.iSubItem = 10;
trace("hittesting pt=(%d,%d)\n", lpht.pt.x, lpht.pt.y);
ret = SendMessage(hwnd, LVM_HITTEST, 0, (LPARAM)&lpht);
if (todo_item)
{
todo_wine
{
ok_(__FILE__, line)(ret == item, "Expected %d item, got %d\n", item, ret);
ok_(__FILE__, line)(lpht.iItem == item, "Expected %d item, got %d\n", item, lpht.iItem);
ok_(__FILE__, line)(lpht.iSubItem == 10, "Expected subitem not overwrited\n");
}
}
else
{
ok_(__FILE__, line)(ret == item, "Expected %d item, got %d\n", item, ret);
ok_(__FILE__, line)(lpht.iItem == item, "Expected %d item, got %d\n", item, lpht.iItem);
ok_(__FILE__, line)(lpht.iSubItem == 10, "Expected subitem not overwrited\n");
}
if (todo_flags)
{
todo_wine
ok_(__FILE__, line)(lpht.flags == flags, "Expected flags %x, got %x\n", flags, lpht.flags);
}
else if (broken_flags)
ok_(__FILE__, line)(lpht.flags == flags || broken(lpht.flags == broken_flags),
"Expected flags %x, got %x\n", flags, lpht.flags);
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
else
ok_(__FILE__, line)(lpht.flags == flags, "Expected flags %x, got %x\n", flags, lpht.flags);
}
/* Performs a single LVM_SUBITEMHITTEST test */
static void test_lvm_subitemhittest(HWND hwnd, INT x, INT y, INT item, INT subitem, UINT flags,
BOOL todo_item, BOOL todo_subitem, BOOL todo_flags, int line)
{
LVHITTESTINFO lpht;
DWORD ret;
lpht.pt.x = x;
lpht.pt.y = y;
trace("subhittesting pt=(%d,%d)\n", lpht.pt.x, lpht.pt.y);
ret = SendMessage(hwnd, LVM_SUBITEMHITTEST, 0, (LPARAM)&lpht);
if (todo_item)
{
todo_wine
{
ok_(__FILE__, line)(ret == item, "Expected %d item, got %d\n", item, ret);
ok_(__FILE__, line)(lpht.iItem == item, "Expected %d item, got %d\n", item, lpht.iItem);
}
}
else
{
ok_(__FILE__, line)(ret == item, "Expected %d item, got %d\n", item, ret);
ok_(__FILE__, line)(lpht.iItem == item, "Expected %d item, got %d\n", item, lpht.iItem);
}
if (todo_subitem)
{
todo_wine
ok_(__FILE__, line)(lpht.iSubItem == subitem, "Expected subitem %d, got %d\n", subitem, lpht.iSubItem);
}
else
ok_(__FILE__, line)(lpht.iSubItem == subitem, "Expected subitem %d, got %d\n", subitem, lpht.iSubItem);
if (todo_flags)
{
todo_wine
ok_(__FILE__, line)(lpht.flags == flags, "Expected flags %x, got %x\n", flags, lpht.flags);
}
else
ok_(__FILE__, line)(lpht.flags == flags, "Expected flags %x, got %x\n", flags, lpht.flags);
}
Huw Davies
committed
static void test_images(void)
DWORD r;
LVITEM item;
HIMAGELIST himl;
HBITMAP hbmp;
RECT r1, r2;
static CHAR hello[] = "hello";
himl = ImageList_Create(40, 40, 0, 4, 4);
ok(himl != NULL, "failed to create imagelist\n");
hbmp = CreateBitmap(40, 40, 1, 1, NULL);
ok(hbmp != NULL, "failed to create bitmap\n");
r = ImageList_Add(himl, hbmp, 0);
ok(r == 0, "should be zero\n");
hwnd = CreateWindowEx(0, "SysListView32", "foo", LVS_OWNERDRAWFIXED,
10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
ok(hwnd != NULL, "failed to create listview window\n");
r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, 0,
LVS_EX_UNDERLINEHOT | LVS_EX_FLATSB | LVS_EX_ONECLICKACTIVATE);
ok(r == 0, "should return zero\n");
r = SendMessage(hwnd, LVM_SETIMAGELIST, 0, (LPARAM)himl);
ok(r == 0, "should return zero\n");
r = SendMessage(hwnd, LVM_SETICONSPACING, 0, MAKELONG(100,50));
/* returns dimensions */
r = SendMessage(hwnd, LVM_GETITEMCOUNT, 0, 0);
ok(r == 0, "should be zero items\n");
item.mask = LVIF_IMAGE | LVIF_TEXT;
item.iItem = 0;
item.iSubItem = 1;
item.iImage = 0;
item.pszText = 0;
r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
ok(r == -1, "should fail\n");
item.iSubItem = 0;
r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
ok(r == 0, "should not fail\n");
memset(&r1, 0, sizeof r1);
r1.left = LVIR_ICON;
r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM) &r1);
r = SendMessage(hwnd, LVM_DELETEALLITEMS, 0, 0);
ok(r == TRUE, "should not fail\n");
item.iSubItem = 0;
r = SendMessage(hwnd, LVM_INSERTITEM, 0, (LPARAM) &item);
ok(r == 0, "should not fail\n");
memset(&r2, 0, sizeof r2);
r2.left = LVIR_ICON;
r = SendMessage(hwnd, LVM_GETITEMRECT, 0, (LPARAM) &r2);
ok(!memcmp(&r1, &r2, sizeof r1), "rectangle should be the same\n");
DestroyWindow(hwnd);
}
Huw Davies
committed
static void test_checkboxes(void)
{
Huw Davies
committed
LVITEMA item;
DWORD r;
static CHAR text[] = "Text",
text2[] = "Text2",
text3[] = "Text3";
Huw Davies
committed
hwnd = CreateWindowEx(0, "SysListView32", "foo", LVS_REPORT,
10, 10, 100, 200, hwndparent, NULL, NULL, NULL);
ok(hwnd != NULL, "failed to create listview window\n");
/* first without LVS_EX_CHECKBOXES set and an item and check that state is preserved */
item.mask = LVIF_TEXT | LVIF_STATE;
item.stateMask = 0xffff;
item.state = 0xfccc;
item.iItem = 0;
item.iSubItem = 0;
Huw Davies
committed
r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
ok(r == 0, "ret %d\n", r);
Huw Davies
committed
item.iItem = 0;
item.mask = LVIF_STATE;
item.stateMask = 0xffff;
r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
ok(item.state == 0xfccc, "state %x\n", item.state);
/* Don't set LVIF_STATE */
item.mask = LVIF_TEXT;
item.stateMask = 0xffff;
item.state = 0xfccc;
item.iItem = 1;
item.iSubItem = 0;
Huw Davies
committed
r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
ok(r == 1, "ret %d\n", r);
Huw Davies
committed
item.iItem = 1;
item.mask = LVIF_STATE;
item.stateMask = 0xffff;
r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
ok(item.state == 0, "state %x\n", item.state);
r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
ok(r == 0, "should return zero\n");
Huw Davies
committed
/* Having turned on checkboxes, check that all existing items are set to 0x1000 (unchecked) */
item.iItem = 0;
item.mask = LVIF_STATE;
item.stateMask = 0xffff;
r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
Nikolay Sivov
committed
if (item.state != 0x1ccc)
{
win_skip("LVS_EX_CHECKBOXES style is unavailable. Skipping.\n");
DestroyWindow(hwnd);
return;
}
Huw Davies
committed
/* Now add an item without specifying a state and check that its state goes to 0x1000 */
Huw Davies
committed
item.iItem = 2;
item.mask = LVIF_TEXT;
item.state = 0;
Huw Davies
committed
r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
ok(r == 2, "ret %d\n", r);
Huw Davies
committed
item.iItem = 2;
item.mask = LVIF_STATE;
item.stateMask = 0xffff;
r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
ok(item.state == 0x1000, "state %x\n", item.state);
/* Add a further item this time specifying a state and still its state goes to 0x1000 */
Huw Davies
committed
item.iItem = 3;
item.mask = LVIF_TEXT | LVIF_STATE;
item.stateMask = 0xffff;
item.state = 0x2aaa;
Huw Davies
committed
r = SendMessage(hwnd, LVM_INSERTITEMA, 0, (LPARAM) &item);
ok(r == 3, "ret %d\n", r);
Huw Davies
committed
item.iItem = 3;
item.mask = LVIF_STATE;
item.stateMask = 0xffff;
r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
ok(item.state == 0x1aaa, "state %x\n", item.state);
/* Set an item's state to checked */
item.iItem = 3;
item.mask = LVIF_STATE;
item.stateMask = 0xf000;
item.state = 0x2000;
r = SendMessage(hwnd, LVM_SETITEMA, 0, (LPARAM) &item);
item.iItem = 3;
item.mask = LVIF_STATE;
item.stateMask = 0xffff;
r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
ok(item.state == 0x2aaa, "state %x\n", item.state);
/* Check that only the bits we asked for are returned,
* and that all the others are set to zero
*/
item.iItem = 3;
item.mask = LVIF_STATE;
item.stateMask = 0xf000;
item.state = 0xffff;
r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
ok(item.state == 0x2000, "state %x\n", item.state);
Huw Davies
committed
/* Set the style again and check that doesn't change an item's state */
r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
ok(r == LVS_EX_CHECKBOXES, "ret %x\n", r);
Huw Davies
committed
item.iItem = 3;
item.mask = LVIF_STATE;
item.stateMask = 0xffff;
r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
ok(item.state == 0x2aaa, "state %x\n", item.state);
/* Unsetting the checkbox extended style doesn't change an item's state */
r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, 0);
ok(r == LVS_EX_CHECKBOXES, "ret %x\n", r);
Huw Davies
committed
item.iItem = 3;
item.mask = LVIF_STATE;
item.stateMask = 0xffff;
r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
ok(item.state == 0x2aaa, "state %x\n", item.state);
/* Now setting the style again will change an item's state */
r = SendMessage(hwnd, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
ok(r == 0, "ret %x\n", r);
Huw Davies
committed
item.iItem = 3;
item.mask = LVIF_STATE;
item.stateMask = 0xffff;
r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
ok(item.state == 0x1aaa, "state %x\n", item.state);
/* Toggle checkbox tests (bug 9934) */
memset (&item, 0xcc, sizeof(item));
item.mask = LVIF_STATE;
item.iItem = 3;
item.iSubItem = 0;
item.state = LVIS_FOCUSED;
item.stateMask = LVIS_FOCUSED;
r = SendMessage(hwnd, LVM_SETITEM, 0, (LPARAM) &item);
expect(1, r);
item.iItem = 3;
item.mask = LVIF_STATE;
item.stateMask = 0xffff;
r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
ok(item.state == 0x1aab, "state %x\n", item.state);
r = SendMessage(hwnd, WM_KEYDOWN, VK_SPACE, 0);
expect(0, r);
r = SendMessage(hwnd, WM_KEYUP, VK_SPACE, 0);
expect(0, r);
item.iItem = 3;
item.mask = LVIF_STATE;
item.stateMask = 0xffff;
r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
ok(item.state == 0x2aab, "state %x\n", item.state);
r = SendMessage(hwnd, WM_KEYDOWN, VK_SPACE, 0);
expect(0, r);
r = SendMessage(hwnd, WM_KEYUP, VK_SPACE, 0);
expect(0, r);
item.iItem = 3;
item.mask = LVIF_STATE;
item.stateMask = 0xffff;
r = SendMessage(hwnd, LVM_GETITEMA, 0, (LPARAM) &item);
ok(item.state == 0x1aab, "state %x\n", item.state);
Huw Davies
committed
DestroyWindow(hwnd);
}
static void insert_column(HWND hwnd, int idx)
{
LVCOLUMN column;
DWORD rc;
Francois Gouget
committed
memset(&column, 0xcc, sizeof(column));
column.mask = LVCF_SUBITEM;
column.iSubItem = idx;
rc = ListView_InsertColumn(hwnd, idx, &column);
expect(idx, rc);
}
static void insert_item(HWND hwnd, int idx)
{
static CHAR text[] = "foo";
LVITEMA item;
DWORD rc;
Francois Gouget
committed
memset(&item, 0xcc, sizeof (item));
item.mask = LVIF_TEXT;
item.iItem = idx;
item.iSubItem = 0;
item.pszText = text;
Francois Gouget
committed
rc = ListView_InsertItem(hwnd, &item);
expect(idx, rc);
}