diff --git a/rostests/winetests/user32/edit.c b/rostests/winetests/user32/edit.c index 11550f724aa..700dfb0f5a1 100755 --- a/rostests/winetests/user32/edit.c +++ b/rostests/winetests/user32/edit.c @@ -2530,6 +2530,120 @@ static void test_dialogmode(void) destroy_child_editcontrol(hwEdit); } +static void test_EM_GETHANDLE(void) +{ + static const char str0[] = "untouched"; + static const char str1[] = "1111+1111+1111#"; + static const char str2[] = "2222-2222-2222-2222#"; + static const char str3[] = "3333*3333*3333*3333*3333#"; + CHAR current[42]; + HWND hEdit; + HLOCAL hmem; + HLOCAL hmem2; + HLOCAL halloc; + char *buffer; + int len; + int r; + + trace("EDIT: EM_GETHANDLE\n"); + + /* EM_GETHANDLE is not supported for a single line edit control */ + hEdit = create_editcontrol(WS_BORDER, 0); + ok(hEdit != NULL, "got %p (expected != NULL)\n", hEdit); + + hmem = (HGLOBAL) SendMessage(hEdit, EM_GETHANDLE, 0, 0); + ok(hmem == NULL, "got %p (expected NULL)\n", hmem); + DestroyWindow(hEdit); + + + /* EM_GETHANDLE needs a multiline edit control */ + hEdit = create_editcontrol(WS_BORDER | ES_MULTILINE, 0); + ok(hEdit != NULL, "got %p (expected != NULL)\n", hEdit); + + /* set some text */ + r = SendMessageA(hEdit, WM_SETTEXT, 0, (LPARAM)str1); + len = SendMessageA(hEdit, WM_GETTEXTLENGTH, 0, 0); + ok((r == 1) && (len == lstrlenA(str1)), "got %d and %d (expected 1 and %d)\n", r, len, lstrlenA(str1)); + + lstrcpyA(current, str0); + r = SendMessageA(hEdit, WM_GETTEXT, sizeof(current), (LPARAM)current); + ok((r == lstrlenA(str1)) && !lstrcmpA(current, str1), + "got %d and \"%s\" (expected %d and \"%s\")\n", r, current, lstrlenA(str1), str1); + + hmem = (HGLOBAL) SendMessage(hEdit, EM_GETHANDLE, 0, 0); + ok(hmem != NULL, "got %p (expected != NULL)\n", hmem); + /* The buffer belongs to the app now. According to MSDN, the app has to LocalFree the + buffer, LocalAlloc a new buffer and pass it to the edit control with EM_SETHANDLE. */ + + buffer = LocalLock(hmem); + ok(buffer != NULL, "got %p (expected != NULL)\n", buffer); + len = lstrlenA(buffer); + ok((len == lstrlenA(str1)) && !lstrcmpA(buffer, str1), + "got %d and \"%s\" (expected %d and \"%s\")\n", len, buffer, lstrlenA(str1), str1); + LocalUnlock(hmem); + + /* use LocalAlloc first to get a different handle */ + halloc = LocalAlloc(LMEM_MOVEABLE, 42); + ok(halloc != NULL, "got %p (expected != NULL)\n", halloc); + /* prepare our new memory */ + buffer = LocalLock(halloc); + ok(buffer != NULL, "got %p (expected != NULL)\n", buffer); + lstrcpyA(buffer, str2); + LocalUnlock(halloc); + + /* LocalFree the old memory handle before EM_SETHANDLE the new handle */ + LocalFree(hmem); + /* use LocalAlloc after the LocalFree to likely consume the handle */ + hmem2 = LocalAlloc(LMEM_MOVEABLE, 42); + ok(hmem2 != NULL, "got %p (expected != NULL)\n", hmem2); + + SendMessage(hEdit, EM_SETHANDLE, (WPARAM)halloc, 0); + + len = SendMessageA(hEdit, WM_GETTEXTLENGTH, 0, 0); + ok(len == lstrlenA(str2), "got %d (expected %d)\n", len, lstrlenA(str2)); + + lstrcpyA(current, str0); + r = SendMessageA(hEdit, WM_GETTEXT, sizeof(current), (LPARAM)current); + ok((r == lstrlenA(str2)) && !lstrcmpA(current, str2), + "got %d and \"%s\" (expected %d and \"%s\")\n", r, current, lstrlenA(str2), str2); + + /* set a different text */ + r = SendMessageA(hEdit, WM_SETTEXT, 0, (LPARAM)str3); + len = SendMessageA(hEdit, WM_GETTEXTLENGTH, 0, 0); + ok((r == 1) && (len == lstrlenA(str3)), "got %d and %d (expected 1 and %d)\n", r, len, lstrlenA(str3)); + + lstrcpyA(current, str0); + r = SendMessageA(hEdit, WM_GETTEXT, sizeof(current), (LPARAM)current); + ok((r == lstrlenA(str3)) && !lstrcmpA(current, str3), + "got %d and \"%s\" (expected %d and \"%s\")\n", r, current, lstrlenA(str3), str3); + + LocalFree(hmem2); + DestroyWindow(hEdit); + + /* Some apps have bugs ... */ + hEdit = create_editcontrol(WS_BORDER | ES_MULTILINE, 0); + + /* set some text */ + r = SendMessageA(hEdit, WM_SETTEXT, 0, (LPARAM)str1); + len = SendMessageA(hEdit, WM_GETTEXTLENGTH, 0, 0); + ok((r == 1) && (len == lstrlenA(str1)), "got %d and %d (expected 1 and %d)\n", r, len, lstrlenA(str1)); + + /* everything is normal upto EM_GETHANDLE */ + hmem = (HGLOBAL) SendMessage(hEdit, EM_GETHANDLE, 0, 0); + /* Some messages still work while other messages fail. + After LocalFree the memory handle, messages can crash the app */ + + /* A buggy editor used EM_GETHANDLE twice */ + hmem2 = (HGLOBAL) SendMessage(hEdit, EM_GETHANDLE, 0, 0); + ok(hmem2 == hmem, "got %p (expected %p)\n", hmem2, hmem); + + /* Let the edit control free the memory handle */ + SendMessage(hEdit, EM_SETHANDLE, (WPARAM)hmem2, 0); + + DestroyWindow(hEdit); +} + + START_TEST(edit) { BOOL b; @@ -2568,5 +2682,7 @@ START_TEST(edit) else win_skip("EndMenu is not available\n"); + test_EM_GETHANDLE(); + UnregisterWindowClasses(); } diff --git a/rostests/winetests/user32/listbox.c b/rostests/winetests/user32/listbox.c index ef4a35b41a3..0a000ccd772 100644 --- a/rostests/winetests/user32/listbox.c +++ b/rostests/winetests/user32/listbox.c @@ -274,30 +274,42 @@ static LRESULT WINAPI main_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARA return DefWindowProc(hwnd, msg, wparam, lparam); } -static void test_ownerdraw(void) +static HWND create_parent( void ) { WNDCLASS cls; - HWND parent, hLB; - INT ret; - RECT rc; + HWND parent; + static ATOM class; - cls.style = 0; - cls.lpfnWndProc = main_window_proc; - cls.cbClsExtra = 0; - cls.cbWndExtra = 0; - cls.hInstance = GetModuleHandle(0); - cls.hIcon = 0; - cls.hCursor = LoadCursor(0, IDC_ARROW); - cls.hbrBackground = GetStockObject(WHITE_BRUSH); - cls.lpszMenuName = NULL; - cls.lpszClassName = "main_window_class"; - ok (RegisterClass(&cls), "RegisterClass failed\n"); + if (!class) + { + cls.style = 0; + cls.lpfnWndProc = main_window_proc; + cls.cbClsExtra = 0; + cls.cbWndExtra = 0; + cls.hInstance = GetModuleHandle(0); + cls.hIcon = 0; + cls.hCursor = LoadCursor(0, IDC_ARROW); + cls.hbrBackground = GetStockObject(WHITE_BRUSH); + cls.lpszMenuName = NULL; + cls.lpszClassName = "main_window_class"; + class = RegisterClass( &cls ); + } parent = CreateWindowEx(0, "main_window_class", NULL, WS_POPUP | WS_VISIBLE, 100, 100, 400, 400, GetDesktopWindow(), 0, GetModuleHandle(0), NULL); + return parent; +} + +static void test_ownerdraw(void) +{ + HWND parent, hLB; + INT ret; + RECT rc; + + parent = create_parent(); assert(parent); hLB = create_listbox(LBS_OWNERDRAWFIXED | WS_CHILD | WS_VISIBLE, parent); @@ -1498,6 +1510,84 @@ static void test_listbox_dlgdir(void) DestroyWindow(hWnd); } +static void test_set_count( void ) +{ + HWND parent, listbox; + LONG ret; + RECT r; + + parent = create_parent(); + listbox = create_listbox( LBS_OWNERDRAWFIXED | LBS_NODATA | WS_CHILD | WS_VISIBLE, parent ); + + UpdateWindow( listbox ); + GetUpdateRect( listbox, &r, TRUE ); + ok( IsRectEmpty( &r ), "got non-empty rect\n"); + + ret = SendMessage( listbox, LB_SETCOUNT, 100, 0 ); + ok( ret == 0, "got %d\n", ret ); + ret = SendMessage( listbox, LB_GETCOUNT, 0, 0 ); + ok( ret == 100, "got %d\n", ret ); + + GetUpdateRect( listbox, &r, TRUE ); + ok( !IsRectEmpty( &r ), "got empty rect\n"); + + ValidateRect( listbox, NULL ); + GetUpdateRect( listbox, &r, TRUE ); + ok( IsRectEmpty( &r ), "got non-empty rect\n"); + + ret = SendMessage( listbox, LB_SETCOUNT, 99, 0 ); + ok( ret == 0, "got %d\n", ret ); + + GetUpdateRect( listbox, &r, TRUE ); + ok( !IsRectEmpty( &r ), "got empty rect\n"); + + DestroyWindow( listbox ); + DestroyWindow( parent ); +} + +static DWORD (WINAPI *pGetListBoxInfo)(HWND); +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) +{ + HWND listbox, parent; + WNDPROC oldproc; + DWORD ret; + + pGetListBoxInfo = (void*)GetProcAddress(GetModuleHandle("user32"), "GetListBoxInfo"); + + if (!pGetListBoxInfo) + { + win_skip("GetListBoxInfo() not available\n"); + return; + } + + 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; + ret = pGetListBoxInfo(listbox); + ok(ret > 0, "got %d\n", ret); +todo_wine + ok(lb_getlistboxinfo == 0, "got %d\n", lb_getlistboxinfo); + + DestroyWindow(listbox); + DestroyWindow(parent); +} + START_TEST(listbox) { const struct listbox_test SS = @@ -1576,4 +1666,6 @@ START_TEST(listbox) test_listbox_item_data(); test_listbox_LB_DIR(); test_listbox_dlgdir(); + test_set_count(); + test_GetListBoxInfo(); } diff --git a/rostests/winetests/user32/scroll.c b/rostests/winetests/user32/scroll.c index 1d7e75e21a7..0f0ede23fed 100644 --- a/rostests/winetests/user32/scroll.c +++ b/rostests/winetests/user32/scroll.c @@ -241,7 +241,6 @@ static void scrollbar_test_default( DWORD style) ok( min == 0 && max == 0, "Scroll bar range is %d,%d. Expected 0,0. Style %08x\n", min, max, style); else -todo_wine ok(( min == 0 && max == 100) || broken( min == 0 && max == 0), /* Win 9x/ME */ "Scroll bar range is %d,%d. Expected 0,100. Style %08x\n", min, max, style); @@ -253,7 +252,6 @@ todo_wine ok( min == 0 && max == 0, "Scroll bar range is %d,%d. Expected 0,0. Style %08x\n", min, max, style); else -todo_wine ok(( min == 0 && max == 100) || broken( min == 0 && max == 0), /* Win 9x/ME */ "Scroll bar range is %d,%d. Expected 0,100. Style %08x\n", min, max, style); @@ -263,7 +261,6 @@ todo_wine if( !( style & ( WS_VSCROLL | WS_HSCROLL))) ok( !ret, "GetScrollInfo succeeded unexpectedly. Style is %08x\n", style); else -todo_wine ok( ret || broken( !ret), /* Win 9x/ME */ "GetScrollInfo failed unexpectedly. Style is %08x\n", style); @@ -273,7 +270,6 @@ todo_wine if( !( style & ( WS_VSCROLL | WS_HSCROLL))) ok( !ret, "GetScrollInfo succeeded unexpectedly. Style is %08x\n", style); else -todo_wine ok( ret || broken( !ret), /* Win 9x/ME */ "GetScrollInfo failed unexpectedly. Style is %08x\n", style); @@ -396,6 +392,98 @@ todo_wine DestroyWindow( hwnd); } +static LRESULT CALLBACK scroll_init_proc(HWND hwnd, UINT msg, + WPARAM wparam, LPARAM lparam) +{ + SCROLLINFO horz, vert; + CREATESTRUCTA *cs = (CREATESTRUCTA *)lparam; + BOOL h_ret, v_ret; + + switch(msg) + { + case WM_NCCREATE: + return cs->lpCreateParams ? DefWindowProcA(hwnd, msg, wparam, lparam) : + TRUE; + + case WM_CREATE: + horz.cbSize = sizeof horz; + horz.fMask = SIF_ALL; + horz.nMin = 0xdeadbeaf; + horz.nMax = 0xbaadc0de; + vert = horz; + h_ret = GetScrollInfo(hwnd, SB_HORZ, &horz); + v_ret = GetScrollInfo(hwnd, SB_VERT, &vert); + + if(cs->lpCreateParams) + { + /* WM_NCCREATE was passed to DefWindowProc */ + if(cs->style & (WS_VSCROLL | WS_HSCROLL)) + { + ok(h_ret && v_ret, "GetScrollInfo() should return NON-zero " + "but got h_ret=%d v_ret=%d\n", h_ret, v_ret); + ok(vert.nMin == 0 && vert.nMax == 100, + "unexpected init values(SB_VERT): min=%d max=%d\n", + vert.nMin, vert.nMax); + ok(horz.nMin == 0 && horz.nMax == 100, + "unexpected init values(SB_HORZ): min=%d max=%d\n", + horz.nMin, horz.nMax); + } + else + { + ok(!h_ret && !v_ret, "GetScrollInfo() should return zeru, " + "but got h_ret=%d v_ret=%d\n", h_ret, v_ret); + ok(vert.nMin == 0xdeadbeaf && vert.nMax == 0xbaadc0de, + "unexpected initialization(SB_VERT): min=%d max=%d\n", + vert.nMin, vert.nMax); + ok(horz.nMin == 0xdeadbeaf && horz.nMax == 0xbaadc0de, + "unexpected initialization(SB_HORZ): min=%d max=%d\n", + horz.nMin, horz.nMax); + } + } + else + { + ok(!h_ret && !v_ret, "GetScrollInfo() should return zeru, " + "but got h_ret=%d v_ret=%d\n", h_ret, v_ret); + ok(horz.nMin == 0xdeadbeaf && horz.nMax == 0xbaadc0de && + vert.nMin == 0xdeadbeaf && vert.nMax == 0xbaadc0de, + "unexpected initialization\n"); + } + return FALSE; /* abort creation */ + + default: + /* need for WM_GETMINMAXINFO, which precedes WM_NCCREATE */ + return 0; + } +} + +static void scrollbar_test_init(void) +{ + WNDCLASSEXA wc; + CHAR cls_name[] = "scroll_test_class"; + LONG style[] = {WS_VSCROLL, WS_HSCROLL, WS_VSCROLL | WS_HSCROLL, 0}; + int i; + + memset( &wc, 0, sizeof wc ); + wc.cbSize = sizeof wc; + wc.style = CS_VREDRAW | CS_HREDRAW; + wc.hInstance = GetModuleHandleA(0); + wc.hCursor = LoadCursorA(NULL, IDC_ARROW); + wc.hbrBackground = GetStockObject(WHITE_BRUSH); + wc.lpszClassName = cls_name; + wc.lpfnWndProc = scroll_init_proc; + RegisterClassExA(&wc); + + for(i = 0; i < sizeof style / sizeof style[0]; i++) + { + /* need not to destroy these windows due creation abort */ + CreateWindowExA(0, cls_name, NULL, style[i], + 100, 100, 100, 100, NULL, NULL, wc.hInstance, (LPVOID)TRUE); + CreateWindowExA(0, cls_name, NULL, style[i], + 100, 100, 100, 100, NULL, NULL, wc.hInstance, (LPVOID)FALSE); + } + UnregisterClassA(cls_name, wc.hInstance); +} + START_TEST ( scroll ) { WNDCLASSA wc; @@ -444,6 +532,8 @@ START_TEST ( scroll ) scrollbar_test_default( WS_VSCROLL); scrollbar_test_default( WS_HSCROLL | WS_VSCROLL); + scrollbar_test_init(); + DestroyWindow(hScroll); DestroyWindow(hMainWnd); }